当柳上原的风吹向天际的时候...

真正的快乐来源于创造

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks

2009年8月27日 #

人生转轨中,此博使命结束,今后停止更新此博。

何杨

2013年8月7日23:22:32
posted @ 2013-08-07 23:23 何杨| 编辑 收藏

加字段用这个,CS.TG表名,LINE2_TYPE字段名,CHAR(1)字段类型
ALTER TABLE CS.TG ADD COLUMN LINE2_TYPE CHAR(1);

要是加错了用以下语句删除:
alter table CS.TG drop column LINE2_TYPE;

删完了再更新或查询可能会遇到这个
DB2 sqlstate 57016 原因码 "7"

不用怕,也好解决
首先打开一个db2admin控制台
执行以下命令:
db2 connect to DBName user XXX 之后输入密码
然后输入:
db2 reorg table CS.TG
就OK了。

posted @ 2013-07-23 16:37 何杨 阅读(2479) | 评论 (0)编辑 收藏

// 首先与DB2数据建立连接(如:数据库名为dbname)
db2 connect to KOUE231 user ci2 using db2adin3

// 将del文件(如:数据文件名为T1.del,存放在c盘根目录下)导入到数据中指定的table中(如:table名为T1)
db2 import from c:\T1.del of del insert into T1
db2 import from c:\T2.del of del insert into T2
db2 import from c:\T3.del of del insert into T3
db2 import from c:\T4.del of del insert into T4
posted @ 2013-07-16 20:07 何杨 阅读(540) | 评论 (0)编辑 收藏

http://guanzhilibai.blog.163.com/blog/static/13587993201171953537784/

SQL3001C
打开输出文件时,发生 I/O 错误(原因 = 原因)。
SQL3002C
写入输出数据文件时,发生了 I/O 错误。
SQL3003C
关闭输出数据文件时,发生了 I/O 错误。
SQL3004N
filetype 参数无效。
SQL3005N
处理被中断。
SQL3006C
打开消息文件时,发生了 I/O 错误。
SQL3007C
写入消息文件时,发生了 I/O 错误。
SQL3008N
实用程序在连接到数据库时遇到了错误 错误。
SQL3009N
“操作字符串”参数无效或者太长。
SQL3010N
METHOD 参数无效。
SQL3011C
没有足够存储空间来处理此命令。
SQL3012C
发生了系统错误。
SQL3013N
filetmod 的长度超出可接受的范围。它应大于或等于 0 且小于或等于 8000。
SQL3014C
关闭消息文件时,发生了 I/O 错误。
SQL3015N
处理期间发生 SQL 错误 sqlcode。
SQL3016N
在文件类型的 filetmod 参数中找到意外的关键字 关键字。
SQL3017N
定界符无效,或使用多次。
SQL3018N
指定了句点作为字符串定界符。
SQL3019N
未在命令中指定“操作字符串”参数。
SQL3020N
用户无权运行指定的 Export 命令。
SQL3021N
用户无权对表 名称 运行指定的 Import 命令。
SQL3022N
处理“操作字符串”参数中的 SELECT 字符串时发生 SQL 错误 sqlcode。
SQL3023N
数据库名称参数无效。
SQL3024N
打开格式文件时,发生了 I/O 错误。
SQL3025N
指定文件名或路径的参数无效。
SQL3026N
msgfile 或 tempfiles 路径参数无效。
SQL3027N
读取格式文件时发生了 I/O 错误。
SQL3028N
导出方法指示符无效。它必须是“N”或“D”。
SQL3029N
未指定 filetype 参数。
SQL3030C
打开输入文件时,发生 I/O 错误(原因 = 原因)。
SQL3031C
读输入文件时,发生了 I/O 错误。
SQL3032N
LOAD/IMPORT 方法指示符对指定的文件类型无效。它必须是“N”、“P”或“缺省值”。
SQL3033N
目标规范中丢失诸如 INSERT、REPLACE、CREATE、 INSERT_UPDATE 或 REPLACE_CREATE 之类的关键字,或关键字拼写错误。
SQL3034N
目标规范中丢失关键字 INTO,或关键字拼写错误。
SQL3035N
目标规范中的 tablename 参数无效。
SQL3036N
目标规范中的 tcolumn-list 没有右圆括号。
SQL3037N
Import 处理期间发生 SQL 错误 sqlcode。
SQL3038N
“操作字符串”参数包含意外的字符。
SQL3039W
可供 DATA BUFFER 的 LOAD 使用的内存禁止完全 LOAD 并行性。将使用装入并行性 值。
SQL3040N
实用程序无法使用 选项名 参数中指定的文件名 文件名。原因码:原因码。
SQL3041N
指定的日期值在 Sybase 中不受支持。
SQL3042N
对 DATALINK 列指定的 LINKTYPE 无效。
SQL3043N
DATALINK 列的 DATALINK SPECIFICATION 无效。
SQL3044N
DATALINK 列的 DATALINK SPECIFICATION 带有重复的前缀规范。
SQL3045N
METHOD 参数中的 dcolumn 位置小于 1,或大于“定界”ASCII 码文件中的最大列数(1024)。
SQL3046N
METHOD 参数中的列数小于 1。
SQL3047N
METHOD 中指定的 LOAD/IMPORT 方法对“定界”ASCII 码文件无效。它必须是“P”或“缺省值”。
SQL3048N
输入文件中指定的列数比数据库的列数少,但其中一个数据库列不可为空。
SQL3049N
数据库列 名称 的数据类型 类型 与此格式文件不兼容,但数据库列不可为空。
SQL3050W
将在 IXF 文件代码页 文件代码页 与应用程序代码页 应用程序代码页 之间进行转换。
SQL3051W
已装入要装入 列名 中的数据,但是尚未执行从 IXF 文件代码页转换为应用程序代码页。
SQL3052N
缺少 类型 路径参数,但此参数是必需的。原因码:原因码。
SQL3053N
要导出至工作表格式文件的行数超过 8191。
SQL3054N
输入文件是无效的 PC/IXF 文件。该文件太短,无法包含有效的 H 记录。
SQL3055N
输入文件是无效的 PC/IXF 文件。不能将第一条记录中的长度字段转换为数值。
SQL3056N
输入文件是无效的 PC/IXF 文件。H 记录的长度字段中的值过小。
SQL3057N
输入文件是无效的 PC/IXF 文件。第一条记录中的输入字段不是 H。
SQL3058N
H 记录中的标识字段不是 IXF。
SQL3059N
H 记录中的版本字段无效。
SQL3060N
不能将 H 记录中的 HCNT 字段转换为数值,或其值超过范围。
SQL3061N
不能将 H 记录中的单字节和/或双字节代码页字段转换为数值,或值超出范围。
SQL3062N
不能将 H 记录中的双字节代码页字段转换为数值,或值超出范围。
SQL3063N
H 记录中的单字节代码页值 值-1 与应用程序的单字节代码页值 值-2 不兼容。未指定 FORCEIN 选项。
SQL3064N
H 记录中的双字节代码页值 值-1 与应用程序的双字节代码页值 值-2 不兼容。未指定 FORCEIN 选项。
SQL3065C
不能确定应用程序代码页的值。
SQL3066N
读取或寻找 T 记录时,到达文件末尾。
SQL3067N
不能将 T 记录中的长度字段转换为数值。
SQL3068N
T 记录的长度字段中的值太小。
SQL3069N
H 记录后的第一个非 A 记录不是 T 记录。
SQL3070N
A 记录中的长度字段超出范围。
SQL3071N
T 记录中的数据约定字段不是 C。
SQL3072N
T 记录中的数据格式字段不是 M。
SQL3073N
T 记录中的机器格式字段不是 PCbbb(其中 b = 空白)。
SQL3074N
T 记录中的数据位置字段不是 I。
SQL3075N
不能将 T 记录的 CCNT 转换为数值,或值超过范围。
SQL3076N
不能将 T 记录中的名称长度字段转换为数值,或值超过范围。
SQL3077N
T 记录中的 CCNT 字段中指定的 C 记录数 值 超过允许的最大值 最大值。
SQL3078N
不能将 A 记录中的长度字段转换为数值。
SQL3079N
不能将 C 记录中的长度字段转换为数值。
SQL3080N
C 记录的长度字段中的值太小。
SQL3081N
找不到足够的 C 记录。
SQL3082N
当读取或寻找 C 记录时,到达文件末尾。
SQL3083N
不能将列 名称 的 C 记录中的“D 记录标识”字段转换为数值。
SQL3084N
不能将列 名称 的 C 记录中的“D 记录位置”字段转换为数值。
SQL3085N
列 名称 的 C 记录中的“D 记录标识”和“D 记录位置”字段超出范围,或与前一个 C 记录不一致。
SQL3086N
未指定要装入数据库列 名称 的源列,或指定的源列不存在,但数据库列不可为空。
SQL3087N
指定要装入数据库列 名称 的源列无效,但该数据库列不可为空。
SQL3088N
指定要装入数据库列 名称 的源列与该数据库列不兼容,但数据库列不可为空。
SQL3089N
在期望 D 记录的地方找到非 D 记录。
SQL3090N
不能将 D 记录中的长度字段转换为数值。
SQL3091N
D 记录中的长度字段超出范围。
SQL3092N
D 记录中的标识字段未包含期望的值。
SQL3093N
输入文件是无效的 WSF 文件。
SQL3094N
找不到输入列 名称,但相对应的数据库列不可为空。
SQL3095N
指定的列位置 位置 不在有效范围 1 至 256 之内。
SQL3096N
数据库列 名称 的数据类型 类型 与任何 WSF 列类型都不兼容,但是该数据库列不可为空。
SQL3097N
WSF 记录中的记录长度字段对其记录类型无效。
SQL3098N
输入文件中的行号不在有效范围 1 至 8192 之内。
SQL3099N
输入文件中的列号不在有效范围 1 至 256 之内。
SQL3100W
输出 DEL 格式文件中的列号 列号(标识为 名称)长于 254 字节。
SQL3101W
第 行号 行的第 列号 列中有字符串定界符。
SQL3102W
METHOD 参数中的列数大于“操作字符串”(例如,“REPLACE into ...”)参数中的列数。
SQL3103W
METHOD 参数中的列数小于“操作字符串”(例如,“REPLACE into ...”)参数中的列数。
SQL3104N
EXPORT 实用程序 正在开始将数据导出至文件 名称。
SQL3105N
Export 实用程序已经完成导出 行数 行。
SQL3106N
格式化消息文件的消息时出错。
SQL3107W
消息文件中至少有一条警告消息。
SQL3108W
无法访问第 行号 行第 列号 列中的 DATALINK 值所引用的文件。原因码 = 原因码。
SQL3109N
实用程序正在开始从文件 名称 装入数据。
SQL3110N
实用程序已完成处理。从输入文件读了 数目 行。
SQL3111C
关闭输入数据文件时发生了 I/O 错误。
SQL3112W
指定的输入文件列数少于数据库列数。
SQL3113W
数据库列 名称 的数据类型 类型 与此格式文件不兼容。对该列插入了空值。
SQL3114W
未装入第 行号 行第 列号 列中 文本 后的某些数据。
SQL3115W
在第 行号 行第 列号 列中以 文本 开头的字段值比允许的最长表列还要长。该值被截断。
SQL3116W
第 行号 行第 列号 列中的字段值丢失,但是目标列不可为空。
SQL3117W
不能将第 行号 行第 列号 列中的字段值转换成 SMALLINT 值。装入了空值。
SQL3118W
不能将第 行号 行第 列号 列中的字段值转换成 SMALLINT 值,但目标列不可为空。未装入该行。
SQL3119W
不能将第 行号 行第 列号 列中的字段值转换成 INTEGER 值。装入了空值。
SQL3120W
不能将第 行号 行第 列号 列中的字段值转换成 INTEGER 值,但目标列不可为空。未装入该行。
SQL3121W
不能将第 行号 行第 列号 列中的字段值转换成 FLOAT 值。装入了空值。
SQL3122W
不能将第 行号 行第 列号 列中的字段值转换成 FLOAT 值,但目标列不可为空。未装入该行。
SQL3123W
不能将第 行号 行第 列号 列中的字段值转换成 PACKED DECIMAL 值。装入了空值。
SQL3124W
不能将第 行号 行第 列号 列中的字段值转换成 PACKED DECIMAL 值,但目标列不可为空。未装入该行。
SQL3125W
因为数据比目标数据库列长,所以第 行号 行第 列号 列中的字符数据被截断。
SQL3126N
远程客户机需要文件和目录的绝对路径。
SQL3128W
第 行号 行第 列号 列中包含 数据 的字段被截断为 DATE 字段,因为该数据比数据库列更长。
SQL3129W
已用空格填充了第 行号 行第 列号 列中包含 文本 的日期、时间或时间戳记字段。
SQL3130W
第 行号 行第 列号 列中包含 文本 的字段被截断为 TIME 字段,因为该数据比数据库列更长。
SQL3131W
第 行号 行第 列号 列中包含 文本 的字段被截断为 TIMESTAMP 字段,因为该数据比数据库列更长。
SQL3132W
列 列 中的字符数据将被截断成大小为 大小。
SQL3133W
第 行号 行第 列号 列中的字段包含无效的 DATALINK 值。装入了空值。
SQL3134W
第 行号 行第 列号 列中的字段包含无效 DATALINK 值,但目标列不可为空。未装入该行。
SQL3135N
METHOD 参数中的列数大于目标表中的列数。
SQL3137W
第 行号 行太短。至少丢失了一个已装入非可空列的输入值。未装入该行。
SQL3138W
在到达输入数据文件末尾之前,找不到结束字符串定界符。
SQL3139W
当实用程序与数据库断开连接时发生了错误 错误。
SQL3140W
不能将第 行号 行第 列号 列中的字段值转换成十进制浮点值。装入了空值。
SQL3141W
不能将第 行号 行第 列号 列中的字段值转换成十进制浮点值,但目标列不可为空。未装入该行。
SQL3142W
第 列号 列的列标题被截断为 240 字节。
SQL3143W
变长列 列号 的最大长度超过 240 字节这一限制。列的数据可能被截断。
SQL3144W
定长列 列号 的长度超过 240 字节这一限制。列的数据可能被截断。
SQL3145W
第 行号 行第 列号 列的数据被截断为 240 字节。
SQL3146N
第 行号 行第 列号 列的 DATE 或 TIMESTAMP 值超出范围。
SQL3147W
导出至工作表格式文件中的行超过 2048 行。
SQL3148W
未将输入文件中的行插入至表中。返回了 SQLCODE sqlcode。
SQL3149N
处理了输入文件中的 数值-1 行。已将 数值-2 行成功插入表中。拒绝了 数值-3 行。
SQL3150N
PC/IXF 文件中的 H 记录具有产品 产品,日期 日期 和时间 时间。
SQL3151N
因为指定了 FORCEIN 选项,所以将不执行从 H 记录中单字节代码页值 代码页 至应用程序 单字节代码页值 代码页 的数据转换。
SQL3152N
H 记录中的双字节代码页值 值 与应用程序的双字节代码页值 值 不兼容。因为指定了 FORCEIN 选项,所以将插入数据。
SQL3153N
PC/IXF 文件中的 T 记录具有名称 名称,限定符 限定符 和源 源。
SQL3154W
H 记录中的 HCNT 值与 T 记录中的 CCNT 值不兼容。将使用 T 记录中的 CCNT 值。
SQL3155W
列 名称 的 C 记录中名称长度字段无效。将不装入该列中的数据。
SQL3156W
列 名称 的 C 记录中的 NULL 字段无效。将不装入该列中的数据。
SQL3157W
列 名称 的 C 记录中的类型字段无效。将不装入该列中的数据。
SQL3158W
列 名称 的 C 记录中的单字节代码页字段无效。将不装入该列中的数据。
SQL3159W
列 名称 的 C 记录中的双字节代码页字段无效。将不装入该列中的数据。
SQL3160W
列 名称 的 C 记录中的列长度字段无效。将不装入该列中的数据。
SQL3161W
列 名称 的 C 记录中的精度字段无效。将不装入该列中的数据。
SQL3162W
列 名称 的 C 记录中的小数位字段无效。将不装入该列中的数据。
SQL3163W
浮点列 名称 的 C 记录中的列长度字段是空白。将使用值 00008。
SQL3164W
浮点列 名称 的 C 记录中的列长度字段无效。将不装入该列中的数据。
SQL3165W
列 名称 的 C 记录中的列类型字段 类型 无效。将不装入该列中的数据。
SQL3166W
未指定要装入 PC/IXF 列中的数据库列 名称,或者指定的 PC/IXF 列不存在。将插入空值。
SQL3167W
指定要装入到数据库列 名称 的 PC/IXF 列无效。将插入空值。
SQL3168W
指定要装入到数据库列 名称 的 PC/IXF 列与数据库列不兼容。将插入空值。
SQL3169N
FORCEIN 选项可用于支持 PC/IXF 列 名称 装入到数据库列 名称 中。
SQL3170W
在一行数据内到达文件末尾。未装入部分数据行。
SQL3171W
在列标题行中发现非标号记录。未处理该记录。
SQL3172W
找不到指定的输入列 名称。相应的数据库列将包含空值。
SQL3173N
对列 名称 插入的数据所包含的字符将总是比列宽少。
SQL3174W
数据库列 名称 的数据类型 类型 与任何 WSF 列类型都不兼容。将对此列插入空值。
SQL3175W
数据库行 行 列 列 的输入记录无效。
SQL3176W
WSF 文件中的第 行 行第 列 列的值超出日期值的范围。
SQL3177W
WSF 文件中第 行 行第 列 列的值超出时间值的范围。
SQL3178W
WSF 文件中数据库第 行号 行第 列号 列中的记录的类型对于表示时间值而言无效。
SQL3179W
输入文件中的行 行 丢失要插入到数据库中不可为空列的数据。未插入该行。
SQL3180W
将第 号码 张软盘插入驱动器 驱动器 中。
SQL3181W
在找到期望的结束记录之前,到达文件末尾。
SQL3182W
将第 号码 张软盘插入驱动器 驱动器 中。当前插入的软盘不是正确 的软盘,或延续软盘无效。
SQL3183W
filetmod 参数的多个定界符覆盖未由空白分隔。
SQL3184W
创建表时发生了 SQL 警告 SQLCODE。
SQL3185W
处理输入文件的第 行号 行中的数据时,发生前一个错误。
SQL3186W
未将数据装入数据库,因为日志已满或者耗尽了锁定空间。返回了 SQLCODE sqlcode。将尝试落实,如果落实成功,那么操作将继续。
SQL3187W
创建索引时出错。返回了 SQLCODE sqlcode。
SQL3188N
当擦除表的内容时出错。
SQL3189N
前一条消息涉及到具有列 列列表 的索引 名称。
SQL3190N
indexixt 选项对此 Import 操作无效。
SQL3191N
在第 行号 行第 列号 列中以 字符串 开头的字段与用户指定的 DATEFORMAT、TIMEFORMAT 或 TIMESTAMPFORMAT 不匹配。该行将被拒绝。
SQL3192N
在 filetmod 中,用户指定的以字符串 字符串 开头的格式 关键字 无效。
SQL3193N
不能更新指定的视图或具体化查询表。无法装入/导入(LOAD/IMPORT)至此视图,或者无法装入(LOAD)至此具体化查询表。
SQL3194N
指定的表是系统表。不能装入系统表。
SQL3195W
不能将驱动器 驱动器 中的软盘 编号 用于输出文件。插入 带有可写入的可用空间的格式化软盘。
SQL3196N
找不到输入文件。
SQL3197N
试图执行 Import 或 Export 的多个副本。
SQL3201N
指定的表不能被替换,因为有另一个表依赖于该表。
SQL3202N
LOAD 实用程序未能获取分区锁定。
SQL3203N
指定的目标不允许 INSERT_UPDATE 选项,因为它没有主键,或者所有列都在主键中。
SQL3204N
INSERT_UPDATE 选项可能不应用于视图。
SQL3205N
因为基本表有从属对象,所以指定的视图不能被替换。
SQL3206N
因为指定视图的定义涉及子查询,所以不能将其替换。
SQL3207N
提供了无效的表列表。原因码为 原因码。
SQL3208W
将数据从类型表导入常规表。
SQL3209N
带有 CREATE 选项的 Import 既不允许重命名子表名,也不允许重命名属性名。
SQL3210N
选项 选项 与 命令名 中的层次结构不兼容。
SQL3211N
LOAD 不支持类型表。
SQL3212N
对于带有 DATALINK 列的表或处于删除暂挂状态的表空间,当前不支持 LOAD 命令的 TERMINATE 选项。
SQL3213I
建立索引方式为 方式。
SQL3214N
LOAD 实用程序不支持延迟对带有唯一索引的表建立索引。
SQL3215W
当装入到表的 DMS 表空间中,而该表的索引对象与任何其他目标表的对象驻留在同一表空间中,且还指定了 COPY 选项时,LOAD 实用程序当前不支持 INCREMENTAL 建立索引方式。将改为使用 REBUILD 建立索引方式。
SQL3216W
表的索引对象在 LOAD 实用程序开始时与 INCREMENTAL 索引维护不兼容。此 LOAD 实用程序操作期间,不能执行按 INCREMENTAL 方式建立索引。将改为使用 REBUILD 建立索引方式。
SQL3217W
仅当使用 LOAD 来通过使用 INSERT INTO 操作追加数据时,才支持 INCREMENTAL 建立索引方式。当前 LOAD 操作是 操作。实用程序将使用建立索引方式 方式。
SQL3218C
LOAD 实用程序不能继续,因为它遇到了一个或多个破坏的索引文件。重新启动数据库并重新提交 LOAD 命令。
SQL3219N
LOAD 实用程序未能禁用对目标表的约束检查。
SQL3220W
在 目录名 目录中找不到卷 卷名。将该卷复制到此目录中,并继续 LOAD/IMPORT。
SQL3221W
...开始 COMMIT WORK。输入记录计数 = 计数。
SQL3222W
...对任何数据库更改的 COMMIT 都成功。
SQL3223N
未正确指定指向 参数 的类型指针的参数。
SQL3225N
RESTARTCOUNT 值或 SKIPCOUNT 值 值 大于文件中的行数(行数)。未装入任何行。
SQL3227W
记录标记 标记-1 指的是用户记录号 标记-2。
SQL3228N
对于带有 DATALINK 列的表,DEFERRED INDEXING 不受支持。
SQL3229W
第 行号 第 列号 列中的字段值无效。该行被拒绝。原因码:原因码。
SQL3230N
不支持从数据文件代码页 数据文件代码页 至数据类型 数据类型 的数据库代码页 数据库代码页 的代码页转换。
SQL3232W
写入文件 文件名 时出错。已改为使用 文件名。
SQL3233W
忽略了 XML 数据说明符(XDS)中的属性 属性名。原因码:原因码
SQL3234N
列 列号 的 XML 数据说明符(XDS)无效。属性名:属性名;字符号:字符号;原因码:原因码
SQL3235N
实用程序无法使用指定的 类型 的路径 路径名 参数。原因码:原因码。
SQL3236N
在 XMLVALIDATE 选项的 IGNORE 子句中指定了模式 模式名,但是 MAP 子句中的模式对的左边也存在该模式。
SQL3237N
所提供的 EXPORT 操作字符串无法与 XMLSAVESCHEMA 选项配合使用。原因码:原因码
SQL3238N
WSF 文件格式与 功能部件 不兼容。
SQL3239W
不会将模式信息包括在某些 XML 文档的 XDS 中。
SQL3240N
授权标识 授权标识 没有对受安全策略 策略名 保护的表运行实用程序所必需的 LBAC 凭证。
SQL3241W
在输入源中,第 行 行和第 列 列包含对目标表无效的安全标号。
SQL3242W
在输入源中,行 行 和列 列 包含对目标表无效的安全标号字符串。
SQL3243W
在输入源中,第 行 行和第 列 列中的安全标号字符串包含元素 元素,该元素不是安全标号组件 组件 的有效元素。
SQL3244W
在输入源中,行 行 和列 列 包含名为 安全标号名 的安全标号,但在保护目标表的安全策略 策略名 中找不到该安全标号。
SQL3245W
由于用户没有必需的 LBAC 凭证,因此无法将输入源中的行 行 和列 列 插入到目标表中。
SQL3250N
COMPOUND = 值 是无效的。原因码:原因码。
SQL3251N
在导入期间发生了多于 错误计数 个错误。
SQL3252N
LOAD METHOD 方法 选项与指定的文件格式不兼容。
SQL3253N
实用程序正在开始通过 SQL 语句 语句 来从数据库 数据库 装入数据。
SQL3254N
实用程序正在开始从数据库 数据库 中的表 模式.表名 装入数据。
SQL3255N
Load 实用程序在执行 SOURCEUSEREXIT 源用户出口 时出错。原因码为 原因。
SQL3256N
Load 实用程序在处理指定文件类型的数据时出错。
SQL3257N
Load 实用程序在处理指定文件类型中的数据时出错。原因码为 原因。在适用的时候,记录号是 记录号,列号是 列号。
SQL3260N
访问 LDAP 目录时,发生了意外错误。错误代码 = 错误代码。
SQL3261N
因为未指定必需的输入参数,所以 REGISTER LDAP 命令未成功完成。原因码 = 原因码。
SQL3262N
TCP/IP 服务名称 名称 无效。
SQL3263N
协议类型不受支持。
SQL3264N
未在 LDAP 中注册 DB2 服务器。
SQL3265N
LDAP 认证期间发生了意外错误。
SQL3266N
LDAP 用户密码不正确。
SQL3267N
授权标识 没有足够的权限来执行所请求的命令。
SQL3268N
LDAP 模式与 DB2 的当前发行版不兼容。
SQL3269N
因为 LDAP 服务器不可用,所以 DB2 无法访问 LDAP 目录中的信息。
SQL3270N
LDAP 用户的“专有名称”(DN)无效。
SQL3271N
未对当前登录用户定义 LDAP 用户的“专有名称”(DN)和/或密码。
SQL3272N
在 LDAP 目录中找不到节点 节点名。
SQL3273N
在 LDAP 目录中找不到数据库 数据库别名。
SQL3274W
已成功创建数据库。但是,未在 LDAP 目录中编目该数据库。SQLCODE = sqlcode。
SQL3275W
已成功删除数据库。但是,未在 LDAP 目录中取消编目该数据库。SQLCODE = sqlcode。
SQL3276N
得不到 LDAP 命名上下文。
SQL3277N
数据库 数据库别名 在 LDAP 目录中已存在。
SQL3278N
节点 节点 在 LDAP 目录中已存在。
SQL3279N
因为 LDAP 被禁用,所以命令未成功完成。
SQL3280N
尝试连接 DRDA 服务器失败。
SQL3281N
OSTYPE 参数无效。
SQL3282N
提供的凭证无效。
SQL3283W
成功更新了数据库管理器配置。然而,在 LDAP 目录中未更新协议信息。SQLCODE = sqlcode-值。
SQL3284N
nodetype 参数无效。
SQL3285N
因为不支持 LDAP,所以命令未成功完成。
SQL3300N
输入文件中的记录的顺序不正确。
SQL3301N
在输入文件的中间找到 BOF 记录。
SQL3302N
导入在任何数据前找到 EOF 记录。
SQL3303N
当在“操作字符串”参数中使用 CREATE 或 REPLACE_CREATE 关键字时,文件类型必须是 IXF。
SQL3304N
该表不存在。
SQL3305N
不能创建表,因为它已存在。
SQL3306N
当将行插入表时,发生 SQL 错误 sqlcode。
SQL3307N
METHOD 参数中的列数与“操作字符串”参数中的条目数不匹配,或者在 METHOD 参数中指定的列不存在。
SQL3308N
PC/IXF 列 名称 的代码页值与应用程序的代码页值不兼容。未指定 FORCEIN 参数。
SQL3309N
PC/IXF 文件中的列 名称 被定义为图形列。未指定 FORCEIN 参数。
SQL3310N
PC/IXF 文件中的列 名称 无效。
SQL3311N
此 PC/IXF 文件在 Import CREATE 方式下不受支持。原因码 = 原因码。
SQL3313N
磁盘已满。处理结束。
SQL3314N
A 记录中的日期和时间字段与 H 记录中的日期和时间字段不匹配。
SQL3315N
子类型为 C 的 A 记录中的卷字段无效。
SQL3316N
当关闭输入文件的一部分时,发生了 I/O 错误。
SQL3317N
filetmod 参数所指向的字符串包含冲突的信息。
SQL3318N
filetmod 参数中有重复关键字。
SQL3319N
创建表时发生 SQL 错误 sqlcode。
SQL3320N
filetmod 参数的关键字后面没有定界符或十进制小数点字符。
SQL3321C
未将数据导入数据库,因为日志已满或者耗尽了锁定空间。恢复不成功。返回了 SQLCODE sqlcode。
SQL3322N
发生操作系统信号量错误。
SQL3324N
列 名称 的类型为 类型,不识别该类型。
SQL3325W
第 行号 行中的所有列都是空值;WSF 数据文件将不包括该行。
SQL3326N
“操作字符串”参数中表名后面的列列表无效。
SQL3327N
发生系统错误(原因码 1 = 原因码-1 和原因码 2 = 原因码-2)。
SQL3330W
在第 行号 行中,字符字段的长度为奇数,但其目标数据库列为图形列。未装入该行。
SQL3331C
文件(或目录)的许可权设置不允许指定的访问。
SQL3332C
已达到最大打开文件数。
SQL3333C
文件或目录不存在。
SQL3334C
没有足够的存储器可用。
SQL3335C
文件系统已满。
SQL3337N
对服务器写数据时发生了 I/O 错误。
SQL3338N
读服务器上的临时消息文件时发生了 I/O 错误。
SQL3340N
未能对表的并行读访问执行装入。原因码 = 原因码。
SQL3341N
USE 选项提供了无效的表空间名。原因码 = 原因码。
SQL3342N
权限不够,无法使用 LOCK WITH FORCE 选项。
SQL3343N
在前滚失败的装入操作后不允许重新启动装入。
SQL3346N
忽略了 USE TablespaceName 选项。原因码 = 原因码。
SQL3400N
METHOD 中指定的方法对“非定界”ASCII 码文件无效。它必须是“L”(表示位置)。
SQL3401N
METHOD 中指定的方法对任何 filetype 均无效。
SQL3402N
对不可为空的列 名称 指定了起始/结束位置对,但两者的值均为零。
SQL3403N
用于插入到列 名称 中的起始/结束位置对无效。(开始 结尾)
SQL3404N
用于插入到列 名称 中的起始/结束位置对对数字无效。
SQL3405N
用于插入到列 名称 中的起始/结束位置对对日期无效。
SQL3406N
用于插入到列 名称 中的起始/结束位置对对时间无效。
SQL3407N
用于插入到列 名称 中的起始/结束位置对对时间戳记无效。
SQL3408W
用于插入到列 名称 中的起始/结束位置对定义了大于目标列的字段。数据可能被截断。
SQL3409W
用于插入到列 名称 中的起始/结束位置对定义了短于目标定长列的字段。将填充数据。
SQL3410N
用于插入到列 名称 中的起始/结束位置对对图形无效。
SQL3411W
第 行号 行第 列号 列中的字段值对图形列无效。插入了空值。
SQL3412W
第 行号 行第 列号 列中的字段值对图形列无效,但是目标列不可为空。 未插入该行。
SQL3413W
第 行号 行第 列号 列中的字段值对于目标列而言太短。插入了空值。
SQL3414N
找不到临时文件 文件名。
SQL3415W
未能将第 行号 行和第 列号 列中的字段值从输入数据文件的代码页转换为数据库的代码页。装入了空值。
SQL3416W
未能将第 行号 行和第 列号 列中的字段值从输入数据文件的代码页转换为数据库的代码页。未装入该行。
SQL3417N
开始结束位置对 对号 对代码页 代码页 无效。
SQL3418W
如果数据是使用 DB2 导出的,那么不应指定 NOCHARDEL 文件类型修饰符。提供此修饰符的目的是支持不具有字符定界符的供应商数据文件。
SQL3419W
供应商排序不支持指定的排序选项。将使用缺省 DB2 排序来继续 执行操作。
SQL3500W
在时间 时间戳记,实用程序在开始 阶段。
SQL3501W
由于禁用数据库正向恢复,因此表所驻留的表空间将不被置于备份暂挂状态。
SQL3502N
实用程序遇到了 数目 个警告,这超过了允许的最大警告数。
SQL3503W
实用程序已装入 行数 行,这等于用户指定的总行数。
SQL3504W
正在建立一致点。
SQL3505N
在 RECLEN 选项的 filetmod 中指定的长度不在有效范围 1 至 32767 之内。
SQL3506W
第 行号 行第 列号 列中空指示符中指定的值无效。将假设值为 'N'。
SQL3507N
对空指示符指定的列号不在有效范围 0 到 32767 之内,或空指示符参数无效。
SQL3508N
装入或装入查询期间,当访问类型为 文件类型 的文件或路径时出错。原因码:原因码。路径:路径/文件。
SQL3509W
实用程序已从表中删除了 数目 行。
SQL3510N
不能访问用于排序阶段的工作目录。
SQL3511W
第 行号 行第 列号 列中命名的文件找不到。装入了空值。
SQL3512W
找不到第 行号 行第 列号 列中命名的文件,但目标列不可为空。未装入该行。
SQL3513N
文件的代码页与数据库的代码页不匹配。不能装入此文件。
SQL3514N
发生了实用程序系统错误。函数代码:函数。原因码:原因码。错误代码:错误代码。
SQL3515W
在时间 时间戳记,实用程序已经完成了 阶段。
SQL3516N
实用程序未能按指定的那样重新启动 Load。
SQL3517N
从输入源读取了意外的记录。
SQL3518N
源中的数据与要装入的表不兼容。
SQL3519W
开始装入一致点。输入记录数 = 计数。
SQL3520W
“装入一致点”成功。
SQL3521N
未提供输入源文件 序号。
SQL3522N
当禁用日志保留和用户出口时,不能提供复制目标。
SQL3523W
消息文件中没有要检索的消息。原因码:返回码。
SQL3524N
选项 选项 具有无效值 值。
SQL3525N
选项-1 选项与 选项-2 选项不兼容。
SQL3526N
修饰符子句 子句 与当前装入命令不一致。原因码:原因码。
SQL3527N
FILETMOD 参数中对 CODEPAGE 选项指定的数字无效。
SQL3528W
可能将 CLP 命令中指定的定界符(列定界符、字符串定界符或小数点) 从应用程序代码页转换为数据库代码页。
SQL3529N
操作名称 操作在列 列号 中遇到不受支持的数据类型 数据类型。
SQL3530I
LOAD QUERY 实用程序正在分区 分区号 上监视 代理类型 进度。
SQL3531I
已发生 LOAD RESTART。
SQL3532I
Load 实用程序当前正处于 阶段 阶段。
SQL3533I
Load 实用程序当前正在构建第 编号 个索引(共 数值 个)。
SQL3534I
Load DELETE 阶段大概已完成 数值%。
SQL3535W
LOAD 命令参数 参数名 不再受支持;LOAD 实用程序将忽略它的值。
SQL3536N
系统临时表空间 表空间名 已满。
SQL3537N
执行 LOAD 实用程序期间,未能分配排序内存。
SQL3538N
因为多个 LOAD 正在使用同一临时文件路径,所以 LOAD QUERY 实用程序失败。
SQL3539N
因为至少已尝试了一次 LOAD TERMINATE,所以 LOAD RESTART 不能继续。
SQL3550W
第 行号 行第 列号 列中的字段值不是 NULL,但目标列已定义为 GENERATED ALWAYS。
SQL3551W
表至少包含实用程序将覆盖的一个 GENERATED ALWAYS 列。
SQL3600N
因为表 表名 是用户维护的具体化查询表或未处于设置完整性暂挂状态,所以 SET INTEGRITY 语句的 IMMEDIATE CHECKED 选项无效。
SQL3601W
该语句导致一个或多个表自动置于设置完整性暂挂状态。
SQL3602W
检查数据处理找到约束违例,并将它们移至异常表。
SQL3603N
通过 SET INTEGRITY 语句来检查数据处理时,发现涉及名为 名称 的约束或唯一索引的完整性违例。
SQL3604N
与 SET INTEGRITY 语句或 LOAD 实用程序中的表 表名 相对应的 异常表 异常表名 的结构不正确、此异常表已用唯一索引、约束、生成列或触发器定义,或者它处于设置完整性暂挂状态,或者它属于无效类型。原因码为 原因码。
SQL3605N
在 SET INTEGRITY 语句中指定的表 表名 未列示出来以进行检查,或者该表是指定了多次的异常表。
SQL3606N
检查的表数目与在 SET INTEGRITY 语句中指定的异常表数目不匹配。
SQL3608N
当父表或基础表 父表名 处于设置完整性暂挂状态或将使用 SET INTEGRITY 语句将其置于设置完整性暂挂状态时,不能使用 SET INTEGRITY 语句检查从属表 从属表名。
SQL3700W
设备 设备 已满。有 活动设备 个活动设备。请安装新介质,或执行适当的操作。
SQL3701W
指定了 lobpaths 参数,但此表未包含任何 LOB 或 Long 数据。此参数将被忽略。
SQL3702W
警告。接收到设备 设备 的 SQLCODE sqlcode。卸装将尝试在 没有此设备的情况下继续。
SQL3703W
已卸装并发送了类型为 类型 的总页数 yyy 中的 xxx 页,以便将它们写入目标介质。
SQL3704N
指定的 num_buffers 参数无效。
SQL3705N
指定的缓冲区大小参数无效。必须将缓冲区大小指定为 0,或在 8 和 250000 之间(包括 8 和 250000)。对于多个缓冲区,缓冲区总大小不能超过 250000。
SQL3706N
在 路径/文件 上遇到磁盘满错误。
SQL3707N
指定的排序内存大小参数 大小-1 无效。需要的最小大小为 大小-2。
SQL3783N
打开复制位置文件时出错。打开文件错误代码是 错误代码。
SQL3784W
在读复制位置文件时遇到无效数据。故障发生在第 行号 行处,错误类型是 错误类型。
SQL3785N
因为错误 sqlcode,所以在节点 节点号 上的时间 时间戳记 表 模式.表名 的装入恢复失败,更多信息 更多信息。
SQL3798W
为了继续装入恢复,对参数 参数 使用了无效值来调用前滚恢复 API。
SQL3799W
由于警告 sqlcode,因此在节点 节点号 上时间 时间戳记 表 模式.表名 的装入恢复暂挂,更多信息 更多信息。
SQL3802N
遇到无效停顿方式 停顿方式。
SQL3804N
索引无效。
SQL3805N
应用程序的状态或指定表的一个或多个表空间的状态禁止 loadapi 操作或 quiescemode 操作。原因码 =原因码。
SQL3806N
对于要装入的表,并非所有表约束都已关闭。
SQL3807N
实例或数据库 名称 停顿被暂挂。
SQL3808N
实例或数据库 名称 取消停顿被暂挂。
SQL3901N
发生了非严重系统错误。原因码为 原因码。
SQL3902C
发生了系统错误。不能进行进一步的处理。原因码 = 原因码。
SQL3910I
同步会话成功完成。
SQL3911I
测试同步会话成功完成。
SQL3912I
STOP 成功完成。
SQL3913I
已发出 STOP,但当前没有活动的同步会话。
SQL3914I
已发出用户中断。同步会话成功停止。
SQL3915I
在将结果上载至卫星控制服务器之前,发出了用户中断。将在 下一同步会话期间上载结果。
SQL3916I
接收到 STOP 请求。同步会话成功停止。
SQL3917I
在将结果上载至卫星控制服务器之前,接收到 STOP 请求。将在 下一同步会话期间上载结果。
SQL3918I
成功获取同步进度信息。
SQL3919I
在卫星可联系到卫星控制服务器之前,接收到 STOP 请求。同步成功停止。
SQL3920I
此卫星上的应用程序版本与可用于此卫星的组的应用程序版本不兼容。同步不能发生。
SQL3921I
在卫星控制服务器上,此卫星被禁用。同步不能发生。
SQL3930W
没有要执行的同步脚本。
SQL3931W
测试同步会话成功完成。但是,在卫星控制数据库中找不到卫星标识。
SQL3932W
测试同步会话成功完成。然而,卫星应用程序版本不是在 本地设置的,或者在卫星控制服务器上,此卫星的组不存在卫星应用程序版本。
SQL3933W
测试同步会话成功完成。但是,卫星的发行版级别不 受卫星控制服务器的发行版级别支持。
SQL3934W
测试同步会话成功完成。但是,在卫星控制服务器上,此卫星被禁用。
SQL3935W
测试同步会话成功完成。但是,在卫星控制服务器上,此卫星处于故障状态。
SQL3936W
没有进度信息可用。
SQL3937W
此卫星的应用程序版本与可用于此卫星的组的应用程序版本不匹配。
SQL3938W
脚本执行期间发出中断。同步会话已停止,但卫星可能处于不一致状态。
SQL3942I
已成功设置卫星的同步会话标识符。
SQL3943N
同步会话标识符超过最大长度(长度 个字符)。
SQL3944I
已成功复位卫星的同步会话标识符。
SQL3945I
成功检索到卫星的同步会话标识符。
SQL3946N
同步会话标识符操作失败。
SQL3950N
有同步会话活动。最多只能有一个同步会话处于活动状态。
SQL3951N
在本地找不到卫星标识。
SQL3952N
在卫星控制服务器上找不到卫星标识。
SQL3953N
在卫星控制服务器上,此卫星已被禁用。
SQL3954N
在卫星控制服务器上,此卫星处于故障状态。
SQL3955N
找不到卫星控制数据库名称或它的别名。
SQL3956N
此卫星的应用程序版本不是在本地定义的。
SQL3957N
由于通信故障而不能与卫星控制数据库连接:SQLCODE=sqlcode,SQLSTATES=sqlstate,Tokens=标记-1,标记-2,标记-3。
SQL3958N
同步会话期间出错:SQLCODE=sqlcode,SQLSTATES=sqlstate,Tokens=标记-1,标记-2,标记-3。
SQL3959N
由于通信故障而不能启动同步会话:SQLCODE=sqlcode,SQLSTATES=sqlstate,Tokens=标记-1,标记-2,标记-3。
SQL3960N
由于通信故障而不能将结果上载到卫星控制服务器:SQLCODE=sqlcode,SQLSTATES=sqlstate,Tokens=标记-1,标记-2,标记-3。
SQL3961N
不能对卫星控制服务器进行认证。
SQL3962N
由于数据库错误而未能启动同步:SQLCODE=sqlcode,SQLSTATES=sqlstate,Tokens=标记-1,标记-2,标记-3。
SQL3963N
因为数据库错误而不能上载结果:SQLCODE=sqlcode,SQLSTATES=sqlstate,Tokens=标记-1,标记-2,标记-3。
SQL3964N
因为卫星的发行版级别不受卫星控制服务器支持,所以同步失败。
SQL3965N
由于卫星控制服务器故障而不能下载同步脚本:SQLCODE=sqlcode,SQLSTATES=sqlstate,Tokens=标记-1,标记-2,标记-3。
SQL3966N
同步会话失败。原因码为 原因码。
SQL3967N
不能检索进度信息。
SQL3968N
因为脚本故障,所以同步未能成功完成。然而,结果被成功地 发送到了卫星控制服务器。
SQL3969N
因为在脚本执行期间接收到中断,所以同步失败。
SQL3970N
同步会话失败:SQLCODE sqlcode,SQLSTATE sqlatate。在位置 位置 检测到该错误。
SQL4001N
第 行 行上的列 列 中的字符 字符 无效。
SQL4002N
标记-1 和 标记-2 是未声明的主变量,两者都不能在单一 SQL 语句中用作描述符。
SQL4003N
第 行号 行上的 SQL 语句不受此版本的预编译器支持。
SQL4004N
程序包名无效。
SQL4005N
在第 行 行上,从位置 位置 开始找到无效标记 标记。
SQL4006N
结构嵌套层次太多。
SQL4007N
主结构 主结构 没有字段。
SQL4008N
即使在完全限定的情况下,也不能唯一地引用主变量 名称。
SQL4009N
数据长度表达式无效。
SQL4010N
“复合 SQL”语句的嵌套非法。
SQL4011N
“复合 SQL”语句中有无效 SQL 子语句。
SQL4012N
“复合 SQL”语句中有对 COMMIT 的无效使用。
SQL4013N
找到 END COMPOUND 语句,但前面没有 BEGIN COMPOUND 语句。
SQL4014N
复合 SQL 语法无效。
SQL4015N
预处理期间出错。
SQL4016N
找不到指定的预处理器。
SQL4017W
预处理已成功完成。
SQL4018W
开始处理预处理文件 预处理文件。
SQL4019W
完成处理预处理文件 预处理文件。
SQL4020N
'long' 主变量 标记-1 无效。转而使用“sqlint32”。
SQL4100I
标志程序使用 sqlflag-type SQL 语言语法来进行语法检查。
SQL4102W
在以文本 文本 开始的标记处发生 SQL 语法违规。
SQL4103W
数据定义语句不在 CREATE SCHEMA 语句中。
SQL4104W
有非标准嵌入式注释。
SQL4105W
发生 SQL 语法偏差。该语句不完整。
SQL4106W
标识符 标识符 多于 18 个字符。
SQL4107W
列 列 具有无效的长度、精度或小数位属性。
SQL4108W
指示符变量具有非精确数字数据类型,或带有非零小数位。
SQL4109W
SET FUNCTION SPECIFICATION 引用列 列。
SQL4110W
包含 列 的 VALUE EXPRESSION 不能包括运算符。
SQL4111W
COLUMN REFERENCE 丢失,或对 ALL 列函数 函数 无效。
SQL4112W
列 列 不唯一,需要限定。
SQL4113W
VALUE EXPRESSION 不能包含 SET FUNCTION SPECIFICATION。
SQL4114W
列 列 未标识当前作用域中的表列。
SQL4115W
包含 OUTER REFERENCE 列 列 的列函数不在 HAVING 子句的子查询中。
SQL4116W
SUM 或 AVG 函数的结果不能是字符串。
SQL4117W
运算符 运算符 在此上下文中无效。
SQL4118W
exptype EXPRESSION 正在比较不兼容的数据类型。
SQL4119W
LIKE 谓词中的操作数不是字符串。
SQL4120W
ESCAPE 字符必须是单字节字符串。
SQL4121W
WHERE 子句、GROUP BY 子句或 HAVING 子句对分组视图 模式名.视图 无效。
SQL4122W
模式名.名称 在 FROM 子句中出现多次。
SQL4123W
对于分组视图,FROM 子句中只允许引用一个表。
SQL4124W
在 WHERE 子句中,对从列函数派生的列 列 的引用无效。
SQL4125W
当 WHERE 子句带有列函数时,HAVING 子句必须包含 WHERE 子句。
SQL4126W
列 的 COLUMN REFERENCE 必须是 OUTER REFERENCE。
SQL4127W
列 列 在当前作用域内重复。
SQL4128W
列名 的 COLUMN REFERENCE 应该是分组列,或者应在列函数中指定。
SQL4129W
使用值为 * 的 SELECT LIST 时,表 模式名.表 的 DEGREE 应是 1。
SQL4130W
列函数对以表 模式名.表 开始的 TABLE EXPRESSION 无效。
SQL4131W
列 的 COLUMN REFERENCE 无效。
SQL4132W
多次指定 DISTINCT。
SQL4133W
COMPARISON PREDICATE 子查询不能包含 GROUP BY 或 HAVING 子句。
SQL4134W
COMPARISON PREDICATE 子查询不能标识分组视图。
SQL4135W
存在无效的 AUTHORIZATION IDENTIFIER 授权标识。
SQL4136W
表或视图 模式名.名称 已存在。
SQL4137W
COLUMN DEFINITION 丢失。
SQL4138W
目标的数据类型 类型-1 与源的数据类型 类型-2 不兼容。
SQL4139W
必须对 模式名.表 指定 VIEW COLUMN LIST。
SQL4140W
发生错误,导致标志程序停止。模块名 = 模块名。内部错误代码 = 错误代码。
SQL4141W
试图在模块 模块名 中生成消息 消息号 时出错。
SQL4142W
没有足够内存用于标志程序操作。内部错误代码 = 错误代码。
SQL4143W
释放标志程序内存时出错。内部错误代码 = 错误代码。
SQL4144W
在模块 模块名 中调用 FLAGGER 时发生内部错误。内部错误代码 = 错误代码。
SQL4145W
FLAGGER 访问系统目录期间出错。加标志操作仍然继续,以便只检查语法。SQLCODE = nnnSQLERRP = modname SQLERRD1 = nnn 创建程序 = 创建程序名 表 = 表名。
SQL4146W
发生内部错误导致,导致语义处理停止。模块名 = 模块名。内部错误代码 = 错误代码。
SQL4147W
无效标志程序版本号。
SQL4170W
必须将 列号 列声明成 NOT NULL。
SQL4171W
查看的表 模式名.表 必须是可更新的。
SQL4172W
列名数无效。
SQL4173W
在关闭游标 游标 之前,必须先对其进行声明。
SQL4174W
已声明游标 游标。
SQL4175W
在此上下文中,只有 * 或列名才有效。
SQL4176W
由以 模式名-1.表-1 开头的 QUERY EXPRESSION 和以 模式名-2.表-2 开头的 QUERY TERM 标识的表的描述必须相同。
SQL4177W
SORT SPECIFICATION 号码 在游标 游标 的 DEGREE 之外。
SQL4178W
表 模式名.表 是只读表。
SQL4179W
一定不能在 SEARCH CONDITION 中包含的任何子查询的 FROM 子句中标识表 模式名.表。
SQL4180W
表 模式名-1.表-1 不是在 DECLARE CURSOR 语句中指定的第一个表 模式名-2.表-2。
SQL4181W
TARGET SPECIFICATION 的数目与游标 游标 的 DEGREE 不匹配。
SQL4182W
INSERT 语句的目标表 模式名.表 也在 FROM 子句或子查询中。
SQL4183W
指定的列数与指定的值的数目不匹配。
SQL4184W
指定的列数与以表 模式名.表 开始的 QUERY SPECIFICATION 的 DEGREE 不匹配。
SQL4185W
在列 列 与 INSERT 或 UPDATE 项目之间,存在数据类型或长度不匹配。
SQL4186W
不能在此上下文中使用 GROUP BY 或 HAVING 子句,或标识分组视图。
SQL4187W
SELECT LIST 中指定的元素数应该与 SELECT TARGET LIST 中的元素数相匹配。
SQL4188W
UPDATE 语句的 SET 子句不允许列函数。
SQL4189W
不能对“非 NULL”列 列 指定 NULL。
SQL4190W
引用不识别的数据类型的主变量。该主变量位置是 位置。
SQL4191W
不识别 列名 列的数据类型。
SQL4192W
在目录中找不到表 模式名.表。
SQL4300N
未在此平台上安装或正确配置 Java 支持。
SQL4301N
Java 或 .NET 解释器启动或通信失败,原因码为 原因码。
SQL4302N
过程或用户定义的函数 名称(特定名称 特定名称)由于异常 字符串 而异常终止。
SQL4303N
Java 存储过程或用户定义的函数 名称,特定名称 特定名称 不能由外部名 字符串 来标识。
SQL4304N
Java 存储过程或用户定义的函数 名称(特定名称 特定名称)不能装入 Java 类 类,原因码为 原因码。
SQL4306N
Java 存储过程或用户定义的函数 名称(特定名称 特定名称)不能调用 Java 方法 方法,特征符为 字符串。
SQL4400N
授权标识 无权在 DB2 管理服务器上执行管理任务。
SQL4401C
DB2 管理服务器在启动期间遇到错误。
SQL4402W
DB2ADMIN 命令成功。
SQL4403N
命令的语法无效。
SQL4404N
DB2 管理服务器不存在。
SQL4405W
DB2 管理服务器已存在。
SQL4406W
已成功启动 DB2 管理服务器。
SQL4407W
已成功停止“DB2管理服务器”。
SQL4408N
因为 DB2 管理服务器是活动的,所以未将其删除。
SQL4409W
DB2 管理服务器已是活动的。
SQL4410W
DB2 管理服务器不是活动的。
SQL4411N
因为服务器实例不是 DB2 管理服务器,所以不允许请求的操作。
SQL4412N
DB2 管理服务器的登录用户帐户无效。
SQL4413W
用法:DB2ADMIN 创建、删除、启动或停止 DB2 管理服务器。
SQL4414N
DB2 管理服务器不是活动的。
SQL4701N
已超出最大分区数(最大数目)。
SQL4702N
由应用程序句柄 应用程序句柄、工作单元标识 工作单元标识 和活动标识 活动标识 所标识的活动不存在。
SQL4703N
无法取消由应用程序句柄 应用程序句柄、工作单元 工作单元标识 和活动标识 活动标识 所标识的活动。原因码 = 原因码。
SQL4704N
只能对数据库或服务超类 数据库或服务超类名称 定义一个工作操作集。
SQL4705N
在映射工作操作 工作操作名称 中指定的服务子类不能是缺省服务子类。
SQL4706N
对工作类 工作类名称 指定的范围无效。
SQL4707N
工作负载 工作负载名称 不能处理请求,因为该工作负载无权访问数据库或已被禁用。
SQL4708N
目前,此工作单元仅允许 COMMIT 或 ROLLBACK 语句。
SQL4709N
不能从工作负载 工作负载名称 的定义中删除最后一个连接属性。
SQL4710N
不能删除工作负载 工作负载名称,因为它未被禁用、出现了活动的工作负载或者具有相关联的阈值。
SQL4711N
不能删除阈值 阈值名称。该阈值未被禁用,阈值队列不为空,或者活动正在该阈值的控制下运行。
SQL4712N
已超过阈值 阈值名称。原因码 = 原因码。
SQL4713N
已超过数据库或服务超类的最大服务类数目。无法创建服务类 服务类名称。
SQL4714N
请求无法执行,因为服务类 服务类名称 已被禁用。
SQL4715N
无法在缺省服务类下创建服务子类。
SQL4716N
与外部工作负载管理器进行通信时出错。
SQL4717N
无法删除服务类 服务类名称,因为它包含子类、相关联的工作负载、工作操作集、工作操作、连接、活动或阈值,未被禁用或者是缺省服务类。原因码 = 原因码。
SQL4718N
缺省服务类 服务类名称 无法按照指定方式进行改变或关联。原因码 = 原因码。
SQL4719N
PREVENT EXECUTION 工作操作 工作操作名称 已应用于该活动,因此该活动未运行。
SQL4720N
指定的工作操作类型对于工作操作 工作操作名称 无效。原因码为 原因码。
SQL4721N
无法创建阈值 阈值名称(原因码 = 原因码)。
SQL4722W
阈值未创建,因为已存在某个具有匹配定义的阈值 对象名。
SQL4723N
已经对连接属性 连接属性 定义值 连接属性值,或者检测到该值重复。
SQL4724N
值 连接属性值 无法删除,因为它不是对连接属性 连接属性 定义的。
SQL4725N
已取消该活动。
SQL4728W
您对用户定义的服务类指定的优先级设置高于缺省系统服务类的优先级设置。
SQL4901N
由于先前的错误,需要重新初始化“预编译器服务”。
SQL4902N
函数 函数 的参数 n 中至少有一个字符无效。
SQL4903N
函数 名称 的参数 n 的长度无效。
SQL4904N
函数 函数 的参数 n 的指针无效。
SQL4905N
函数 函数 的参数 n 的值超出有效范围。
SQL4906N
对于前滚操作,指定的表空间名的列表是不完整的集合。
SQL4907W
已恢复数据库 名称,但是前滚操作包括的表空间列表中一个或多个表处于设置完整性暂挂状态。
SQL4908N
对数据库 名称 的前滚恢复指定的表空间列表在节点 节点列表 上无效。
SQL4909W
已成功完成前滚恢复,但是有一个或多个表空间使它们的表置于 DRP/DRNP 状态。检查管理通知日志,以了解有关节点 节点列表 的详细信息。
SQL4910N
溢出日志路径 日志路径 无效。
SQL4911N
主变量数据类型无效。
SQL4912N
主变量数据长度超出范围。
SQL4913N
已经使用了主变量标记标识。
SQL4914N
主变量标记标识无效。
SQL4915N
已调用“sqlainit”函数。
SQL4916N
尚未调用“sqlainit”函数。
SQL4917N
选项数组中的元素 号码 无效。
SQL4918N
函数“sqlainit”的 term_option 参数无效。
SQL4919N
函数“sqlacmpl”的 task_array 参数太小。
SQL4920N
函数“sqlacmpl”的 token_id_array 参数太小。
SQL4921N
由于所有数据库分区上当前正在进行先前的时间点恢复,因此前滚命令失败。
SQL4930N
绑定或预编译选项或选项值 选项名 无效。
SQL4940N
子句 子句是不允许的或者是必需的。
SQL4941N
SQL 语句为空白或是空的。
SQL4942N
该语句在主变量 名称 中选择了不兼容的数据类型。
SQL4943W
INTO 子句中的主变量数与 SELECT 子句中的项数不相等。
SQL4944N
更新或插入值是 NULL,但对象列不能包含空值。
SQL4945N
参数标记的使用无效。
SQL4946N
未定义游标或语句名 名称。
SQL4947W
遇到了 INCLUDE SQLDA 语句,但被忽略。
SQL4950N
包含用户定义的 SQLDA 的复合 SQL 语句在此环境中不受支持。
SQL4951N
函数 名称 的 sqlda_id 参数无效。
SQL4952N
函数 名称 的 sqlvar_index 参数无效。
SQL4953N
函数 名称 的 call_type 参数无效。
SQL4954N
函数 名称 的 section_number 参数无效。
SQL4970N
在数据库分区 数据库分区列表 上,对数据库 名称 执行的前滚恢复操作无法到达指定的停止点(日志末尾或时间点)。前滚恢复操作在处理日志文件 日志文件 时停止。
SQL4971N
先前停止时对节点 节点号 上的数据库 名称 的前滚恢复失败。必须停止前滚恢复。
SQL4972N
不能将节点节点号上的日志数据块数据块移至数据库日志路径。
SQL4973N
不能完成对数据库 名称 的正向恢复,因为节点 节点列表 上的日志信息与目录节点上的相应记录不匹配。
SQL4974W
ROLLFORWARD DATABASE QUERY STATUS 命令遇到了 sqlcode sqlcode。
SQL4975W
成功地取消了前滚操作。必须在节点 节点列表 上复原数据库或选择的表空间。
SQL4976N
不能在非目录节点上提交此命令。
SQL4977N
已删除表导出目录 目录 无效。
SQL4978N
不能访问已删除的表。
SQL4979W
无法导出已删除的表数据。
SQL4980N
在数据库 名称 上的恢复在数据库分区 数据库分区号 上遇到损坏的日志文件 日志文件。
SQL4981W
从已删除的表中导出了数据,但是,包含一个或多个数据分区的表空间未包括在前滚列表中。这些数据分区的数据将不会存在于导出目录中。
SQL4990N
SQL 语句中最多支持 数字 个文字。每个文字的长度最多为 值 字节。
SQL4994N
由于用户中断请求使得预编译结束。
SQL4997N
授权标识无效。
SQL4998C
应用程序状态出错;数据库连接已丢失。
SQL4999N
发生“预编译器服务”或“运行时服务”错误。
SQL5001N
授权标识 无权更改数据库管理器配置文件。
SQL5005C
系统错误。
SQL5010N
到数据库管理器配置文件的路径名无效。
SQL5012N
主变量 主变量 不是一个精确的数字数据类型。
SQL5018N
数据库管理器配置文件中,关于与工作站的最大远程连接数的条目(numrc)不在有效范围内。
SQL5020N
数据库管理器配置文件中,关于工作站的节点名的条目(nname)无效。
SQL5021N
在数据库管理器配置文件中,索引重新创建参数(INDEXREC)的输入值无效。
SQL5022N
在数据库配置文件中,索引重新创建参数(INDEXREC)的输入值无效。
SQL5025C
数据库管理器配置文件不是当前的。
SQL5028N
sysadm_group 的值必须是实例所有者的主组。
SQL5030C
发行版号无效。
SQL5035N
数据库要求迁移至当前发行版。
SQL5040N
另一进程正使用 TCP/IP 服务器支持所必需的其中一个套接字地址。
SQL5042N
其中一个通信协议服务器支持进程未能启动。
SQL5043N
对一个或多个通信协议的支持未能成功启动。 但是,成功启动了核心数据库管理器功能。
SQL5047C
没有足够内存来执行此功能。
SQL5048N
数据库服务器的发行版级别不支持数据库客户机的发行版级别。
SQL5050C
数据库管理器配置文件的内容无效。
SQL5051N
不能以模式 模式名 创建由 限定符 限定的对象。
SQL5055C
数据库配置文件的内容无效。
SQL5060N
指定的配置参数标记无效。
SQL5061N
将指向结构 sqlfupd 的无效指针传送给了“配置服务”。
SQL5062N
在 sqlfupd 结构中,将无效指针传送给了“配置服务”。
SQL5065C
数据库管理器配置文件中的节点类型值无效。
SQL5066W
已截断标记 标记名称 的数据库配置参数值。
SQL5070N
配置命令中的 count 参数无效。它必须大于 0。
SQL5075N
配置实用程序被中断。
SQL5076W
更新成功完成。 NOTIFYLEVEL 的当前值将导致某些运行状况监视器通知不被发送至通知日志。
SQL5077N
此服务器发行版的“配置顾问程序”不支持参数 参数。支持的参数包括 支持的参数。
SQL5081N
数据库配置文件中,关于缓冲池大小的条目(buffpage)不在有效范围内。
SQL5083N
数据库配置文件中,关于初始日志文件大小的条目(logfile)不在有效范围内。
SQL5091N
在数据库配置文件中,关于一个日志文件扩展大小的条目(logext)不在有效范围内。
SQL5092N
在数据库配置文件中,关于允许的最大日志文件扩展数(logmaxext)的条目不在有效范围内。
SQL5093N
数据库管理器配置文件中用于表示代理进程堆大小的条目不在有效范围之内。
SQL5099N
由数据库配置参数 参数 指示的值 值 无效,原因码为 原因码。
SQL5100N
数据库管理器配置文件中,关于允许的并发数据库数的条目太大。
SQL5101N
数据库配置文件中定义日志文件参数(logprimary 和 logsecond)的条目不在有效范围内。
SQL5102E
产品的版本 版本名 不支持 DB2 工作负载管理器(WLM)。
SQL5103N
数据库配置文件中,关于缓冲池大小的条目(buffpage)对最大活动应用程序数(maxappls)而言太小。
SQL5112N
配置参数 参数 的值必须是 0 或 1。
SQL5113N
不能对 Unicode 数据库更新 ALT_COLLATE。
SQL5120N
不能同时修改旧的和新的日志参数。
SQL5121N
数据库配置文件中,关于配置选项的条目无效。
SQL5122N
对数据库的访问因与机器有关的检查而无效。
SQL5123N
因为访问日志控制文件时发生 I/O 错误,所以不能配置数据库 名称。
SQL5124N
DB2 未能更新或复位一个或多个分区上的数据库配置。原因码为 原因码。
SQL5126N
试图修改数据库管理器配置参数 参数,此参数对节点类型 节点类型代码 无效。
SQL5130N
为配置参数 参数 指定的值不在有效范围 起始范围 到 结束范围 内。
SQL5131N
为配置参数 参数 指定的值不在有效范围内。有效范围是“-1”,或从 起始范围 到 结束范围 之间。
SQL5132N
配置参数 参数 为 NULL 或太长。最大长度是 最大长度。
SQL5133N
配置参数 参数 的值 值 无效。有效值集合是 值列表。
SQL5134N
配置参数 tpname 包含无效字符。
SQL5135N
maxlocks 和 maxappls 配置参数的设置值未使用所有锁定列表空间。
SQL5136N
数据库管理器配置文件中,关于缺省数据库路径(dftdbpath)的条目无效。
SQL5137N
数据库管理器配置文件中,关于诊断目录路径的条目(diagpath)无效。
SQL5140N
数据库管理器配置参数“authentication”中的条目必须是下列 其中之一:SERVER、CLIENT、DCE、 KERBEROS、SERVER_ENCRYPT、 DCE_SERVER_ENCRYPT 或 KRB_SERVER_ENCRYPT。
SQL5141N
配置参数 avg_appls 超出范围。有效范围为从 1 到 maxappls 的值。
SQL5142N
配置参数 agentpri 不在有效范围内。
SQL5144W
参数更新已生效,但是只有将数据库配置参数 SELF_TUNING_MEM 设置为 ON 之后才会进行自动参数的自调整。
SQL5145W
参数更新已生效,但是取消激活了 AUTOMATIC 内存参数的调整,这是因为参数数目不足或者已将缓冲池设置为 AUTOMATIC。
SQL5146W
当 参数-2 为 参数-3 时,必须将 参数-1 设置为 参数-3。而 参数-1 已设置为 参数-3。
SQL5147N
如果 参数-2 为 AUTOMATIC,那么不能将 参数-1 设置为 MANUAL。
SQL5148W
已成功地将数据库配置参数 配置参数 更新为 AUTOMATIC,但是,只有将数据库管理器参数 SHEAPTHRES 设置为 0 之后,配置参数 的自调整才会生效。
SQL5150N
对配置参数 参数 指定的值小于允许的最小值 最小值。
SQL5151N
对配置参数 参数 指定的值小于允许的最小值 最小值 且不是 -1。
SQL5152N
对配置参数 参数 指定的值大于允许的最大值 最大值。
SQL5153N
不能完成更新,因为将违反下列关系:条件。
SQL5154N
不允许为“authentication” 和 参数 请求的配置值组合。原因码 = 原因码。
SQL5155W
更新成功完成。SORTHEAP 的当前值可能对性能产生负面影响。
SQL5156N
数据库管理器配置参数“trust_allclnts”的值必须是下列其中一项:NO、YES 或 DRDAONLY。
SQL5160N
当前不允许更新 参数。必须在所有应用程序都与数据库断开连接之后,才能应用对此参数进行的新更新。
SQL5161N
在执行下一个 DB2START 命令之前,不允许更新 参数。
SQL5180N
DB2 未能读取联合配置文件 文件名。
SQL5181N
联合配置文件 文件名 中的第 行号 行的格式无效。
SQL5182N
尚未设置必需的环境变量 变量名。
SQL5185N
不支持至 服务器类型 数据源的传递。
SQL5500N
DB2 未能读取供应商配置文件 文件名。
SQL5501N
供应商配置文件 文件名 中的第 行号 行的格式无效。
SQL6000N
QMF 数据 的 DB2 转换。
SQL6001N
“数据库管理器”没有异常结束。
SQL6002N
必须同时指定程序名和 CS:IP 参数。
SQL6003N
CS:IP 参数无效。
SQL6004N
函数 返回了意外的返回码 代码。
SQL6005N
读已下载的 QMF 文件时出错。
SQL6006N
写入输出文件时出错。
SQL6007N
不能将第 行 行第 列 列中的十进制数转换为 ASCII。
SQL6008N
命令中指定的文件不处于 QMF 数据格式。
SQL6009N
从 QMF 导出的文件包含宽度 宽度 太长的列 名称。最大列宽是 4000 字节。
SQL6010N
下载的 QMF 文件带有 255 个以上的数据列。
SQL6011N
不能处理列 名称(第 列号 列)的数据类型 号码(类型文本)。
SQL6012N
对命令指定了太多参数。
SQL6013N
主机文件名 主机文件名 太长,或未以字母字符开头。
SQL6014N
无效命令语法,冒号(“:”)应跟随着关键字。
SQL6015N
不识别关键字。
SQL6016N
System/370 文件名 名称 的操作数太多。
SQL6017N
Import 消息记录 名称 中可能包含更多信息。
SQL6018N
未指定 S/370 文件名。
SQL6019N
通信短会话标识 标识 太长或无效。
SQL6020N
指定了导入选项,但未同时提供数据库名称。
SQL6021N
数据导入成功。
SQL6022N
系统数据库目录不被所有节点共享。
SQL6023N
用户没有在表 名称 上运行“获取表分区信息”实用程序的权限。
SQL6024E
未在节点 节点号 上定义表或索引 名称。
SQL6025N
不能将在节点 节点-1 上备份的数据库复原到节点 节点-2 上。
SQL6026N
不能将目录节点为 节点-1 的数据库复原到目录节点为 节点-2 的数据库。
SQL6027N
数据库目录路径 路径 无效。
SQL6028N
因为在本地数据库目录中找不到数据库 数据库名称,所以目录数据库失败。
SQL6030N
START 或 STOP DATABASE MANAGER 失败。原因码为 原因码。
SQL6031N
在 db2nodes.cfg 文件的第 行号 行上出错。原因码为 原因码。
SQL6032W
在 总数 个节点上尝试了启动命令处理。成功启动了 已启动的数目 个节点。已启动了 已启动的数目 个节点。未能启动 未启动的数目 个节点。
SQL6033W
在 总数 个节点上尝试了停止命令处理。成功停止了 已停止的数目 个节点。已停止了 已停止的数目 个节点。未能停止 未停止的数目 个节点。
SQL6034W
节点 节点 未被任何数据库使用。
SQL6035W
数据库 数据库 正使用数据库分区 分区名称。
SQL6036N
START 或 STOP DATABASE MANAGER 命令已在处理之中。
SQL6037N
已达到 START 或 STOP DATABASE MANAGER 超时值。
SQL6038N
未定义分区键。
SQL6039N
分区列 列号 当前定义为不可空。
SQL6040C
没有 FCM 缓冲区里用。
SQL6041C
没有 FCM 连接条目可用。
SQL6042C
没有 FCM 消息锚可用。
SQL6043C
没有 FCM 请求块可用。
SQL6044N
数据类型值为 数据类型值 和长度为 长度 的字符串表示法 字符串 的语法不正确。
SQL6045N
不支持长度为 数据类型长度 的数据类型 数据类型值。
SQL6046N
指定的 DROP NODE 操作无效。
SQL6047N
因为表 名称 没有分区键,所以不能重新分发数据库分区组。
SQL6048N
处理 START 或 STOP DATABASE MANAGER 期间发生通信错误。
SQL6049N
在下列数据库分区上找不到 数据库名称 数据库的日志控制文件:数据库分区列表。
SQL6050N
访问下列数据库分区上的 数据库名称 数据库的日志控制文件时发生了 I/O 错误:数据库分区列表。
SQL6051N
未对节点 节点列表 上的前滚恢复配置数据库 名称。
SQL6052N
不能前滚数据库 名称,因为它在节点 节点列表 上不处于前滚暂挂状态。
SQL6053N
文件 文件 中存在错误。原因码 = 原因码。
SQL6054N
归档文件 名称 不是节点 节点号 上的数据库 名称 的有效日志文件。
SQL6055N
归档文件 名称 不属于节点 节点号 上的数据库 名称。
SQL6056N
数据库分区组无法重新分发。原因码 = 原因码。
SQL6057N
归档文件 名称 与已复原的数据库 名称 不相关,或者与节点 节点号 上先前已处理的日志文件不相关。
SQL6058N
由于检索节点 节点号 上的数据库 名称 的日志文件 名称 时发生错误 错误,前滚恢复停止。
SQL6059N
传送至“前滚”实用程序的时间点必须大于或等于 时间戳记,因为节点 节点列表 上的数据库 名称 包含晚于指定时间的信息。
SQL6061N
因为节点 节点列表 上丢失了日志文件,所以数据库 名称 上的前滚恢复不能到达指定的停止点(日志结束或时间点)。
SQL6062N
不能完成对数据库 名称 前滚恢复,因为在节点 节点列表 上的日志信息与目录节点上的相应记录不匹配。
SQL6063N
由于更改了日志文件大小,因此节点 节点列表 上停止了对数据库 名称 进行前滚恢复。
SQL6064N
数据重新分发期间,发生 SQL 错误 sqlcode。
SQL6065N
写入文件 文件 时出错。
SQL6067W
ROLLFORWARD DATABASE QUERY STATUS 命令遇到 sqlcode sqlcode。
SQL6068W
已成功取消前滚操作。必须在节点 节点列表 上复原数据库。
SQL6069N
不能在非目录节点上提交 ROLLFORWARD DATABASE 命令。
SQL6071N
因为已将新节点添加至系统,所以不能处理请求的操作。在可以执行该操作之前,系统必须停止并重新启动。
SQL6072N
因为指定的节点已是活动的,所以带有 RESTART 选项的 DB2START 不能继续。
SQL6073N
“添加数据库分区”操作失败。SQLCODE = sqlcode。
SQL6074N
因为当前正在执行“创建数据库”或“删除数据库”操作,所以“添加节点”操作失败。
SQL6075W
“启动数据库管理器”操作已成功地添加了数据库分区。直到所有数据库分区都停止并再次启动之后,该数据库分区才会处于活动状态。
SQL6076W
警告!此命令将除去此实例在节点上的所有数据库文件。在继续之前,通过运行 DROP NODE VERIFY 命令确保在此节点上没有用户数据。
SQL6077W
db2stop DROP NODENUM 过程成功结束,但未能除去所有文件。请参阅文件 文件 以了解详细信息。
SQL6078N
db2stop DROP NODENUM 过程未能更新数据库 数据库名称 的数据库信息。
SQL6079W
已成功取消 db2stop DROP NODENUM 命令。
SQL6080W
“启动数据库管理器”操作已成功添加新节点,但尚未在该节点上创建数据库分区。在所有节点停止并再次启动之前,该节点不活动。
SQL6081N
通信错误导致 DB2STOP FORCE 命令在此节点上超时。
SQL6100N
数据文件中的分区映射与数据库的分区映射不同。
SQL6101N
此数据文件包含节点 节点-1 的数据,但 Load 实用程序与节点 节点-2 相连。
SQL6102W
保留参数 名称 以供将来使用。其值应设置为 缺省值。
SQL6103C
发生了意外的实用程序错误。原因码 = 原因码。
SQL6104N
Load 实用程序不支持创建索引。
SQL6105W
Load 实用程序已完成处理。装入后执行至某时间点的“前滚” 将不成功。如果要求数据库必须是可恢复的,那么现在进行数据库备份。
SQL6106N
指定了文件类型修饰符“NOHEADER”,但在其中定义了表的节点组不是单节点节点组。
SQL6107N
数据文件中的分区键信息不正确。
SQL6108N
在数据文件头中定义的分区键数(数值-1)与对表定义的分区键数(数值-2)不匹配。
SQL6109N
实用程序期望分区列 列名-1,但找到分区列 列名-2。
SQL6110N
实用程序期望列 列名-1 的分区列类型为类型 列类型-1,但是数据文件将其列示为类型 列类型-2。
SQL6111N
不能在 newlogpath 指定的路径下创建子目录。
SQL6112N
不能执行请求的更改。结果配置参数设置值无效。原因码为 原因码。
SQL6500W
Load 命令中的 RESTARTCOUNT 可能导致某些问题。
SQL6501N
未在装入命令中给定数据库名称。
SQL6502N
未指定数据文件的路径名(参数:data_path)。 
SQL6504N
配置文件中的输出节点列表规范(参数:outputnodes)有错。
SQL6505N
在装入命令中的分区数据库分区列表规范(参数:PARTITIONING_DBPARTNUMS)中有错误。
SQL6506N
程序未能从系统目录表中抽取表 表名 的分区键信息。
SQL6507N
配置文件中的检查级别(参数:check_level)无效。
SQL6508N
程序未能为 ftp 进程创建输出管道。
SQL6509N
程序无法为分区代理程序创建输入管道。
SQL6510N
程序未能在分区 分区号 的本地非 NFS 空间上创建临时目录。
SQL6511N
装入程序无法为分区 分区号 上的分区代理程序创建输出。
SQL6512N
装入程序无法为分区 分区号 上的合并代理程序创建输入管道。
SQL6513N
装入程序无法为分区 分区号 上的装入代理程序创建输入管道。
SQL6514N
程序不能读取节点配置文件:节点配置文件。
SQL6515N
程序在配置文件中找不到 Load 命令。
SQL6516N
程序未能与数据库 数据库名称 相连。
SQL6517N
装入程序无法从系统目录表中抽取分区列表,表 表名 就是在该分区列表中定义的。
SQL6518N
记录长度(Load 命令中的 reclen)无效。
SQL6519N
配置文件中的方式(参数:mode)方式 无效。
SQL6520N
程序未能为进程创建输出管道,该进程生成分割文件的头信息。
SQL6521N
此程序的配置文件 配置文件 不存在。
SQL6522N
程序在 Load 命令中找到输入数据文件的路径名。
SQL6523N
在节点配置(db2nodes.cfg)文件中未定义分区数据库分区列表(参数:PARTITIONING_DBPARTNUMS)中的元素 分区号。
SQL6524N
输出分区列表(参数:OUTPUT_DBPARTNUMS)中的元素 分区号 不是在其中定义表的分区列表的成员。
SQL6525N
程序不能读取输入数据文件 文件名。
SQL6526N
程序不能写入当前工作目录 当前工作目录。
SQL6527N
将在其中收集统计信息数据的分区(参数:RUN_STAT_DBPARTNUM)不是输出分区列表的成员。
SQL6528N
Load 命令中未指定记录长度。
SQL6529N
在装入命令中未指定“无标题”选项(noheader)。
SQL6530N
一个分区键的数据类型是浮点型或双精度型。
SQL6531N
程序未能复位表空间停顿。
SQL6532N
不能将 Load 命令中的 savecount 设为非零。
SQL6533N
不能将 Load 命令中的 restartcount 设为非零。
SQL6534N
.netrc 文件 netrc-文件 中有错误。
SQL6535N
方式 PARTITION_ONLY 或 ANALYZE 无效。
SQL6536N
程序 程序名 未能打开文件 文件名 以进行读取。
SQL6537N
程序 程序名 未能打开文件 文件名 以进行写操作。
SQL6538N
装入程序无法读取分区文件 分区文件。
SQL6539N
在工作环境中,在 命令列表 中至少有一个命令找不到。
SQL6540N
在装入命令中指定的文件类型 文件类型 无效。
SQL6550N
未能打开分区映射文件 映射文件名 以进行写操作。
SQL6551N
试图写入该分区映射文件时出错。
SQL6552N
尝试打开临时配置文件 文件名 以进行写操作时出错。
SQL6553N
尝试写入临时配置文件 文件名 时出错。
SQL6554N
试图远程执行进程时出错。
SQL6555N
Load 实用程序遇到意外通信错误。
SQL6556W
在文件 文件名 的末尾检测到不完整的记录。
SQL6557N
未能检索缺省节点号。
SQL6558N
该实用程序未能确定当前工作目录和/或驱动器。
SQL6559N
向 AutoLoader 实用程序提供了无效的命令行选项。
SQL6560N
节点 节点号 在 db2nodes.cfg 文件中未出现,该节点是用于分区的执行节点。
SQL6561N
用于装入的目标节点 节点号 不出现在节点组中。
SQL6562N
实用程序不能检索该实例名。
SQL6563N
未能检索当前用户标识。
SQL6564N
提供的密码无效。
SQL6565I
用法:db2xxld [-config config-file] [-restart] [-terminate] [-help]
SQL6566N
AutoLoader 配置文件中丢失了 LOAD 命令。
SQL6567N
在 AutoLoader 配置文件中多次出现了 选项名 选项。
SQL6568I
Load 实用程序现在正在分派所有的 请求类型 请求。
SQL6569I
AutoLoader 现在正在发出所有分割请求。
SQL6570I
AutoLoader 正在等待所有分割程序完成。
SQL6571I
Load 实用程序正在等待所有操作完成。
SQL6572I
LOAD 操作已在分区 节点号 上开始。
SQL6573I
已完成远程执行在分区 节点号 上的分割实用程序,远程执行代码为 代码。
SQL6574I
实用程序已从源数据中读取了 MB-数 兆字节。
SQL6575I
实用程序已从用户数据中读取 MB-数 兆字节。
SQL6576N
AutoLoader 实用程序遇到线程错误。原因码为 原因码,返回码为 返回码。
SQL6577N
AutoLoader 实用程序不支持装入命令中的 ROWCOUNT 选项。
SQL6578N
无效 AutoLoader 选项。仅可对 SPLIT_AND_LOAD 或 LOAD_ONLY 方式指定 RESTART/TERMINATE 选项。
SQL6579N
在 AutoLoader 配置文件中的 LOAD 命令无效。AutoLoader 的 RESTART 和 TERMINATE 选项分别用于执行 LOAD RESTART 和 LOAD TERMINATE 操作。
SQL6580I
在阶段 重新启动阶段 中,LOAD 正在节点 节点号 上重新启动。
SQL6581I
Load 在节点 节点号 上不能重新启动。
SQL6582I
不需要在节点 节点号 上重新启动 LOAD。
SQL6583N
分区键定义与分区数据库装入方式 装入方式 不兼容
posted @ 2013-07-16 20:03 何杨 阅读(3563) | 评论 (0)编辑 收藏

在命令行窗口输入db2cmd,再执行命令。
posted @ 2013-07-16 10:00 何杨 阅读(770) | 评论 (0)编辑 收藏

系统变成Win7后,因需要安装DB2 97版,但以前一蹴而就的过程却在90%处中断了,错误是DB29501E 如下图所示:


多次重试无效,同事也没有遇到过同样的错误,一筹莫展中,只好搁置先做别的。
在安装Install manager后,再试DB2重装,居然通过了。

估计是它们共享一个gre的原因,DB2自带的在Win7中运行不好,但Install Manager的可以。故先装Installl Manager再装DB2就OK了。
也许还有别的原因,但目前只能这样认为。

2013年7月16日9:35:07
posted @ 2013-07-16 09:35 何杨 阅读(1063) | 评论 (0)编辑 收藏

对此只要在服务里启动DB2相关服务即可。

参考:http://hi.baidu.com/cf2928/item/70e61edf9539d99d270ae758

我在控制中心新建个数据库可是总出现这个样的问题:SQL4414N  “DB2 管理服务器”处于不活动状态。 


解释: 
除非“DB2 管理服务器”是活动的,否则不能处理请求。 
用户响应: 
通过发出命令 DB2ADMIN START 启动“DB2
管理服务器”,并重新发出请求。 
DB2主要的那2 个服务,
DB2DAS-DB2DAS00,DB2-DB2-0 主要是这2个服务,db2admin start这个是启动
SQL4409W  “DB2 管理服务器”,启动了DB2DAS-DB2DAS00服务
 创建新库和表了
posted @ 2013-07-15 21:25 何杨 阅读(563) | 评论 (0)编辑 收藏

WIN7下装DB2,启动任务中心、控制中心报DB2JAVIT:RC=9505。

解决方案:进入(计算机—>管理—>本地用户和组用户)把用户加入到DB2ADMNS或DB2USERS,重启后,即可解决。


参考:http://blog.163.com/dream11867@126/blog/static/2695265120121893417152/

posted @ 2013-07-15 21:13 何杨 阅读(1837) | 评论 (1)编辑 收藏

有人说会自动降频1078使用,试了,大忽悠,无效。
posted @ 2013-07-15 16:56 何杨 阅读(700) | 评论 (0)编辑 收藏

如图,其他语言系统自己参照:

posted @ 2013-07-15 16:54 何杨 阅读(416) | 评论 (0)编辑 收藏

    FROM:

http://blog.csdn.net/pangdingshan/article/details/7198760



   系统环境:windows 7 旗舰版

      软件版本:IBM DB2数据库(DB2_ESE_97_Win_x86)

      准备工作:关闭防火墙及杀软等安全防护软件

     本文是事后整理的,可以在循序上有些乱,有些步奏也是省略的,省略的都是选择默认选项

1.   运行安装目录下的  setup.exe 程序,点击“下一步”

2.    选择“我接受许可证协议中的全部条款”,点击“下一步”

3.  根据自己需求选择安装方式,我选择“典型安装”,点击“下一步”

4.   选择“在此计算机上安装DB2Enterprise Server Edition ” ,点击“下一步”

5.    更改安装路径,点击“下一步”

6.    默认选项,点击“下一步”

 

7.    设置密码,点击“下一步”

 

8. 不勾选“设置DB2服务器以发送通知”,点击“下一步”

9.    勾选“启动操作系统安全性”,点击“下一步”

10.   勾选“准备DB2工具目录”,点击“下一步”

 

11.  点击“下一步”,进行安装

  安装成功后会有提示



我安装的时候出现以下问题:
posted @ 2013-07-14 00:11 何杨 阅读(316) | 评论 (0)编辑 收藏

http://www.cnblogs.com/mingmingruyuedlut/archive/2011/11/04/2235630.html


1:

Internet Information Services 7.5

Error Summary

HTTP Error 500.19 - Internal Server Error

The requested page cannot be accessed because the related configuration data for the page is invalid.

Detailed Error Information
Module IIS Web Core
Notification Unknown
Handler Not yet determined
Error Code 0x80070005
Config Error Cannot read configuration file due to insufficient permissions
Config File \\?\C:\Users\EricSun\Documents\Visual Studio 2010\WebSites\SSOAuthWebSite1\web.config
Requested URL http://10.2.5.153:10001/
Physical Path  
Logon Method Not yet determined
Logon User Not yet determined
Config Source
 -1:     0:  
Links and More InformationThis error occurs when there is a problem reading the configuration file for the Web server or Web application. In some cases, the event logs may contain more information about what caused this error.

View more information »

 

Cause:1) 没有向iis中注册.net framework(引起的原因之一:先安装了.net framework,后安装的iis)

    2) 没有对IIS中所配置的site有足够的操作权限(Modify权限)

Solution:

    1) 到C:\Windows\Microsoft.NET\Framework64\v2.0.50727下,

      用命令向iis中重新注册一下.net framework:aspnet_regiis -i

    2) IIS Manager --> Sites --> 相应的site --> 点击右键 --> Edit Permissions --> Security --> Group or user names --> Edit --> Add --> 添加赋予Full Control权限(实质上带有Modify的权限就可以)的Everyone用户

 


2:

Server Error in '/' Application.


Configuration Error

Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

Parser Error Message: Unrecognized attribute 'targetFramework'. Note that attribute names are case-sensitive.

Source Error:

Line 9:  	</connectionStrings> Line 10: 	<system.web> Line 11: 		<compilation debug="true" targetFramework="4.0"/> Line 12: 		<authentication mode="Forms"> Line 13: 			<forms loginUrl="~/Account/Login.aspx" timeout="2880"/>


Source File: C:\Users\EricSun\Documents\Visual Studio 2010\WebSites\SSOAuthWebSite1\web.config    Line: 11


Version Information: Microsoft .NET Framework Version:2.0.50727.4963; ASP.NET Version:2.0.50727.4955

 

Cause:当前程序所运行的.NET Framework版本与IIS中相应site所设置的.NET Framework版本不相同

Solution:启动IIS Manager --> Application Pools --> 选择相应的Name(site) --> 点击右键 --> Advanced Settings --> (General).NET Framwork Version --> 由2.0更改到4.0即可

 

3:

Compilation Error

Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

Compiler Error Message: CS0016: Could not write to output file 'c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\2ae25944\4afe0277\App_global.asax.ke894tgr.dll' -- 'Access is denied. '

Source Error:

 
[No relevant source lines]


Source File:    Line: 0


Show Detailed Compiler Output:

c:\windows\system32\inetsrv> "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe" /t:library /utf8output /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Web.Extensions\v4.0_4.0.0.0__31bf3856ad364e35\System.Web.Extensions.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Web.Services\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.Services.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Data.DataSetExtensions\v4.0_4.0.0.0__b77a5c561934e089\System.Data.DataSetExtensions.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ServiceModel.Web\v4.0_4.0.0.0__31bf3856ad364e35\System.ServiceModel.Web.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ServiceModel\v4.0_4.0.0.0__b77a5c561934e089\System.ServiceModel.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Activities\v4.0_4.0.0.0__31bf3856ad364e35\System.Activities.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ServiceModel.Activation\v4.0_4.0.0.0__31bf3856ad364e35\System.ServiceModel.Activation.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Drawing\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Drawing.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ServiceModel.Activities\v4.0_4.0.0.0__31bf3856ad364e35\System.ServiceModel.Activities.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Web.ApplicationServices\v4.0_4.0.0.0__31bf3856ad364e35\System.Web.ApplicationServices.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_64\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ComponentModel.DataAnnotations\v4.0_4.0.0.0__31bf3856ad364e35\System.ComponentModel.DataAnnotations.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.WorkflowServices\v4.0_4.0.0.0__31bf3856ad364e35\System.WorkflowServices.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_64\System.EnterpriseServices\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.EnterpriseServices.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_64\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.Serialization\v4.0_4.0.0.0__b77a5c561934e089\System.Runtime.Serialization.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.IdentityModel\v4.0_4.0.0.0__b77a5c561934e089\System.IdentityModel.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll" /R:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Web.DynamicData\v4.0_4.0.0.0__31bf3856ad364e35\System.Web.DynamicData.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.CSharp\v4.0_4.0.0.0__b03f5f7f11d50a3a\Microsoft.CSharp.dll" /R:"C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll" /out:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\2ae25944\4afe0277\App_global.asax.ke894tgr.dll" /debug- /optimize+ /w:4 /nowarn:1659;1699;1701 /warnaserror-  "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\2ae25944\4afe0277\App_global.asax.ke894tgr.0.cs" "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\2ae25944\4afe0277\App_global.asax.ke894tgr.1.cs"   Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1 Copyright (C) Microsoft Corporation. All rights reserved.  error CS0016: Could not write to output file 'c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\2ae25944\4afe0277\App_global.asax.ke894tgr.dll' -- 'Access is denied. ' 




Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.1

 

Cause:对Windows下的temp文件夹缺少操作权限

Solution: 将Windows下的temp文件夹 --> properties --> security --> create owner --> add --> 添加赋予Full Control权限的Everyone用户

 

4:

Server Error in '/' Application.


Login failed for user 'IIS APPPOOL\SSO1'.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Data.SqlClient.SqlException: Login failed for user 'IIS APPPOOL\SSO1'.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.


Stack Trace:

[SqlException (0x80131904): Login failed for user 'IIS APPPOOL\SSO1'.]    System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) +6333696    System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() +412    System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) +1363    System.Data.SqlClient.SqlInternalConnectionTds.CompleteLogin(Boolean enlistOK) +53    System.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, Boolean redirectedUserInstance, SqlConnection owningObject, SqlConnectionString connectionOptions, TimeoutTimer timeout) +6348638    System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(SqlConnection owningObject, TimeoutTimer timeout, SqlConnectionString connectionOptions, String newPassword, Boolean redirectedUserInstance) +6348553    System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, Object providerInfo, String newPassword, SqlConnection owningObject, Boolean redirectedUserInstance) +352    System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection) +831    System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnection owningConnection, DbConnectionPool pool, DbConnectionOptions options) +49    System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject) +6350358    System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject) +78    System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject) +1938    System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection) +89    System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) +6353246    System.Data.SqlClient.SqlConnection.Open() +300    System.Web.DataAccess.SqlConnectionHolder.Open(HttpContext context, Boolean revertImpersonate) +150    System.Web.DataAccess.SqlConnectionHelper.GetConnection(String connectionString, Boolean revertImpersonation) +4679471    System.Web.Security.SqlMembershipProvider.GetPasswordWithFormat(String username, Boolean updateLastLoginActivityDate, Int32& status, String& password, Int32& passwordFormat, String& passwordSalt, Int32& failedPasswordAttemptCount, Int32& failedPasswordAnswerAttemptCount, Boolean& isApproved, DateTime& lastLoginDate, DateTime& lastActivityDate) +3720151    System.Web.Security.SqlMembershipProvider.CheckPassword(String username, String password, Boolean updateLastLoginActivityDate, Boolean failIfNotApproved, String& salt, Int32& passwordFormat) +189    System.Web.Security.SqlMembershipProvider.ValidateUser(String username, String password) +202    System.Web.UI.WebControls.Login.AuthenticateUsingMembershipProvider(AuthenticateEventArgs e) +225    System.Web.UI.WebControls.Login.AttemptLogin() +166    System.Web.UI.WebControls.Login.OnBubbleEvent(Object source, EventArgs e) +93    System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +52    System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3707 



Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.1

 

Cause:IIS中的Application pool中相应site的Identity类型错误

Solution: IIS Manager --> Application Pools --> 找到相应的site --> 左键选择Advanced Settings --> 将Process Model中的Identity类型换成LocalSystem

此问题(4)的解决方法可以详 见:http://blogs.microsoft.co.il/blogs/shlomo/archive/2009/11/09/system- data-sqlclient-sqlexception-login-failed-for-user-iis-apppool-defaultapppool.aspx

 

5:

 

Server Error in '/' Application.
--------------------------------------------------------------------------------

 

Could not load type 'System.ServiceModel.Activation.HttpModule' from assembly 'System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

 

Exception Details: System.TypeLoadException: Could not load type 'System.ServiceModel.Activation.HttpModule' from assembly 'System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

 

Source Error:

 

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

 

Stack Trace:

 


[TypeLoadException: Could not load type 'System.ServiceModel.Activation.HttpModule' from assembly 'System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.]
System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMarkHandle stackMark, Boolean loadTypeFromPartialName, ObjectHandleOnStack type) +0
System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, Boolean loadTypeFromPartialName) +314
System.Type.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase) +95
System.Web.Compilation.BuildManager.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase) +124
System.Web.Configuration.ConfigUtil.GetType(String typeName, String propertyName, ConfigurationElement configElement, XmlNode node, Boolean checkAptcaBit, Boolean ignoreCase) +76

 

[ConfigurationErrorsException: Could not load type 'System.ServiceModel.Activation.HttpModule' from assembly 'System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.]
System.Web.Configuration.ConfigUtil.GetType(String typeName, String propertyName, ConfigurationElement configElement, XmlNode node, Boolean checkAptcaBit, Boolean ignoreCase) +11355388
System.Web.Configuration.Common.ModulesEntry.SecureGetType(String typeName, String propertyName, ConfigurationElement configElement) +69
System.Web.Configuration.Common.ModulesEntry..ctor(String name, String typeName, String propertyName, ConfigurationElement configElement) +62
System.Web.HttpApplication.BuildIntegratedModuleCollection(List`1 moduleList) +301
System.Web.HttpApplication.GetModuleCollection(IntPtr appContext) +1332
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleReflectionUtil.GetIntegratedModuleCollection(HttpApplication target, IntPtr appContext) +34
Microsoft.Web.Infrastructure.DynamicModuleHelper.CriticalStatics.Init(HttpApplication context) +264
System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) +546
System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) +325
System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) +407
System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext) +375

 

[HttpException (0x80004005): Could not load type 'System.ServiceModel.Activation.HttpModule' from assembly 'System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.]
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +11524352
System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +141
System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +4782309

 

 

 


--------------------------------------------------------------------------------
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.1

 

 

 

Cause:.Net Framework4先安装,IIS后安装,导致.Net Framework4.0没有注册到IIS中

 

Solution: 在Windows的文件夹里找到一个安装程序,在CMD里执行,具体如下:

      C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis.exe -iru
      显示如下:
      Start installing ASP.NET (4.0.30319).
      ..........
      Finished installing ASP.NET (4.0.30319).
      这样就可以了。
 
此问题的更详细的原因请看: http://msdn.microsoft.com/zh-cn/library/k6h9cz8h.aspx
posted @ 2013-07-12 13:22 何杨 阅读(1475) | 评论 (0)编辑 收藏

char* HcC21PrintPres::getStringFromDouble(double d){
    char  sbuf2[256];

    sprintf(sbuf2,"%.3f",d);// 保留位数自己可调

    for(;sbuf2[strlen(sbuf2) - 1] == '0';){
        sbuf2[strlen(sbuf2) - 1] = '\0';
        if(sbuf2[strlen(sbuf2) - 1] == '.'){
            sbuf2[strlen(sbuf2) - 1] = '\0';
            break;
        }
    }

    return sbuf2;
}
这种写法还是挺有意思的.
posted @ 2013-07-11 10:33 何杨 阅读(320) | 评论 (0)编辑 收藏

http://blog.csdn.net/masikkk/article/details/5634886

在将各种类型的数据构造成字符串时,sprintf 的强大功能很少会让你失望。由于sprintf 跟printf 在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,后者则直接在命令行上输出。这也导致sprintf 比printf 有用得多。
  sprintf 是个变参函数,定义如下:
  int sprintf( char *buffer, const char *format [, argument] ... );
  除了前两个参数类型固定外,后面可以接任意多个参数。而它的精华,显然就在第二个参数:

  (1)格式化字符串上。

  printf 和sprintf 都使用格式化字符串来指定串的格式,在格式串内部使用一些以“%”开头的格式说明符(format specifications)来占据一个位置,在后边的变参列表中提供相应的变量,最终函数就会用相应位置的变量来替代那个说明符,产生一个调用者想要 的字符串。
  格式化数字字符串
  sprintf 最常见的应用之一莫过于把整数打印到字符串中,所以,spritnf 在大多数场合可以替代itoa。
  如:
  //把整数123 打印成一个字符串保存在s 中。
  sprintf(s, "%d", 123); //产生"123"
  可以指定宽度,不足的左边补空格:
  sprintf(s, "%8d%8d", 123, 4567); //产生:" 123 4567"
  当然也可以左对齐:
  sprintf(s, "%-8d%8d", 123, 4567); //产生:"123 4567"
  也可以按照16 进制打印:
  sprintf(s, "%8x", 4567); //小写16 进制,宽度占8 个位置,右对齐
  sprintf(s, "%-8X", 4568); //大写16 进制,宽度占8 个位置,左对齐
  这样,一个整数的16 进制字符串就很容易得到,但我们在打印16 进制内容时,通常想要一种左边补0 的等宽格式,那该怎么做呢?很简单,在表示宽度的数字前面加个0 就可以了。
  sprintf(s, "%08X", 4567); //产生:"000011D7"
  上面以”%d”进行的10 进制打印同样也可以使用这种左边补0 的方式。
  这里要注意一个符号扩展的问题:比如,假如我们想打印短整数(short)-1 的内存16 进制表示形式,在Win32 平台上,一个short 型占2 个字节,所以我们自然希望用4 个16 进制数字来打印它:
  short si = -1;
  sprintf(s, "%04X", si);
  产生“FFFFFFFF”,怎么回事?因为spritnf 是个变参函数,除了前面两个参数之外,后面的参数都不是类型安全的,函数更没有办法仅仅通过一个“%X”就能得知当初函数调用前参数压栈时被压进来的到底 是个4 字节的整数还是个2 字节的短整数,所以采取了统一4 字节的处理方式,导致参数压栈时做了符号扩展,扩展成了32 位的整数-1,打印时4 个位置不够了,就把32 位整数-1 的8 位16 进制都打印出来了。
  如果你想看si 的本来面目,那么就应该让编译器做0 扩展而不是符号扩展(扩展时二进制左边补0 而不是补符号位):
  sprintf(s, "%04X", (unsigned short)si);
  就可以了。或者:
  unsigned short si = -1;
  sprintf(s, "%04X", si);
  sprintf 和printf 还可以按8 进制打印整数字符串,使用”%o”。注意8 进制和16 进制都不会打
  印出负数,都是无符号的,实际上也就是变量的内部编码的直接的16 进制或8 进制表示。
  控制浮点数打印格式
  浮点数的打印和格式控制是sprintf 的又一大常用功能,浮点数使用格式符”%f”控制,默认保
  留小数点后6 位数字,比如:
  sprintf(s, "%f", 3.1415926); //产生"3.141593"
  但有时我们希望自己控制打印的宽度和小数位数,这时就应该使用:”%m.nf”格式,其中m 表
  示打印的宽度,n 表示小数点后的位数。比如:
  sprintf(s, "%10.3f", 3.1415626); //产生:" 3.142"
  sprintf(s, "%-10.3f", 3.1415626); //产生:"3.142 "
  sprintf(s, "%.3f", 3.1415626); //不指定总宽度,产生:"3.142"
  注意一个问题,你猜
  int i = 100;
  sprintf(s, "%.2f", i);
  会打出什么东东来?“100.00”?对吗?自己试试就知道了,同时也试试下面这个:
  sprintf(s, "%.2f", (double)i);
  第一个打出来的肯定不是正确结果,原因跟前面提到的一样,参数压栈时调用者并不知道跟i相对应的格式控制符是个”%f”。而函数执行时函数本身则并不 知道当年被压入栈里的是个整数,于是可怜的保存整数i 的那4 个字节就被不由分说地强行作为浮点数格式来解释了,整个乱套了。不过,如果有人有兴趣使用手工编码一个浮点数,那么倒可以使用这种方法来检验一下你手工编 排的结果是否正确。
  

    (2)字符/Ascii 码对照

  我们知道,在C/C++语言中,char 也是一种普通的scalable 类型,除了字长之外,它与short,
  int,long 这些类型没有本质区别,只不过被大家习惯用来表示字符和字符串而已。(或许当年该把
  这个类型叫做“byte”,然后现在就可以根据实际情况,使用byte 或short 来把char 通过typedef 定义出来,这样更合适些)于是,使用”%d”或者”%x”打印一个字符,便能得出它的10 进制或16 进制的ASCII 码;反过来,使用”%c”打印一个整数,便可以看到它所对应的ASCII 字符。以下程序段把所有可见字符的ASCII 码对照表打印到屏幕上(这里采用printf,注意”#”与”%X”合用时自动为16 进制数增加”0X”前缀):
  for(int i = 32; i < 127; i++) {
  printf("[ %c ]: %3d 0x%#04X/n", i, i, i);
  }


  (3)连接字符串

  sprintf 的格式控制串中既然可以插入各种东西,并最终把它们“连成一串”,自然也就能够连
  接字符串,从而在许多场合可以替代strcat,但sprintf 能够一次连接多个字符串(自然也可以同时
  在它们中间插入别的内容,总之非常灵活)。比如:
  char* who = "I";
  char* whom = "CSDN";
  sprintf(s, "%s love %s.", who, whom); //产生:"I love CSDN. "
  strcat 只能连接字符串(一段以’’结尾的字符数组或叫做字符缓冲,null-terminated-string),但有时我们有两段字符缓冲区,他们并不是以 ’’结尾。比如许多从第三方库函数中返回的字符数组,从硬件或者网络传输中读进来的字符流,它们未必每一段字符序列后面都有个相应的’’来结尾。如果直接 连接,不管是sprintf 还是strcat 肯定会导致非法内存操作,而strncat 也至少要求第一个参数是个null-terminated-string,那该怎么办呢?我们自然会想起前面介绍打印整数和浮点数时可以指定宽度,字符串 也一样的。比如:
  char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
  char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', 'N'};
  如果:
  sprintf(s, "%s%s", a1, a2); //Don't do that!
  十有八九要出问题了。是否可以改成:
  sprintf(s, "%7s%7s", a1, a2);
  也没好到哪儿去,正确的应该是:
  sprintf(s, "%.7s%.7s", a1, a2);//产生:"ABCDEFGHIJKLMN"
  这可以类比打印浮点数的”%m.nf”,在”%m.ns”中,m 表示占用宽度(字符串长度不足时补空格,超出了则按照实际宽度打印),n 才表示从相应的字符串中最多取用的字符数。通常在打印字符串时m 没什么大用,还是点号后面的n 用的多。自然,也可以前后都只取部分字符:
  sprintf(s, "%.6s%.5s", a1, a2);//产生:"ABCDEFHIJKL"
  在许多时候,我们或许还希望这些格式控制符中用以指定长度信息的数字是动态的,而不是静态指定的,因为许多时候,程序要到运行时才会清楚到底需要取字 符数组中的几个字符,这种动态的宽度/精度设置功能在sprintf 的实现中也被考虑到了,sprintf 采用”*”来占用一个本来需要一个指定宽度或精度的常数数字的位置,同样,而实际的宽度或精度就可以和其它被打印的变量一样被提供出来,于是,上面的例子 可以变成:
  sprintf(s, "%.*s%.*s", 7, a1, 7, a2);
  或者:
  sprintf(s, "%.*s%.*s", sizeof(a1), a1, sizeof(a2), a2);
  实际上,前面介绍的打印字符、整数、浮点数等都可以动态指定那些常量值,比如:
  sprintf(s, "%-*d", 4, 'A'); //产生"65 "
  sprintf(s, "%#0*X", 8, 128); //产生"0X000080","#"产生0X
  sprintf(s, "%*.*f", 10, 2, 3.1415926); //产生" 3.14"


  (4)打印地址信息

  有时调试程序时,我们可能想查看某些变量或者成员的地址,由于地址或者指针也不过是个32 位的数,你完全可以使用打印无符号整数的”%u”把他们打印出来:
  sprintf(s, "%u", &i);
  不过通常人们还是喜欢使用16 进制而不是10 进制来显示一个地址:
  sprintf(s, "%08X", &i);
  然而,这些都是间接的方法,对于地址打印,sprintf 提供了专门的”%p”:
  sprintf(s, "%p", &i);
  我觉得它实际上就相当于:
  sprintf(s, "%0*x", 2 * sizeof(void *), &i);


  (5)利用sprintf 的返回值

  较少有人注意printf/sprintf 函数的返回值,但有时它却是有用的,spritnf 返回了本次函数调用
  最终打印到字符缓冲区中的字符数目。也就是说每当一次sprinf 调用结束以后,你无须再调用一次
  strlen 便已经知道了结果字符串的长度。如:
  int len = sprintf(s, "%d", i);
  对于正整数来说,len 便等于整数i 的10 进制位数。
  下面的是个完整的例子,产生10 个[0, 100)之间的随机数,并将他们打印到一个字符数组s 中,
  以逗号分隔开。
  #include
  #include
  #include
  int main() {
  srand(time(0));
  char s[64];
  int offset = 0;
  for(int i = 0; i < 10; i++) {
  offset += sprintf(s + offset, "%d,", rand() % 100);
  }
  s[offset - 1] = '/n';//将最后一个逗号换成换行符。
  printf(s);
  return 0;
  }
  设想当你从数据库中取出一条记录,然后希望把他们的各个字段按照某种规则连接成一个字
  符串时,就可以使用这种方法,从理论上讲,他应该比不断的strcat 效率高,因为strcat 每次调用
  都需要先找到最后的那个’’的位置,而在上面给出的例子中,我们每次都利用sprintf 返回值把这
  个位置直接记下来了。
  使用sprintf 的常见问题
  sprintf 是个变参函数,使用时经常出问题,而且只要出问题通常就是能导致程序崩溃的内存访
  问错误,但好在由sprintf 误用导致的问题虽然严重,却很容易找出,无非就是那么几种情况,通
  常用眼睛再把出错的代码多看几眼就看出来了。
  ?? 缓冲区溢出
  第一个参数的长度太短了,没的说,给个大点的地方吧。当然也可能是后面的参数的问
  题,建议变参对应一定要细心,而打印字符串时,尽量使用”%.ns”的形式指定最大字符数。
  ?? 忘记了第一个参数
  低级得不能再低级问题,用printf 用得太惯了。//偶就常犯。:。(
  ?? 变参对应出问题
  通常是忘记了提供对应某个格式符的变参,导致以后的参数统统错位,检查检查吧。尤
  其是对应”*”的那些参数,都提供了吗?不要把一个整数对应一个”%s”,编译器会觉得你
  欺她太甚了(编译器是obj 和exe 的妈妈,应该是个女的,:P)。
  strftime
  sprnitf 还有个不错的表妹:strftime,专门用于格式化时间字符串的,用法跟她表哥很像,也
  是一大堆格式控制符,只是毕竟小姑娘家心细,她还要调用者指定缓冲区的最大长度,可能是为
  了在出现问题时可以推卸责任吧。这里举个例子:
  time_t t = time(0);
  //产生"YYYY-MM-DD hh:mm:ss"格式的字符串。
  char s[32];
  strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", localtime(&t));
  sprintf 在MFC 中也能找到他的知音:CString::Format,strftime 在MFC 中自然也有她的同道:
  CTime::Format,这一对由于从面向对象哪里得到了赞助,用以写出的代码更觉优雅。

 

 

 

 

sprintf 用法总结(2009-08-25 09:36:24)标签:it   分类:C++
  sprintf,将各种类型的数据够造成字符串。

  sprintf是个变参函数,int sprintf(char *buffer,const char *format[,argument]...);除了前两个参数类型固定外,后面可以接任意多个参数,而它的精华,则在第二个参数:格式化字符串上。

  printf和sprintf都使用格式化字符串来指定串的格式,在格式串内部使 用一些以“%”开头的格式说明符(format specification)来占据一个位置,在后边的变参列表中提供相应的变量,最终函数就会用相应位置的变量来替代那个说明符,产生一个调用者想要的 字符串。

 一、格式化数字字符串

  sprintf最常见的应用之一莫过于把整数打印到字符串中,所以sprintf在大多数场合可以替代itoa.

    %-8d 代表宽度八位,左对齐(没有负号为右对齐),整数的十进制

  %x小写16进制  %X大写16进制

    符号扩展问题:参数压栈默认四字节,即8位16进制。应该让编译器做0扩展而不是符号扩展。

  如  sprintf(s,"%04X",(unsigned short)si);

    %o 8进制格式化字符串。

  控制浮点数打印格式,使用格式符"%f"控制,默认保留小数点后6位数字。

  %m.nf m表示打印的宽度,n表示小数点后的位数

  sprintf(s,"%m.nf",i)其中i 必须为浮点类型的

二、字符/ASCII码对照

  %c打印一个整数,可以看到整数所对应的ASCII值

  for(int i=32 ;i<127;i++)
  {
    printf("[%c]:%3d 0x%#04X/n",i,i,i);
  }

 #与%X合用时自动为16进制数增加“0X”前缀。

三、连接字符串

 可以在许多场合替代strcat,sprintf能够一次连接多个字符串。

 %s可以参照浮点数控制的%m.n m表示宽度,n表示从相应的字符串中最多取用的字符数,通常m没什么用。

  对于动态的,可以采用sprintf(s,"%.*s%.*s",7,a1,7,a2)或sprintf(s,"%.*s%.*s",sizeof(a1),a1,sizeof(a2),a2);  

四、打印地址信息

有时调试程序时,我们可能想查看某些变量或者成员的地址,由于地址或者指针也不过是个32 位的数,你完全可以使用打印无符号整数的”%u”把他们打印出来:
sprintf(s, "%u", &i);
不过通常人们还是喜欢使用16 进制而不是10 进制来显示一个地址:
sprintf(s, "%08X", &i);
然而,这些都是间接的方法,对于地址打印,sprintf 提供了专门的”%p”:
sprintf(s, "%p", &i);
我觉得它实际上就相当于:
sprintf(s, "%0*x", 2 * sizeof(void *), &i);

五、返回值

返回了本次函数调用最终打印到字符缓冲区中的字符数目。
六、strftime

专门用于格式化时间字符串。需调用者指定缓冲区的最大长度。

strftime(s,sizeof(s),"%Y-%m-%d %H:%M:%S",localtime(&t));
posted @ 2013-07-10 15:31 何杨 阅读(274) | 评论 (0)编辑 收藏

http://sddhn.blog.163.com/blog/static/1281877920129191574926/


在DB2中从客户端访问服务器端的数据库时,不能直接用connect命令,而必须先建立通信node,再在node的基础上建立数据库连接。在命令行的具体操作如下:
->db2 catalog tcpip node ${nodeName} remote ${serverName} server ${portNumber} 
->db2 catalog db ${dbName} as ${dbAlias} at node ${nodeName} 
->db2 connect to ${dbAlias} user ${userName} using ${passWord}
->db2 terminate
说明:
${nodeName}:任意起的一个结点名,注意长度限制
${serverName}:远程数据库所在服务器名称或IP地址
${portNumber} :远程数据库端口号
${dbName}:远程数据库的名字
${dbAlias}:编目到本地后的数据库别名
${userName}:连接数据库用户名
${passWord}:连接数据库密码
其他相关一些重要的DB2命令
  1. 查看本地节点目录
  命令窗口中输入:db2 list node directory
  2. 编目一个TCP/IP节点
   命令窗口:db2 catalog tcpip node <node_name> remote <hostname|ip_address> server <svcname|port_number> ostype <OS2|AIX|WIN95|NT|HPUX|SUN|MVS|OS400|VM|VSE|SCO|SGI|LINUX|DYNIX>

Eg: Open a command shell and input the commands below:

db2 catalog tcpip node koubeSvr remote 9.119.100.222 server 50000

db2 catalog db KOUBE23 as KOUBE23 at node koubeSvr

  3. 取消节点编目
  db2 uncatalog node <node_name>
  4. 查看系统数据库目录
  db2 list database directory
  5. 查看本地数据库目录
  db2 list database directory on <盘符>
  在本地数据库目录中有而系统数据库目录中没有的数据库不能访问,可以在控制中心中选中<数据库>右键单击选择添加,然后输入需要添加的数据库名称或者点击刷新按钮选择数据库,加入数据库后即可以访问。
  6. 编目数据库
  db2 catalog database <db_name> as <db_alias> at node <node_name>
  7. 取消数据库编目
  db2 uncatalog database <db_name>
  8. 测试远程数据库的连接
  db2 connect to <db_alias> user <user_id> using <password>
posted @ 2013-07-08 15:23 何杨 阅读(374) | 评论 (0)编辑 收藏

工具:
这个工具用于将ASM文件编译.
http://www.blogjava.net/Files/heyang/nasm-2.07-installer.rar

建议使用Notepad++书写asm,然后用命令行编译:
>nasm a.asm -o a.com

这个工具能将BIN写入软盘扇区:
http://www.blogjava.net/Files/heyang/FloppyWriter.zip

以下是一个例程:
%define _BOOT_DEBUG_
%ifdef _BOOT_DEBUG_
    org 0100h
%else
    org 07c00h
%endif
    mov ax,cs
    mov ds,ax
    mov es,ax
    call DispStr;
    jmp $;
DispStr:
    mov ax,BootMessage
    mov bp,ax
    mov cx,
32
    mov ax,01301h
    mov bx,000ch
    mov dl,
0
    
int 10h
    ret
BootMessage:    db 
"Hello,OS world!XXXXXX is here."
times 
510-($-$$) db 0;
dw 
0xaa55;
posted @ 2013-05-30 20:40 何杨 阅读(180) | 评论 (0)编辑 收藏

/**********************************************
* 获取相对于今天的日期
* 2013年4月29日22:21:23
*********************************************
*/
function GetDateStr(AddDayCount) {
    
var dd = new Date();
    dd.setDate(dd.getDate()
+AddDayCount);//获取AddDayCount天后的日期
    var y = dd.getFullYear();
    
    
var m = dd.getMonth()+1;//获取当前月份的日期
    m=parseInt(m,10);
    
if(m<10){
        m
="0"+m;
    }
    
    
var d = dd.getDate();
    d
=parseInt(d,10);
    
if(d<10){
        d
="0"+d;
    }
    
    
return y+"-"+m+"-"+d;
}

示例:
var today=GetDateStr(0);
var yesterday=GetDateStr(-1);
var thedaybeforeyesterday=GetDateStr(-2);

posted @ 2013-05-06 16:56 何杨 阅读(243) | 评论 (0)编辑 收藏

1.dom初始化
$(document).ready(
    function(){
        ...// 这里写初始化
    }
);

2.给所有class为channel的元素设定点击事件.
$('.channel').click(
     function(){
         ...
    }
);

3.给id=menuDiv下的ul下的li中的设定点击事件.
$("#menuDiv>ul>li>a").click{   
    function(){
         ...
    }
);
posted @ 2013-05-02 21:18 何杨 阅读(268) | 评论 (0)编辑 收藏

代码:
<div class="XXX">
    <img class="X" src="XX">
</div>

方法:
设置div与img等高,其height=line-height,这样Img就被DIV夹在中间了.
再设置div的margin-top=margin-bottom,这样上下外边距相等,img就随着div被夹在中间了.
posted @ 2013-04-30 21:10 何杨 阅读(378) | 评论 (0)编辑 收藏

1.调用new Object,如
var obj=new Object();
obj创建出来后没有任何属性或方法,需要手工进行添加
obj.property=XX;
obj.method=function(){...};

2.用大括弧{}来直接描述属性或方法
var obj={property01:value01,property02:value02,...};

3.自定义一个构建函数,然后用new来创建
function func(value01,value02,...,value0n){
     this.property01=value01;
     this.property02=value02;
     ...
     this.property0n=value0n;
}

var obj=new func(v1,v2,..,vn);
posted @ 2013-04-29 16:10 何杨 阅读(268) | 评论 (0)编辑 收藏

因为在click事件中,使用return false;语句,能让浏览器认为用户没有单击该链接,从而阻止该超链接跳转.
posted @ 2013-04-27 19:57 何杨 阅读(265) | 评论 (0)编辑 收藏

使高度自动,上部控制padding即可.
示例:
#XXX .XX .x{
      padding-top:20px;
      height:auto;
      ...
}

posted @ 2013-04-26 18:14 何杨 阅读(554) | 评论 (0)编辑 收藏

http://developer.51cto.com/art/201008/222367.htm

本文和大家重点讨论一下DIV高度自适应及注意问题,主要包括父div高度随子div的高度改变而改变和子div高度随父亲div高度改变而改变两种情况。

DIV高度自适应及注意问题

积累了一些经验,总结出一些关于div高度自适应的技巧,希望有助于大家,转载请标明出处,谢谢。

一、DIV高度自适应(父div高度随子div的高度改变而改变)

1、如果父div不定义height、子div均为标准流的时候,父div的height随内容的变化而变化,实现父div高度随子div的高度改变而改变。

代码: 

  1. <styletypestyletype="text/css"> 
  2. #aa{border:#000000solid5px}  
  3. #bb{border:#00ffffsolid5px;}  
  4. #cc{border:#0033CCsolid5px}  
  5. style> 
  6. <dividdivid="aa">父div  
  7. <dividdivid="bb">子divdiv> 
  8. <dividdivid="cc">子divdiv> 
  9. div> 

效果:IE、FF下一致

2、如果父div定义height,子div均为标准流的时候,在IE下父div的height随内容变化而变化,ff中则固定大小,如父div设置height:50px

代码: 

  1. <styletypestyletype="text/css"> 
  2. #aa{border:#000000solid5px;height:50px}  
  3. #bb{border:#00ffffsolid5px;}  
  4. #cc{border:#0033CCsolid5px}  
  5. style> 
  6. <dividdivid="aa">父div  
  7. <dividdivid="bb">子divdiv> 
  8. <dividdivid="cc">子divdiv> 
  9. div> 

IE效果

FF下效果

3、如果子div使用了float属性,此时已经脱离标准流,父div不会随内容的高度变化而变化,解决的办法是在浮动的div下面,加一个空div,设置clear属性both

未加空div代码: 

  1. <styletypestyletype="text/css"> 
  2. #aa{border:#000000solid5px;}  
  3. #bb{border:#00ffffsolid5px;float:left}  
  4. #cc{border:#0033CCsolid5px;float:left}  
  5. style> 
  6. <dividdivid="aa">父div  
  7. <dividdivid="bb">子divdiv> 
  8. <dividdivid="cc">子divdiv> 
  9. div> 

IE效果:

FF效果:

修改后代码: 

  1. <styletypestyletype="text/css"> 
  2. #aa{border:#000000solid5px;}  
  3. #bb{border:#00ffffsolid5px;float:left}  
  4. #cc{border:#0033CCsolid5px;float:left}  
  5. style> 
  6. <dividdivid="aa">父div  
  7. <dividdivid="bb">子divdiv> 
  8. <dividdivid="cc">子divdiv> 
  9. <divstyledivstyle="clear:both">div> 
  10. div> 

修改后效果:IEFF一致

4.另类的DIV高度自适应
原理:
padding-bottom将列拉长变的一样高,而负的margin-bottom又使其回到底部开始的位置,同时,溢出部分隐藏掉了。此方法必须加文档信息才能正常显示
代码: 


  1.  
  2. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
  3. <htmlxmlnshtmlxmlns="http://www.w3.org/1999/xhtml"> 
  4. <styletypestyletype="text/css"> 
  5. #aa{border:#000000solid5px;overflow:hidden;}  
  6. #bb{border:#00ffffsolid5px;float:left;  
  7. padding-bottom:100000px;margin-bottom:-100000px;}  
  8. #cc{border:#0033CCsolid5px;float:left;  
  9. padding-bottom:100000px;margin-bottom:-100000px;}  
  10. #dd{float:left}  
  11. style> 
  12. <dividdivid="aa"> 
  13. <dividdivid="bb">子divdiv> 
  14. <dividdivid="cc">子divdiv> 
  15. <dividdivid="dd">子div<br/><br/><br/><br/><br/>div> 
  16. div> 
  17.  

效果:


二、DIV高度自适应(子div高度随父亲div高度改变而改变)

在有边框的情况下,你会发现同一个div,在IE下的高度和在FF下的高度是不一样的,比如你设置了高度为100px的div,边框是 border:5px;IE的高度是5+5+空白区域=100px,而FF下高度是100px的div是不包括高度的,只是空白区域的高度,如下图黑框的 部分:


黑框的上方是对齐的,但是设置了同样的高度,效果却不一样,代码如下:

  1. <styletypestyletype="text/css"> 
  2.  
  3. #aa{border:#000000solid5px;height:100px;}  
  4.  
  5. #bb{border:#00ffffsolid5px;float:left;height:100%}  
  6.  
  7. #cc{border:#0033CCsolid5px;float:left}  
  8.  
  9. style> 
  10.  
  11. <dividdivid="aa"> 
  12.  
  13. <dividdivid="bb">子divdiv> 
  14.  
  15. <dividdivid="cc">子divdiv> 
  16.  
  17. div> 

如果没有设置边框,完全没有高度不一致的情况,子div适应父div很简单,如上面代码,只是在子div加了height:100%属性即可。如果 设置了边框,可以把子div的高度设置为比父div小上下边框高度的值,比如在此例中,可把#bb中height改为100-5-5=90px,结果在 IE和Mozilla中显示一致。

有一点要注意,如果父div是body的话,也就是说一个body套了一个div,让div适合body的大小的,必须设置body的高度才能实现子div随body改变而改变,body{height:100%}

posted @ 2013-04-25 16:18 何杨 阅读(276) | 评论 (0)编辑 收藏

适用于IE和FF

父Div中设置
    text-align:center;

子Div中设置:
    margin-left:auto:
    margin-right:auto;

    marigin:0 auto;

posted @ 2013-04-22 18:13 何杨 阅读(10255) | 评论 (1)编辑 收藏

select * from SYSCAT.REFERENCES  where constname = 'FK_SRT_ASSIGNMENTS_SMT_RESOURCES_01'
posted @ 2013-04-22 15:23 何杨 阅读(885) | 评论 (0)编辑 收藏

将一个字符串存入数据库并显示出来是一项简单任务,当字符串长度较短(新闻级别)时确实如此.
然而量变引起质变,当字符串长度增加到一定程度(小说级别)时,原有的对简短字符串的处理流程就需要做出一些变化了.下文将讨论这些变化的细节.

一.Web系统的基本情况
以下是某Web系统的基本情况:
前台JS框架:jQuery1.7.2 它确实贴心,比Dojo强,write less do more真不是空话
前后台信息传递方式:全部为Ajax异步处理 拒绝form提交
控制器:Spring3 MVC 很好 SpringMVC终将动摇Struts1/2的低位
Mapping:Hibernate3.2(C),SpringDAO(RUD)
后台DB:MySql5.2 它确实小巧方便,如果Oracle DB2跑在我的T410上那就开不了别的程序了

二.长文本向后台的传递
Web前台向后台传递数据的方式有get和post两种,它们之间有一些差别.就本文涉及的场景来说,差别主要在数据量的大小上,GET方式对传输的数据有大小限制,通常不能大于2KB;而使用POST方式传递的数据量比GET方式大得多,理论上不受限制.因此我采用了POST方式.
传递代码如下:
    var url='wisdom/add.do';

    $.post(
        url, 
        {title:
encodeURIComponent($("#title").val()),concept:
encodeURIComponent(
$(
"#concept").val())},
        function(data,textStatus){    
            
var status=$(data).find("status").text();
            
            
if(status=="ok"){
                ...

            }
            
else{
                
var text=$(data).find("text").text();
                alert(text);
            }
        }
    );
以上代码中,concept就是在textarea中的长文本,理论上长度是无限的,但实际应用中会受到数据库字段的限制.

三.服务器的设置
POST提交有长度限制,当超过时将会出错,可以配置maxPostSize参数来改变大小。
<Connector port="8080" protocol="HTTP/1.1"  connectionTimeout="20000"  redirectPort="8443" maxPostSize="0"/>
当设置为零时,就没有长度限制了.

四.长文本在DB中的存储
首先需要考虑的数据库的字段,一般的varchar肯定是不够了;clob/blob容量是够,但查询时需要取出来转化一下,而这样速度上就受限了;一向比较贴心的MySql提供了一个LONGTEXT类型,它可以容纳4294967295byte的文字,而在使用上又如同文本一样,这成了我的首选,在后来的实际测试中,我发现它存储80万个汉字是没有问题的,100万也行,这就已经满足我的需求了,因此更大的测试没有再进行.
这个Web系统CRUD处理中,C是通过Hinernate完成的,因此在hbm.xml中进行设置就好了.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.ibm.heyang.domain">
    
<class name="Wisdom" table="collections_wisdom">
        
<id name="id" column="ID" >
            
<generator class="increment"/>
        
</id>
        
        
<property name="title" column="title" not-null="true"/>
        
<property name="concept" type="text">
            
<column name="concept" not-null="true" length = "16777216" />
        
</property>
    
        
<property name="conceptLength" column="conceptLength" />
        
<property name="addUserId" column="addUserId" />        
        
<property name="modifyTime" column="modifyTime"/>        
    
</class>
</hibernate-mapping>
以上粗体部分就是大文本字段的设置细节.
由于Hibernate是采用PreparedStatement,因此concept不需要进行转义和其它特殊处理.这给检索也带来了不少方便.

五.长文本的检索
由于插入数据库的文本就是原文,所以检索就是常规的检索,无须赘述.

六.长文本向前台的传递前的包装
在这个Web系统中,后台向前台传递的数据是以XML的型式往回传的,前台JS得到后再解析出来.
但长文本有一个特殊的地方就是内容无限制,比如违反XML规则的字符如<>等,这里就需要把它放在CDATA块里包起来后再向前传递.
如下:
        StringBuilder sb=new StringBuilder();
        
        sb.append(
"<title><![CDATA[");
        sb.append(StringUtils.isBlank(title)
?"-":title);
        sb.append(
"]]></title>");
                        
        sb.append(
"<concept><![CDATA[");
        sb.append(concept);
        sb.append(
"]]></concept>");
如果不这样处理一下,前台js就可能解析XML出错.

七.长文本的显示

将长文本显示给用户看可以采用textarea显示和网页显示,如果是前者那就没有特殊处理,直接放进去就行了,文本格式和存储前会一样,只是用户看起来不方便,需要用滚动条拖来拖去;而网页方式就好多了,用户舒适度好很多,但要求我们进行一些特殊的处理.

首先是CSS设置,这是为了保证文本不把DIV撑开,设置如下:
#concept{
    width
:900px;
    max-width
:900px;
    min-width
:900px;
    display
:inline-block;
    padding-top
:10px;
    
    color
:#7a7a7a;
    font-size
:14px; 
    font-weight
:normal;
    
    text-align
:left;
    
    word-wrap
: break-word; 
    word-break
: normal;
    
    -moz-binding
: url('./wordwrap.xml#wordwrap');/*FF only*/
    word-break
:break-all;
    white-space
: moz-pre-wrap;
}

其次,需要对文本处理一下,这样做的目的是把<>转义,另外把\n转化成<br>,空格转化成&nbsp;等,如果不这样做,文字会乱,阅读起来很觉不便.
以下是转化函数:
function makeText2Html(originalText){
    
    originalText
=originalText.replace("<","&lt;");
    originalText
=originalText.replace(">","&gt;");
    originalText
=originalText.replace(/\n/g,"<br/>");
    originalText
=originalText.replace(/\t/g,"&nbsp;&nbsp;&nbsp;&nbsp;");
    originalText
=originalText.replace(" ","&nbsp;");
    
    
return originalText;
}
以下是把XML中的长文本放到页面中:
$("#concept").html(getFormatedText($(data).find("concept").text()));

如果IE ONly的话,也可以把文本用<pre>标签包起来,这样就不用makeText2Html的辅助了.

以上就是对长文本的存储和显示的一些处理,由于作者水平有限,上文只是我的孔见,不当之处还请指出.
posted @ 2013-04-19 16:11 何杨 阅读(653) | 评论 (5)编辑 收藏

转载自:
http://www.cnblogs.com/Mygirl/archive/2012/03/27/2419971.html


     什么是HTTP长连接? HTTP长连接,与一般每次发起http请求或响应都要建立一个tcp连接不同,http长连接利用同一个tcp连接处理多个http请求和响应,也叫 HTTP keep-alive,或者http连接重用。使用http长连接可以提高http请求/响应的性能。

     使用http长连接有很多好处,包括:
更少的建立和关闭tcp连接,可以减少网络流量。 因为已建立的tcp握手,减少后续请求的延时。 长时间的连接让tcp有充足的时间判断网络的拥塞情况,方便做出下步操作。

    这些优点在使用https连接时更显著。可以减少多次建立高消耗的SSL/TLS握手。 在HTTP/1.1中,默认使用的是长连接方式。客户端默认服务端会保持长连接,即便返回错误响应;除非明确指示不使用长连接。同时,协议中也指定了客户 端可以发送关闭信号到服务端来关闭TCP连接。

    怎样是连接可以重用? 因为TCP是基于流的协议,所以HTTP协议需要有一种方式来指示前一个响应的结束和后一个响应的开始来重用已建立的连接。所以,它要求连接中传输的信息 必须有自定义的消息长度。自定义消息长度可以通过设置 Content-Length 消息头,若传输编码的实体内容块,则每个数据块的标明数据块的大小,而且响应体也是以一个特殊的数据块结束。

    若中间存在代理服务器将会如何? 因为长连接仅占用一条传输链路,所以代理服务器能否正确得与客户端和服务器端(或者其他代理服务器)发送长连接或非长连接的信号尤为重要。但是HTTP的 客户端或服务器端来看,代理服务器对他们来说是透明的,即便长连接是需要关注的。

     当前的JDK如何处理Keep-Alive? JDK同时支持HTTP/1.1 和 HTTP/1.0。 当应用程序读取完响应体内容后或者调用 close() 关闭了URLConnection.getInputStream()返回的流,JDK中的HTTP协议句柄将关闭连接,并将连接放到连接缓存中,以便后 面的HTTP请求使用。 对HTTP keep-Alive 的支持是透明的。但是,你也可以通过系统属性http.keepAlive和http.maxConnections以及HTTP/1.1协议中的特定的 请求响应头来控制。控制Keep-Alive表现的系统属性有:
    http.keepAlive=<布尔值> 默认: true 指定长连接是否支持
    http.maxConnections=<整数> 默认: 5 指定对同一个服务器保持的长连接的最大个数。
    影响长连接的HTTP header是: Connection: close 如果请求或响应中的Connection header被指定为close,表示在当前请求或响应完成后将关闭TCP连接。

     JDK中的当前实现不支持缓存响应体,所以应用程序必须读取完响应体内容或者调用close()关闭流并丢弃未读内容来重用连接。此外,当前实现在清理连接时并未使用阻塞读,这就意味这如果响应体不可用,连接将不能被重用。

    JDK1.5中的新特性 当应用接收到400或500的HTTP响应时,它将忽略IOException 而另发一个HTTP 请求。这种情况下,底层的TCP连接将不会再保持,因为响应内容还在等待被读取,socket 连接未清理,不能被重用。应用可以在捕获IOException 以后调用HttpURLConnection.getErrorStream() ,读取响应内容然后关闭流。但是现存的应用没有这么做,不能体现出长连接的优势。为了解决这个问题,介绍下workaround。
当响应体的状态码大于或等于400的时候,workaround 将在一定时间内缓存一定数量的响应内容,释放底层的socket连接来重用。基本原理是当响应状态码大于或等于400时,服务器端会发送一个简短的响应体来指明连接谁以及如何恢复连接。

   

下面介绍一些SUN实现中的特定属性来帮助接收到错误响应体后清理连接: 主要的一个是: sun.net.http.errorstream.enableBuffering=<布尔值> 默认: false

     当上面属性设置为true后,在接收到响应码大于或等于400是,HTTP 句柄将尝试缓存响应内容。释放底层的socket连接来重用。所以,即便应用不调用getErrorStream()来读取响应内容,或者调用 close()关闭流,底层的socket连接也将保持连接状态。
下面的两个系统属性是为了更进一步控制错误流的缓存行为: sun.net.http.errorstream.timeout=<int> in 毫秒 默认: 300 毫秒

     你如何做可以保持连接为连接状态呢? 不要忽略响应体而丢弃连接。这样会是TCP连接闲置,当不再被引用后将会被垃圾回收器回收。 如果getInputStream()返回成功,读取全部响应内容。如果抛出IOException ,捕获异常并调用getErrorStream() 读取响应内容(如果存在响应内容)。
即便你对响应内容不感兴趣,也要读取它,以便清理连接。但是,如果响应内容很长,你读取到开始部分后就不感兴趣了,可以调用close()来关闭流。值得注意的是,其他部分的数据已在读取中,所以连接将不能被清理进而被重用。
下面是一个基于上面建议的代码样例:

try
    URL a = new URL(args[0]); 
    URLConnection urlc = a.openConnection(); 
    is = conn.getInputStream(); 
    int ret = 0; 
    while ((ret = is.read(buf)) > 0) { 
      processBuf(buf); 
    }
    // close the inputstream
    is.close();
} catch (IOException e) {
    try {
        respCode = ((HttpURLConnection)conn).getResponseCode();
        es = ((HttpURLConnection)conn).getErrorStream();
        int ret = 0;
        // read the response body
        while ((ret = es.read(buf)) > 0) {
            processBuf(buf);
        }
        // close the errorstream
        es.close();
    } catch(IOException ex) {
        // deal with the exception
    }
}

  如果你预先就对响应内容不感兴趣,你可以使用HEAD 请求来代替GET 请求。例如,获取web资源的meta信息或者测试它的有效性,可访问性以及最近的修改。下面是代码片段:

URL a = new URL(args[0]);
URLConnection urlc = a.openConnection();
HttpURLConnection httpc = (HttpURLConnection)urlc;
// only interested in the length of the resource
httpc.setRequestMethod("HEAD");
int len = httpc.getContentLength();
posted @ 2013-04-10 21:16 何杨 阅读(295) | 评论 (0)编辑 收藏

看到很多童鞋讨论有关美剧学习英语到底有没有用,以及用哪部美剧练习,我在这里想说这只是一个参考,世界上没有绝 对的事情,究竟有没有用看个人,想必在校内上至少是高中生,大部分是大学生吧,如果你到现在还无法衡量自己的英语水平或者依旧被英语牵着鼻子走,我只能说 我很抱歉,我觉得这不仅是个人的悲哀更是中国教育的悲哀。如果你到现在连自己基本的评判标准的话,即使存在完美无缺的日志,你依旧照搬照抄,不适合自己的 实际情况,那一切皆为徒劳。就算这是学习英语的一条途径,有几个人能真的照着做呢?

  1. 不是所有的美剧都适合学英语

   如果喜欢看如《24小 时》这样的动作片, 那你基本会讲一口流利的”呯”"轰”"啊”之类的开枪爆炸声英语.如果你喜欢看如《豪斯医生》这种专业性很强的片子,那你基本会讲一些如 MRI,CT,Tumor之类的连自己都不明白的江湖郎中英语.如果看的是《越狱》,基本不用举手,别人就知道你是黑手党的了.不是所有剧都合适的,用来 学习的美剧,是要有一定对话量,生活化的,平民化的片子.   2. 开着字幕看是没有前途的

  很 多人喜欢开着字幕看,觉得会有参照更有帮助,其实这是在拖你的后腿.就像很多人结婚,喜欢找个比自己丑的伴娘,以为这样自己就进步了,事实上是被拖下水 了.中文是母语,对我们的眼球来说有无比强大的吸引力,只要在那里,你一定会看,就像放个美女在眼前,男人一定会看,不看的可能是老婆在一边,或是他爱人 也是个男人.一般人永远会不自觉通过中文字幕理解英语,而不是通过听懂-理解-记忆-重复,这样的过程学到英语.

  3.看一遍是不够的

   看 一遍根本不能叫学英语,充其量只能叫娱乐.如果是抱着学习的目的,必须反复看,精听,理解句子词语的意思,为我所用才行.如果看一遍,基本你就被情节彻底 打败了,或哭或笑,反复思考自己该拥有<HEROES>里的哪种超能力,担心下集可以下载前的日子该怎么过,哪还有心思管学英语这码事,哪怕 讲 的是柬埔寨语都无所谓.所以通过看个几遍,基本到了对剧情已经免疫的程度,如看老友记看到已经笑不出来了,那差不多可以洗干净耳朵仔细听了.

  给大家推荐几部我最喜欢用来正常学英语的美剧:

  1. 初级:Friends

  Friends是经典中的经典,对于英语初级水平的朋友来说,是突破发音和对话交流最好的美剧.整个剧都是人物间谈话,而且都很简短,没有长句,词汇非常简单,基本是plain english的典范.我发觉自己的英文有明显的提升,就是在看这部剧多达十遍后.

  2. 中级:Desperate Housewives

  这部剧讲述的是美国中产阶级的故事,所以用词和语言非常标准,相对于Friends有更多的长句和表达,非常适合中级水平的朋友学习.

  3. 高级:The West Wing

  这是关于美国白宫的政治题材美剧,整个剧基本都是对话,而且语速非常快,充斥着辩论和演讲,词汇也非常高级,听起来很有难度.如果能把这部剧都搞透了,真可以谢谢十八辈祖宗了.

通 过看美剧的方法,在2个月的时间内将《欲望都市》看了4至5遍,托福听力由原先的20分的水平升至了满分。她的做法就是,找到一部自己很喜欢的美剧,然后 先看一遍带中文字幕的。了解了大致的剧情,满足了自己休闲娱乐的好奇心,然后第二,三遍的时候开始看带双语字幕的,遇到不认识的生词,就停下来查一查,然 后记录。这样虽然比较费时,但是相比死气沉沉地不停地听抄听写,已经要生动很多。经过一段时间的积累,已经记了满满一本的生词和句型。这个时候,再去看第 四遍和第五遍,完全脱离拐杖,不带中英字幕。经过前面的积累,这时候再看情节已经轻松很多,并且能够深入理解每个人物在说这句对白时候的动机和理由,对语 言本身的理解也更深入了一步。于此同时,进行一下跟读。比如,听到一个人物的口语很好听,发音标准优雅,就刻意地进行一下模仿,体会一下她的语音、语调、 重音、节奏。这样在训练了听力的前提下,口语水平也会有大幅度地提升。要知道美剧当中的对白和旁白是最好的口语学习范本。

在看美剧学习语 言的时候要注意些什么?首先,注意发音。对于任何一门语言,语音是基础,它不仅包括单词的发音,还包括真实交际中词汇、习语的连读、失爆、弱化、浊化、重 音、缩读等一系列的音变形式。至于语调节奏,则是地道流利表达英语的润滑剂,没有接触过地道的外国人,没有和他们有过面对面的交谈,是很难感受到语调节奏 在表达思想中的巨大作用和强大震撼力的。因此要仔细地体会美剧之中,人物的发音和表达之中的语言习惯。其次,了解文化。语言是文化的载体,用词和句式使用 是否准确直接体现了对异国文化了解的程度。可以说,发音好其实只是与美国人的语言形似,如果能够掌握美国人的思维习惯和文化,用美国文化去思维,则可达到 神似的效果。这就是一种立体的学习方式,美剧则是这种学习方法最好的媒介。

一、准备好笔和纸,将笔放在鼠标旁边,将便笺放在屏幕和座椅之间,作好随时停顿和记录的预备动作。

二、只记录能引发自己内心感触和共鸣的语句和一些符合自身个性特色的句型及语法。

三、记录的时候最好不要分析思考和尝试记忆,待整个影片观看完毕之后,将统一回顾和整理。

四、一部章节或一部电影里面的典型句子和精彩对白记录完毕之后,一定要趁热打铁,想办法用上。(如通过写博客或者到英语角去操练。如果有参加培训班的话,一定不要放过任何能锻炼自己演讲口才的机会。)

五、 再告诉大家一个绝活:如果你发现了那种让自己百看不厌的经典英文影片,不妨通过全能音频转换通软件将它的MP3提取出来,然后到网站上下载完整的英文字 幕,再用LRC歌词编辑器将它做成同步显示歌词文本,放到自己的MP3或者电脑里,随时温习,处处操练。不知不觉这部影片的精髓尽入脑海,随时引用。从而 达到通过影视学英语的最终目的。


不少英语学习者都有这样的困惑:学了十几年的英语,通过了考试,能完全听懂标准语速的英语新闻广播,可就是听(看)不懂英语原版影视剧(无中文字幕),这使他们开始怀疑自己的听力能力。
    要解决这个问题,我们先来了解一下新闻英语和影视英语之间的区别。首先,两者在语体上有较大的区别。前者是书面语体的口头形式,用于正式的交际场合,经过 加工和润饰,比较文雅,是合乎标准的书面语言,因而使较多使用长句、复句、结构严谨的完整句。布局层次分明、逻辑关系严谨是它的主要特征。后者为口头语 体,以日常会话为基本形式,一般用于交际双方直接接触的场合,因而多使用短句、单句、省略句。随意性,不完整是它的主要特征。在英语学习过程中,我国的英 语学习者接触的绝大部分是书面语体。而在英语影视剧中,口头体的语言材料是最重要的特征,具体表现为口语中流行的惯用表达方式、俚语以...(未完)
posted @ 2013-04-08 21:48 何杨 阅读(231) | 评论 (0)编辑 收藏


阅读的时间:

1、早上5:30-6:00起床,有将近1小时的整块阅读时间,如果时间充足一点,会做些笔记.

2、包里放上7寸的阅读设备(以前是K3,这段时间换成NT),放上几十本排版不错的电子书,在有时间的时候看看,比如排队、等人、开会之类零散时间。

3、手机里放一些有声书,比如台湾的博客思听、每天八分钟、中医堂、百家讲坛,做车、做家务、身体锻炼时听听

4、睡前把所有事情都安排完,会拿本书在床上看上一会,然后睡觉。
5、所有读完第一遍,觉得不错的书,会开始读第二遍并做些笔记。
6、出差时如果周末有时间会找家环境好点的咖啡厅,看上半天或一天书。不出差如果周末有空闲时会去图书馆,带上笔记看上半天书,做个记录。
7、做飞机或动车时会准备二、三本纸制书,比较厚有些深度的那种,我发现自己在飞机上看书效果最好。看累了就做笔记或简评。
想多看点书的最有用的建议:就是关闭电脑、离开网络,有网络有电脑的地方永远会让你分心的
我看书效果最好的三个地方:飞机、图书馆、咖啡厅

-----------------------------------------------------------------------------------------------------------------------
总能在网上看到有人抱怨没有时间看书,在现在这个时代最影响注意力的东西就是网络,只要有了网络很容易浪费时间,不管是你用电脑、手机都是一样,点来点去,1个小时2个小时很快就没了,就在我在回答中说的,想多看点书最好的办法就是离开网络,下决心每天留出半小时或1小时的阅读时间,关电脑,关手机,开始看书,看完书做随手做些记录。

关于阅读设备:现在7寸的阅读器已经非常便宜了,K4和N2(Nook Simple Touch)也就700-800元左右,可以考虑买一个。放在包里,拷贝些电子书,有空的时间顺手就拿出来读一会。最好是E-Ink屏的,不要平板,平板什么都能做太容易分心了,我换成Nook Tablet之后,阅读的时间和数量要比K3少很多。

给个建议:最好不要在地铁或公交上用手机看书。颠簸中看小说、玩游戏,很容易引起视力功能尚未发育成熟的青少年视疲劳。一般来说,人们使用手机、平板电脑时,眼睛和屏幕的距离在20厘米左右,这样近距离且长时间地盯着屏幕看,容易使睫状肌产生疲劳,变成假性近视.,
在使用手持终端时,最好不要离屏幕太近,保持30厘米以上的距离最为适宜。同时尽量多眨眼,避免眼球过多地暴露在空气中,以减少眼部水分的蒸发。此外,应在休息时间经常站起来,活动活动颈部肌肉,最好找些有声书、Podcast或英语来听。

前二天在微博转的一句话:
每天花一点钟看10页有用的书,每年可看3600多页书,30年读11万页书。诸位,11万页书足可以使你成为一个学者了。可是,每天看三种小报也得费你一点钟的工夫;四圈麻将又得费你一点钟的光阴。看小报呢?还是打麻将呢?还是努力做一个学者呢?——胡适,纪念胡适先生逝世50周年。

就从今天开始培养你的阅读习惯吧,少上网、少玩会游戏,少聊天,少刷些豆瓣、微博,开始阅读。
posted @ 2013-04-06 22:37 何杨 阅读(201) | 评论 (0)编辑 收藏

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping package="com.ibm.heyang.XXX">
    
<class name="XXXClas" table="XXX_Table">
        
<id name="id" column="ID" >
            
<generator class="increment"/>
        
</id>
        
        
<property name="name" column="name" not-null="true"/>
        
<property name="content" type="text">
            
<column name="content" length = "16777216" />
        
</property>    
    
    
</class>
</hibernate-mapping>

以上length="16777216"
是关键,它会把字段对应到MySql的LONGTEXT类型.

以上是受到
http://sonyfe25cp.iteye.com/blog/830566
启发的.

posted @ 2013-04-02 23:18 何杨 阅读(5543) | 评论 (0)编辑 收藏

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
 
<head>
  
<title> New Document </title>
  
<meta name="Generator" content="EditPlus">
  
<meta name="Author" content="">
  
<meta name="Keywords" content="">
  
<meta name="Description" content="">
 
</head>

 
<body>
  
 
</body>
</html>
<script type="text/javascript">
<!--
window.onload
=function(){
    
var member=new Object;

    member.age
=35;
    member.name
="Heyang";
    member.display
=function(){
        alert(
this.name+" "+this.age);
    };

    alert(getObjAllProperties(member,
"member"));
};

function getObjAllProperties(obj,objName){
    
var retval="";

    
for(var p in obj){
        retval
+=objName+"[\""+p+"\"]="+obj[p]+"\n";
    }

    
return
 retval;
}

//-->
</script>
posted @ 2013-03-20 12:34 何杨 阅读(700) | 评论 (0)编辑 收藏

一切原创性和先发性的事情都蕴涵一个基本原理,那就是当你真心去做的时候,上天的祝福也将随之而来.
posted @ 2013-03-13 14:11 何杨 阅读(223) | 评论 (0)编辑 收藏

关于让网页中的JavaScript函数自动执行,方法就多洛,但是万变不离其宗,下面给大家介绍一下!

  前提条件,网页中必须有JS函数代码,或者,使用文件导入的方法也行:

  在HTML中的Head区域中,有如下函数:

   <SCRIPT   LANGUAGE="JavaScript">  
  functionn MyAutoRun()
  {  
   //以下是您的函数的代码,请自行修改先!
   alert("函数自动执行哦!");   
  }   
  </SCRIPT>

  下面,我们就针对上面的函数,让其在网页载入的时候自动运行!

  ①第一种方法

  将如上代码改为:

   <SCRIPT   LANGUAGE="JavaScript">  
  functionn MyAutoRun()
  {  
   //以下是您的函数的代码,请自行修改先!
   alert("函数自动执行哦!");   
  }   
  window.onload=MyAutoRun; //仅需要加这一句
  </SCRIPT>

  ②第二种方法

  修改网页的Body为:

  <body onLoad="MyAutoRun();">

  或者改为:

  <body onLoad="javascript:MyAutoRun();">  

  ③第三种方法

  使用JS定时器来间断性的执行函数:

  setTimeout("MyAutoRun()",1000);   //隔1000毫秒就执行一次MyAutoRun()函数

  实现方法,将最上面的那JS函数,改为:

   <SCRIPT   LANGUAGE="JavaScript">  
  functionn MyAutoRun()
  {  
   //以下是您的函数的代码,请自行修改先!
   alert("函数自动执行哦!");   
  }   
  setTimeout("MyAutoRun()",1000); //这样就行拉
  </SCRIPT>

本文转载自:
http://blog.163.com/long_alfred/blog/static/188238279201161591355842/
posted @ 2013-03-12 17:50 何杨 阅读(398) | 评论 (0)编辑 收藏

1.我希望当初我有勇气过自己真正想要的生活,而不是别人希望我过的生活。
这是所有后悔的事中最常听到的。心理学上有个理论,较之那些我们做过的事,人们后悔的往往是那些没做的事。所以当人们在生命尽头往回看时,往往会发现有好多梦想应该实现,却没有实现。你的生活方式、你的工作、你的感情、你的伴侣,其实我们多少人过着的是别人希望你过的生活,而不是自己真正想要的生活——又可能,一直以来你把别人希望你过的生活当作是你想要的生活。当你疾病缠身时,才发现其实自己应该而且可以放下很多顾虑追求你要的生活,似乎已经晚了一点。

2.我希望当初我没有花这么多精力在工作上。
Ware说这是她照顾过的每一个男病人会说的话。因为工作,他们错过了关注孩子成长的乐趣,错过了爱人温暖的陪伴,这是他们最深的后悔与愧疚。其实对于现在的职业女性来说,这也将成为一个问题。黑马乐如果把你的生活变简单些,你也许会发现自己在做很多你以为你需要做其实不需要你做的事。腾出那些事占的空间,可能你会过得开心一点。

3.我希望当初我能有勇气表达我的感受。
太多的人压抑自己的感受与想法,只是为了“天下太平”,不与别人产生矛盾。渐渐他们就成了中庸之辈,无法成为他们可以成为的自己。其实,有很多疾病与长期压抑愤怒与消极情绪有关。也许当你直言不讳,你会得罪某些人。但可能从此以后因为你的中肯,你们不打不相识;又或者翻脸,正好让你摆脱这种需要你压抑自己感受才能维持的累人关系。不管哪一种结果,你都是赢家,不是吗?——不过当然,直言不讳还是有底线的。

4.我希望当初我能和朋友保持联系。
老朋友的好,我们总要到自己有事了的时候才会想到。多少人因为自己忙碌的生活忽略了朋友忽略了曾经闪亮的友情。很多人临终前终于放下钱、放下权,却放不下心中的情感与牵挂。朋友也好,爱人也罢,其实生命最后的日子里,他们才是我们最深的惦念。

5.我希望当初我能让自己活过开心点。
也许有点出乎意料,但这一条也在前5之中。很多人直到生命的最后才发现,“快乐是选择”。他们在自己既定习惯和生活方式中太久了,习惯了掩饰,习惯了伪装,习惯了在人前堆起笑脸。就像五月天的那首歌,“你不是真正的快乐,你的笑只是你给的保护色”。他们以为是生活让他们不快乐,其实是他们自己让自己不快乐了。

转载自:
http://qing.weibo.com/tj/a59767ce33002xpo.html
posted @ 2013-03-12 17:43 何杨 阅读(198) | 评论 (0)编辑 收藏

/****************************************************
 * toCurrency: convert a number to currency
 * @param value
 * @returns {String}
 *
 ***************************************************
*/
function toCurrency(money) {  
    
if (/[^0-9\.]/.test(money)){
        
return '0.00';
    }

    money 
= money.replace(/^(\d*)$/"$1.");
    money 
= (money + "00").replace(/(\d*\.\d\d)\d*/"$1");
    money 
= money.replace("."",");
    
var re = /(\d)(\d{3},)/;
    
while (re.test(money)) {
        money 
= money.replace(re, "$1,$2");
    }
    money 
= money.replace(/,(\d\d)$/".$1");

    
return '' + money.replace(/^\./"0.")+" ";
}
posted @ 2013-03-01 22:04 何杨 阅读(351) | 评论 (0)编辑 收藏

修补的代价太大了.
posted @ 2013-03-01 21:29 何杨 阅读(179) | 评论 (0)编辑 收藏

select
     TO_CHAR(A.CREATE_TIMESTAMP,'YYYY-MM-DD HH24:MI:SS') as CREATE_TIMESTAMP
from
      table A

TO_CHAR是转化函数
YYYY-MM-DD HH24:MI:SS 是格式
 
posted @ 2013-03-01 13:22 何杨 阅读(7296) | 评论 (0)编辑 收藏

项目里又搞了个branch需要重新开个workspace下载去,嫌麻烦也得去做.
下载第一次,或许因为是网络问题,文件不全,IDE报错了.
于是删掉已经下载的,再来,一段时间后下好了,这回行,没错.
可是Build到75%就走不下去了.吃饭等,吃完还是75%!!
没招,心想是不是又下出问题了?于是再下一次,问题依旧.
以上时间耗费一下午了.
眼看要耽误进度,于是网络找钥匙,很多地方有说在Eclipse启动参数加上 -vmargs -Xmx512M.
如法炮制,涛声依旧.
都要气翻了.

没办法,换一个workspace,在重新来一边.好了!
估计还是第一遍下的文件搞坏了.
早知如此,何必耽误那么长时间.
posted @ 2013-02-24 18:19 何杨 阅读(1520) | 评论 (0)编辑 收藏

function convertMoney(value) {  
    var digital=Math.floor(value);
    var arr=digital.toString().split("").reverse();
    
    var t = "";  
    for(var i = 0; i < arr.length; i ++ ){  
      t += arr[i] + ((i + 1) % 3 == 0 && (i + 1) != arr.length ? "," : "");  
    }
    return t.split("").reverse().join("");
}
posted @ 2013-02-20 16:16 何杨 阅读(247) | 评论 (0)编辑 收藏

http://www.cnblogs.com/evilyang/archive/2012/02/17/2355218.html

一、使用场景

   服务端获得的DataTable转化为Json格式后传递给客户端dojo,dojo将json数据直接绑定在dojox.grid.DataGrid上

二、基本用法

1.客户端页面DataToJson.aspx返回一个Json数据

复制代码
    private void Json()
    {
        DataTable dt = this.GetData();
        string str = JsonHelper.DateTableToJson(dt);
        Response.Write(str);
        Response.End();
    }
复制代码
 2.利用ajax接受json数据

dojox.grid.DataGrid凭借dojo.data.ItemFileWriteStore可以轻松具有ajax功能

使用dojo.grid.DataGrid首先做如下准备工作

a.引入样式表

<link rel="Stylesheet" href="dojo-re/dojox/grid/resources/soriaGrid.css" />
b.引入所需库
dojo.require("dojo.parser");
dojo.require("dijit.form.Button"); 
dojo.require("dojox.grid.DataGrid");

dojo.require("dojo.data.ItemFileWriteStore");

dojo.require("dojox.layout.FloatingPane");
c.编写代码
复制代码
<script type="text/javascript">
        function Grid1() {
            var data = new dojo.data.ItemFileWriteStore({
                url: "DataToJson.aspx"
            });
            var structure = [
                { name: "用户名", field: "userName", width: "120px" },
                { name: "密码", field: "userPwd", width: "120px" },
                { name: "电子邮件", field: "email", width: "150px;" },
                { name: "博客", field: "blog", width: "150px" },
                { name: "生日", field: "birthday", width: "120px" },
                { name: "年龄", field: "age", width: "80px" },
                { name: "备注", field: "description", width: "120px" }
            ];
            var grid = new dojox.grid.DataGrid({
            store: data,
            structure:structure
            },"grid1");
            grid.startup();
        }
        function ShowFloatingPane() {
            var floatingPane = dijit.byId("dFloatingPane");
            floatingPane.show();
            Grid1();
        }
    </script>
复制代码

 所需HTML

复制代码
   <div >
        <div data-dojo-type="dojox.layout.FloatingPane" id="dFloatingPane"
           title
="A floating pane" data-dojo-props="resizable:true, dockable:true, title:'A floating pane'"
           style
="position:absolute;top:150px;left:400px;width:600px;height:400px; visibility:hidden">
             <div id="grid1" style="width:450px; height:350px"></div>
        </div>
    </div>
<div data-dojo-type="dijit.form.Button" data-dojo-props="label:'Show me', onClick:ShowFloatingPane"></div>
 
复制代码

 d.运行结果如下:

 

 三、继续完善DataGrid功能

1,增加搜索条件

query:{userName:"evilyang",id:"*"},

 2,隐藏一列,不显示

 {name:"密码",field:"userPwd",width:"100px",hidden:"true"}

3,为某一列增加一个样式名

 <style type="text/css">
    .name{ font-style:italic; font-size:14px; color:Red;}
    </style>
{ name: "用户名", field: "userName", width: "120px" ,classes:"name"}
 4,为某一列直接增加一个样式
{ name: "电子邮件", field: "email", width: "150px;",styles:"text-align:center;" },
5,固定前两列

更改structure结构,加入noscroll属性

复制代码
var structure = [{
                noscroll: true,
                cells: [
                { name: "用户名", field: "userName", width: "80px", classes: "name" },
                { name: "密码", field: "userPwd", width: "80px", hidden: "true" },
                { name: "电子邮件", field: "email", width: "150px;", styles: "text-align:center;" }    
                ]
            }, {
                cells: [
                { name: "博客", field: "blog", width: "120px" },
                { name: "生日", field: "birthday", width: "120px" },
                { name: "年龄", field: "age", width: "50px" },
                { name: "备注", field: "description", width: "120px" }
                ]
            }];
复制代码

 6,cell中的样式设置默认模式

defaultCell:{width:"80px",styles:"text-align:center;"},
 这样设置完后,每一列的属性就不必单独设置了

7, 其他属性

selectionMode: "extended", //none,single,multiple
loadingMessage: "请等待,数据正在加载中......",
 errorMessage: "对不起,你的请求发生错误!",
 columnReordering:true//此属性设置为true,可以拖拽标题栏,更换列顺序

new dojox.grid.cells.RowIndex({ name: "编号", width: "20px" })//加入自编号

四、数据显示高级功能

1, RowClick事件

复制代码
grid.on("RowClick", function(evt) {
                var idx = evt.rowIndex,
                    item = this.getItem(idx),
                    store = this.store;
                    content = dojo.byId("content");
                    content.innerHTML="you have clicked on rows " + store.getValue(item, "id");
          }, true);
复制代码

 2,SelectionChanged事件

复制代码
grid.on("SelectionChanged",dojo.hitch(grid, reportSelection), true);
function reportSelection() {
            var items = this.selection.getSelected(),
                        msg = "你选择了以下数据";
            var tmp = dojo.map(items, function(item) {
                return this.store.getValue(item, "id");
            }, this);
            var content = dojo.byId("content");
            content.innerHTML = msg + tmp.join(",");
           
        }
复制代码

五、显示效果如下图:


posted @ 2013-02-18 17:09 何杨 阅读(3922) | 评论 (0)编辑 收藏

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
 <head>
  <title> New Document </title>
  <meta name="Generator" content="EditPlus">
  <meta name="Author" content="">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
 </head>

 <body>
<input id="decimalTxt" />&nbsp;
<button id="showBtn" >Click</button>
 </body>
</html>
<script type="text/javascript">
<!--
window.onload=function(){
    document.getElementById("showBtn" ).onclick=function(){
        var value=document.getElementById("decimalTxt" ).value;
        alert(toCurrency(value));
    };
};

function toCurrency(money) {  
   if (/[^0-9\.]/.test(money)){
        return '0.00';
    }

    money = money.replace(/^(\d*)$/, "$1.");
    money = (money + "00").replace(/(\d*\.\d\d)\d*/, "$1");
    money = money.replace(".", ",");
    var re = /(\d)(\d{3},)/;
    while (re.test(money)) {
        money = money.replace(re, "$1,$2");
    }
    money = money.replace(/,(\d\d)$/, ".$1");

    return '' + money.replace(/^\./, "0.");
}  
//-->
</script>
posted @ 2013-02-18 16:30 何杨 阅读(1171) | 评论 (0)编辑 收藏

<a href="#" style="cursor:default">aaa</a>    
default 默认光标(通常是一个箭头) auto 默认。浏览器设置的光标。
crosshair 光标呈现为十字线。
pointer 光标呈现为指示链接的指针(一只手) move 此光标指示某对象可被移动。
e-resize 此光标指示矩形框的边缘可被向右(东)移动。 ne-resize 此光标指示矩形框的边缘可被向上及向右移动(北/东)。
nw-resize 此光标指示矩形框的边缘可被向上及向左移动(北/西)。
n-resize 此光标指示矩形框的边缘可被向上(北)移动。
se-resize 此光标指示矩形框的边缘可被向下及向右移动(南/东)。
sw-resize 此光标指示矩形框的边缘可被向下及向左移动(南/西)。
s-resize 此光标指示矩形框的边缘可被向下移动(北/西)。
w-resize 此光标指示矩形框的边缘可被向左移动(西)。
text 此光标指示文本。
wait 此光标指示程序正忙(通常是一只表或沙漏)。
help 此光标指示可用的帮助(通常是一个问号或一个气球)。
posted @ 2013-02-01 10:56 何杨 阅读(871) | 评论 (0)编辑 收藏

http://www-01.ibm.com/support/docview.wss?uid=swg27014463
posted @ 2013-01-17 16:20 何杨 阅读(365) | 评论 (0)编辑 收藏

此函数相当于Oracle中的NVL且更方便,它完全可以取代SQL中的CASE.

用法:
COALESCE(A,B,C,D...);

说明:
若A为空;则取B,若B为空,则取C;...;依此类推.

用例:
        sb.append("    select ");
        sb.append("        COALESCE(t03.EMP_USER_NAME,'') as sellerName,");
        sb.append("        COALESCE(t03.EMP_LOTUS_MAIL,'') as sellerNotesMail,");
        sb.append("        COALESCE(t03.EMP_INTERNET_ID,'') as sellerIntranetId,");
        sb.append("        COALESCE(t04.BUSINESS_UNIT_NAME,'') as busiNessUnit,");
        sb.append("        COALESCE(t02.TOPT_JOB_ROLE_NAME,'') as jobRoleName,");
        sb.append("        t01.TERRITORY_NAME as territoryName");
        sb.append("    from");
        sb.append("        topt.territory  t01");
        sb.append("        left join topt.job_role   t02 on t01.ROLE_KEY=t02.ROLE_KEY  ");
        sb.append("           left join FRS.Resource    t03 on t01.EMP_UID=t03.RESOURCE_EMPLOYEE_UID");
        sb.append("        left join TOPT.BUSINESS_UNIT t04 on t01.BUSINESS_UNIT_KEY=t04.BUSINESS_UNIT_KEY        ");
        sb.append("    where ");
        sb.append("        t01.TERRITORY_KEY=? ");
        String sql = sb.toString();
posted @ 2012-12-24 14:34 何杨 阅读(3975) | 评论 (0)编辑 收藏

1.StringUtils.join
使用方法:
String result=StringUtils.join(arr,'','');
如果arr=["1","2","3","A","B","C"];
那么result="1,2,3,A,B,C";
这个用在in查询的场合很好.
如果要颠倒过来,用String[] arr=result.split(",");就好了.
当然,String.split也是一个非常实用的函数.

2.MessageFormat.format
使用方法:
String message = "Territory {0} has been transferred to Team {1}.";
Object[] params={"A1","B2"};
String transferMsg = MessageFormat.format(message,params);//Territory A1 has been transferred to Team B2.
这个函数用于预设空缺待填文本的场合很好.

posted @ 2012-12-24 14:29 何杨 阅读(308) | 评论 (0)编辑 收藏

 Select filed from schema.table where condition  fetch first 1024 rows only

与select top 同等效果.
posted @ 2012-12-20 20:20 何杨 阅读(323) | 评论 (0)编辑 收藏

编码调试过程中,常有Sql语句的调试任务,这种任务比较麻烦的一点在于需要手工将?替换成参数,如果参数有十来个就够让人头疼的.
为了减轻这种无谓的劳动,本人设计了一个类来代替完成这种累而又容易让人出错的活.
下面是代码:
package com.heyang;

import java.text.MessageFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 将SQL语句中的问号替换成参数
 * 此类用于调试SQL时减轻手工加入参数的劳动量
 * 
@author heyang@gmail.com
 *
 
*/
public class SqlCompletion{
    
// 输入的SQL语句
    private String sql;
    
    
// 输入的参数
    private String[] arr;
    
    
// 构造函数
    public SqlCompletion(String sql,Object[] params){
        
this.sql=sql;
        
        arr
=new String[params.length];
        
        
for(int i=0;i<arr.length;i++){
            arr[i]
="'"+params[i].toString()+"'";
        }
    }
    
    
/**
     * 取得将问号替换成参数的补全SQL
     * 
@return
     
*/
    
public String getCompletedSql(){
        Pattern p 
= Pattern.compile("\\?",Pattern.CASE_INSENSITIVE);

        Matcher m 
= p.matcher(sql);
        StringBuffer sb 
= new StringBuffer();

        
boolean result = m.find();
        
int index=0;

        
while (result) {
            m.appendReplacement(sb, 
"{"+index+"}");
            index
++;
            result 
= m.find();
        }
        m.appendTail(sb);
        String repSql
=sb.toString();

        
        
return MessageFormat.format(repSql,arr);
    }
    
    
// 测试
    public static void main(String[] args){
        Object[] params
={"c1","c2","c3","c4"};
        SqlCompletion s
=new SqlCompletion("select * from t where t.f1=? and t.f2=? and t.f3=? and t.f4=? ",params);
        System.out.println(s.getCompletedSql());        
    }
}

输出结果是:
select * from t where t.f1='c1' and t.f2='c2' and t.f3='c3' and t.f4='c4'

你可以把此类拷贝到你的项目中,只要标明我是原作者就行.
posted @ 2012-12-17 22:55 何杨 阅读(529) | 评论 (0)编辑 收藏

POI是Java对Office操作的常用工具包,网上资料有很多,但良莠不齐,临时便找边试容易耽误时间,故收集一些常用操作在这里以便查阅.

1.创建Sheet
Sheet sheet = workbook.createSheet();
workbook.setSheetName(0, "Sheet0");

2.设置列宽
static final int[] COLUMN_WIDTHS = new int[] { 4*3500, 2*3500, 5*3500,
            2*3500, 3*3500, 3*3500, 3500, 3*3500, 2*3800, 2*3500};
for (int colnum = 0; colnum < COLUMN_WIDTHS.length; colnum++) {
    sheet.setColumnWidth(colnum, COLUMN_WIDTHS[colnum]);
}

3.设置缺省行高
sheet.setDefaultRowHeight((short)360);

4.设置某一行行高
Row rowFirst = sheet.createRow(0);
rowFirst.setHeightInPoints(20.0f);

5.给单元格设置字体及下边框
Cell cell00 = rowFirst.createCell(0);
cell00.setCellValue("abc123");            

HSSFFont fontAriel12Bold = workbook.createFont();
fontAriel12Bold.setFontName("Arial");
fontAriel12Bold.setFontHeightInPoints((short)12);
fontAriel12Bold.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
fontAriel12Bold.setColor(HSSFColor.RED.index);

HSSFCellStyle cell00FontStyle = workbook.createCellStyle();
cell00FontStyle.setBorderBottom(HSSFCellStyle.BORDER_THICK);
cell00FontStyle.setFont(fontAriel12Bold);
cell00.setCellStyle(cell00FontStyle);

6.给单元格设置背景色
HSSFCellStyle blueStyle = workbook.createCellStyle();
blueStyle.setBorderTop(HSSFCellStyle.BORDER_THICK);
blueStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
blueStyle.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
blueStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
Cell cell=row9.createCell(0);
cell.setCellStyle(blueStyle);
posted @ 2012-12-14 17:45 何杨 阅读(325) | 评论 (0)编辑 收藏

sqlcode sqlstate 说明
000 00000 SQL语句成功完成

01xxx SQL语句成功完成,但是有警告
+012 01545 未限定的列名被解释为一个有相互关系的引用
+098 01568 动态SQL语句用分号结束
+100 02000 没有找到满足SQL语句的行
+110 01561 用DATA CAPTURE定义的表的更新操作不能发送到原来的子系统
+111 01590 为2型索引设置了SUBPAGES语句
+117 01525 要插入的值的个数不等于被插入表的列数
+162 01514 指定的表空间被置为检查挂起状态
+203 01552 使用非唯一的名字来解决命名的限定列
+204 01532 命名的对象未在DB2中定义
+206 01533 命名的列不在SQL语句中指定的任何表中存在
+218 01537 因为SQL语句引用一个远程对象,不能为该SQL语句执行EXPLAIN
+219 01532 命名的PLAN TABLE不存在
+220 01546 不正确定义PLAN TABLE,检查命名列的定义
+236 01005 SQLDA中的SQLN的值至少应于所描述的列的个数一样大
+237 01594 至少有一个被描述的列应该是单值类型,因此扩展的SQLVAR条目需要另外的空间
+238 01005 至少应有一个被描述的列是一个LOB,因此扩展的SQLVAR条目需要另外的空间
+239 01005 至少应有一个被描述的列应是单值类型,因此扩展的SQLVAR条目需要另外的空间
+304 01515 该值不能被分配给宿主变量,因为该值不再数据类型的范围之内
+331 01520 不能被翻译的字符串,因此被设置为NULL
+339 01569 由于与DB2 2.2版本的子系统连接,所以可能存在字符转换问题
+394 01629 使用优化提示来选择访问路径
+395 01628 设置了无效的优化提示,原因代码指定了为什么,忽略优化提示
+402 01521 未知的位置
+403 01522 本地不存在CREAT ALIAS对象
+434 01608 在DB2未来发布的版本中将不支持指定的特性,IBM建议你停止使用这些特性
+445 01004 值被CAST函数截取
+462 01Hxx 由用户定义的函数或存储过程发出的警告
+464 01609 命名的存储过程超出了它可能返回的查询结果集的个数限制
+466 01610 指定由命名的存储过程返回的查询结果集的个数。成功完成
+494 01614 由存储过程返回的结果集的个数超过了由ASSOCIATE LOCATORS语句指定的结果集定位器的个数
+495 01616 因为倒台SQL的成本估算超出了在ELST中指定的警告阀值,所以发出警告
+535 01591 请求一个主健的定位更新,或请求一个使用自我引出 约束的表的删除操作
+541 01543 命名外健是一个重复的引用约束
+551 01548 命名的授权ID缺少在命名的DB2对象上执行命名操作的权限
+552 01542 命名的授权ID缺少执行命名操作的权限
+558 01516 已经被授权该PUBLIC,因此WITH GRANT OPTION不可用
+561 01523 对ALTER REFERENCES INDEX 和TRIGGER特权,PUBLIC AT ALL LOCATION无效
+562 01560 因为GRANTEE已经拥有这些特权,所以一个或更多的特权被忽略
+585 01625 模式名指定了不止一次
+599 01596 没有为长字符数据类型(BLOB,CLOB和DBCLOB)建立比较函数
+610 01566 由于建立了一个指定为DEFER YES的索引,指定的对象处于PENDING状态,或者因为使用了ALTER INDEX改变关键值的范围,所以指定的对象处于PENDING状态
+625 01518 因为删除了主健索引,所以表定义被标注为不完整
+626 01529 删除了加强UNIQUE约束的索引,唯一性不在被加强
+645 01528 因为建立的索引中没有包含NULL,所以WHERE NOT NULL被忽略
+650 01538 不能更改或者建立已命名的表为从属表
+653 01551 在已指定的分区表空间中尚没有建立指定的分区索引,所以分区索引不可得
+655 01597 为CREATE或ALTER STOGROUP语句指定特定或者非特定的卷ID,在DB2较新发布的版本中(版本6以后)将不再支持他们
+658 01600 当建立目录索引时,不能指定SUBPAGES语句,SUBPAGES将被忽略,并缺省为1
+664 01540 分区索引的限制关键字超出了最大值
+738 01530 已命名的对象的更改可能像只读系统中对象的改变要求一样
+799 0157 SET语句中引用的特定寄存器不存在,将忽略 SET请求
+802 01519 数据溢出或者因除法异常而引起的数据异常错误
+806 01553 ISOLATION(RR)与LOCKSIZE PAGE 冲突
+807 01554 由于十进制乘法导致溢出
+863 01539 连接成功,但是只支持SBCS
+2000 56094 SUBPAGES不等于1的1型索引不能成为数据共享环境中的缓冲池组依赖者
+2002 01624 因为指定的缓冲池不允许超高速缓存,GNPCACHE指定被忽略
+2007 01602 因为DB2子系统的参数禁用“提示(hiats)”所以不能指定优化提示
+30100 01558 分布式协议错误被检测到,提供原来的SQLCODE和SQLSTATE
-007 42601 SQL语句中由非法字符
-010 42603 字符串常量非正常终止;检查到有遗漏的引号标志
-029 42601 需要INTO语句
-060 42815 某特定数据类型的长度或者标量规范无效
-084 42612 不能执行SQL语句,因为该语句对动态SQL无效或者对OS/390的DB2无效
-097 42601 在单位类型、用户自定义的函数以及过程中不能使用带有CAST的LONG VARCHAR或LONGVARGRAPHIC
-101 54001 SQL语句超出了已确定的DB2限制:例如,表的数目太多,语句中的字节太多
-102 54002 字符串常量太长
-103 42604 无效数学文字
-104 42601 SQL语句中遇到非法符号
-105 42604 无效的字符串格式;通常引用一个格式不正确的图形字符串
-107 42622 对象名太长
-108 42601 RENAME语句中指定的名字有错误,不能使用限定词
-109 42601 指定了无效语句;例如CREATE VIEW不能包含ORDER BY 语句
-110 42606 遇到了无效的十六进制的文字
-111 42901 指定的列函数没有给出列名
-112 42607 无效的列函数语法;列函数不能运行与其他的列函数之上
-113 42602 遇到无效字符
-114 42961 该语句的位置名称必须与当前服务器匹配,但是却没有匹配
-115 42601 因为比较运算符没有伴着一个表达式或者列表,遇到了无效谓词
-117 42802 待插入的数值的个数于被插入的行中的列数不相等
-118 42902 数据修改语句(UPDATE或DELETE)和FROM语句中的表和视图命名不合法
-119 42803 HAVING语句中的列的列表与GROUP BY语句中的列列表不匹配
-120 42903 不允许WHERE语句、SET语句、VALUES语句或者SET ASSIGNMENT语句引用列函数
-121 42701 在INSERT或UPDATE语句中,某一列被非法引用了两次
-122 42803 非法使用了列函数。因为没有用于一个列函数的所有列不再GROUP BY语句中
-123 42601 特定位置的参数必须是一个常数或者一个关键词
-125 42805 ORDER BY语句中指定了无效数字,该数字要么小于1要么大于选定的列数
-126 42829 不能为一个UPDATE语句指定ORDER BY语句
-127 42905 在子选择中DISTINCT只能指定一次
-128 42601 SQL谓词中NULL使用不当
-129 54004 SQL语句中包含的表多于15个
-130 22019 ESCAPE语句必须为一个字符

22025 无效的ESCAPE模式
-131 42818 LIKE谓词只能用于字符数据
-132 42824 LIKE语句、ESCAPE语句、LOCATE函数或POSSTR函数中有无效运算对象
-133 42906 无效相关子查询引用
-134 42907 大于255字节的列被不正确使用
-136 54005 排序关键字的长度大于4000字节
-137 54006 被连接的字符串太大;字符的最大值为32767;图形的最大值为16382
-138 22011 SUBSTR列函数的第二个或第三个操作符无效
-142 42612 不支持的SQL语句。该语句可能在另外的RDBMS上有效,也有可能在其他的上下文中有效(例如,VALUES只能在触发器中出现)
-144 58003 指定的段号无效
-147 42809 某一源函数不能更改。要改变源函数,必须删除该源函数并重新建立他
-148 42809 RENAME和ALTER无法执行。RENAME不能对视图或者活动RI.ST表重新命名。ALTER不能用于改变列的长度,因为该列参与了RI、一个用户退出程序、全局的临时表或打开DATACAPTURE CHANGES表的列
-150 42807 触发活动的INSERT,UPDATE或DELETE语句中指定了无效的视图更新或一个无效的转换表
-151 42808 试图更新一个不可更新的视图的列、一个DB2 CATALOG表的列或者一个ROWID列
-152 42809 DROP CHECK试图删除一个参照约束,或者DROP FOREIGN试图删除一个检查约束
-153 42908 无效的视图建立请求,必须为旋转列表中列出的列出的未命名的列或者重复的列提供一个名字
-154 42909 不能用UNION、UNION ALL或者一个远程表建立视图
-156 42809 在视图上建立索引是非法的,或者在ALTER TABLE,CREATE TRIGGER,DROP TABLE或LOCK TABLE语句上指定一个不是表的其他对象这是无效的
-157 42810 必须在FOREIGN KEY语句中指定一个表名
-158 42811 视图的列和选择列表中的列不相匹配
-159 42089 无效DROP或COMMENT ON语句
-160 42813 对该视图的WITH CHECK OPTION无效
-161 44000 正被更新的视图WITH CHECK OPTION语句使得这行不能被插入或更新
-164 42502 用户没有建立这个视图的权限
-170 42605 标量函数指定了无效的参数个数
-171 42815 标量函数指定了无效的数据类型长度或者无效数值
-173 42801 在非只读型的游标上不能指定隔离级别UR
-180 22007 DATE、TIME、TIMESTAMP值的字符串表示法的语法不对
-181 22001 不是有效的DATE、TIME、TIMESTAMP值
-182 42816 在算术表达式中的日期/时间值无效
-183 22008 在算术表达式中返回的日期/时间值的结果不在有效值的范围内
-184 42610 没有正确使用日期/时间值的参数标记
-185 57008 没有定义本定的日期/时间出口
-186 22505 改变本定的日期/时间出口引发这个程序的长度无效
-187 22506 MVS返回无效的当前日期/时间
-188 22503 字符串表示无效
-189 22522 指定的编码字符集的ID无效或没有定义
-190 42837 不能象所设定的那样改变(ALTER)列。只能改变(ALTER)VARCHAR列的长度
-191 22504 字符串中包含了无效的混合数据
-197 42877 当两个或多个表被联合在一起排序时,限定的列名不能在ORDER BY语句中使用
-198 42617 试图对空的字符串发布一个PREPARE或EXECUTE IMMEDIATE语句
-199 42601 SQL语句中使用了非法关键词
-203 42702 模糊列引用
-204 42704 没有定义的对象名
-205 42703 指定的表的列名无效
-206 42703 列名没有在FROM语句所引用的任何表中,或者没有在定义触发器所在的表中
-208 42707 不能ORDER BY指定列,应为该列不在选择列表中
-212 42712 指定的表名在触发器中不允许多次使用,只能使用一次
-214 42822 DISTINCT、ORDER BY 引起的无效表达式
-219 42704 因为PLAN_TABLE不存在,EXPLAIN无法执行
-220 55002 遇到无效的PLAN_TABLE列
-221 55002 如果为PLAN_TABLE定义了可供选择的列,那么,必须定义所有的列
-229 42708 指定的现场找不到
-240 428B4 LOCK TABLE语句的PART子句无效
-250 42718 没有定义本地位置名
-251 42602 记号无效
-300 22024 宿主变量或参数中的字符串不是以NULL为终止
-301 42895 无效的宿主变量数据类型
-302 22001 输入的变量值对指定的列无效

22003 输入的变量值对指定的列而言太大
-303 42806 因为数据类型不兼容,不能分配数值
-304 22003 因为数据超出了范围,不能分配数值
-305 22002 没有NULL指示符变量
-309 22512 因为引用的宿主变量被设置成NULL,所以谓词无效
-310 22501 十进制的宿主变量或参数包含非十进制数据
-311 22501 输入的宿主变量长度无效,或者时负值或者太大
-312 42618 没有定义宿主变量或者宿主变量不可用
-313 07001 宿主变量的个数不等于参数标识的个数
-314 42714 模糊的宿主变量引用
-327 22525 在最后分区的关键字范围内,不能插入行
-330 22021 不能成功的翻译字符串
-331 22021 字符串不能分配到宿主变量,因为其不能成功的被翻译
-332 57017 不能为两个命名的编码字符集的ID定义翻译规则
-333 56010 子类型无效导致翻译失败
-338 42972 ON语句无效,必须引用连接的列
-339 56082 访问DB2 2.2版本的子系统被拒绝,原因时ASCII到EBCDIC翻译不能进行
-350 42962 无效的大对象规范
-351 56084 SELECT列表中有不支持的数据类型
-352 56084 输入列表中有不支持的数据类型
-355 42993 LOB列太大,以至不能被记录在日志中
-372 428C1 每个表只允许有一个ROWID列
-390 42887 在上下文中指定的函数无效
-392 42855 自从前一次FETCH以来,指定游标的SQLDA已被不恰当的改变
-396 38505 在最后的访问过程中,视图执行SQL语句
-397 428D3 在某一列上不恰当的指定了GENERATED因为该列不是ROWID数据类型
-398 428D2 为某一个宿主变量请求LOCATOR,但是该宿主变量不是一个LOB
-399 22511 在INSERT语句中为ROWID列指定的值无效
-400 54027 在DB2编目中定义的用户自定义索引不能超过100个
-401 42818 算术操作符或比较操作符的操作对象不是兼容的
-402 42819 算术函数不能用于字符或日期时间数据
-404 22001 SQL语句指定的字符串太长
-405 42820 数值文字超出了范围
-406 22003 计算出的或者倒出的数值超出了范围
-407 23502 不能把NULL值插到定义为NOT NULL的列中
-408 42821 数值不能被更新或插入,因为他与列的数据类型不兼容
-409 42607 COUNT函数指定的运算对象无效
-410 42820 浮点文字笔30个字符的最大允许长度长
-411 56040 CURRENT SQLID使用无效
-412 42823 在子查询的选择列表中遇到了多个列
-413 22003 当转换为一个数字型数据类型时,数据溢出
-414 42824 LIKE谓词不能运行于用数字或日期时间类型定义的列
-415 42825 为UNION操作指定的选择列表不是联合兼容的
-416 42907 包含UNION操作符的SQL语句不允许有长的字符串列
-417 42609 两参数标识符作为运算对象被指定在同一谓词的两边
-418 42610 参数标识符使用无效
-419 42911 十进制除法无效
-420 22018 字符串自变量值不符合函数的要求
-421 42826 UNION操作的选择列表中没有提供相同数目的列
-423 0F001 为LOB或结果集定位器指定的值无效
-426 2D528 在不允许更新的应用服务器不允许执行COMMIT语句
-427 2D529 在不允许更新的应用服务器不允许执行ROLLBACK语句
-430 38503 在用户自定义的函数或存储过程中遇到了错误
-433 22001 指定的值太长
-435 428B3 无效的应用定义的SQLSTATE
-438 xxxxx 使用了RAISE_ERROR函数的应用发出了一个错误
-440 42884 存储过程或用户自定义函数的参数列表参数个数于预期的个数不匹配
-441 42601 与标量函数一起使用DISTINCT或ALL是不正确的用法
-443 42601 指定的外部函数返回错误的SQLSTATE
-444 42724 与被称为存储过程或用户自定义函数有关的程序不能找到
-449 42878 对存储过程或用户自定义的 函数,CREATE或ALTER语句不正确(缺失EXTERNAL NAME 子句)
-450 39501 存储过程或用户自定义函数写入存储器的值超过了参数声明的长度
-451 42815 CREATE FUNCTION中指定了不正确的数据类型
-453 42880 用户自定义函数中的RETURNS语句无效
-454 42723 指定的函数识别标记与已存在的另一函数的识别标记冲突
-455 42882 模式名不比配
-456 42710 为用户自定义函数指定的函数名已经存在
-457 42939 用户自定义函数或用户自定义类型正试图使用系统中定义的函数或者类型所用的名称
-458 42883 没有找到函数
-463 39001 特定的外部例程返回无效的SQLSTATE
-469 42886 参数定义为OUT或INOUT的CALL语句必须提供宿主变量
-470 39002 指定了NULL参数,但是该例程却不支持NULL
-471 55023 存储过程或用户自定义函数失败:提供原因代码
-472 24517 外部的函数程序使游标处于打开状态
-473 42918 用户自定义数据类型命名不能和系统定义的数据类型一样
-475 42866 结果类型不能被转换成RETURNS类型
-476 42725 在其模式中该函数不是独一无二的
-478 42893 不能DROP或REVOKE特定的对象,因为其他对象依赖于该对象
-480 51030 直到存储过程已经被CALL后,DESCRIBE PROCEDURE和ASSOCIATE LOCATORS才能被发布
-482 51030 存储过程不返回到任何一个定位器
-483 42885 CREATE FUNCTION语句中的参数个数与源函数中的参数个数不匹配
-487 38001 选择了NO SQL选项建立指定的存储过程或用户自定义函数,但却视图发布SQL语句
-491 42601 CREATE FUNCTION语句无效,因为该语句没有RETURNS语句或者因为该语句没有指定有效的SOURCE或者EXTERNAL语句
-492 42879 指定函数的指定参数的个数有错误
-495 57051 语句的估计处理器成本超出了资源限制
-496 51033 语句无法执行,因为当前服务器与调用存储过程的服务器不同
-497 54041 指定的数据库超过了32767 OBID的上限,或者CREATE DATABASE语句使之达到了32511DBID的上限
-499 24516 指定的游标已被分配到结果集,该结果集来自已经指定的存储过程
-500 24501 因为连接被破坏,WITH HOLD游标被关闭
-501 24501 在试图获取数据或关闭一个游标前必须打开一个游标
-502 24502 在没有关闭游标前不能再次打开游标
-503 42912 因为列在游标的FOR UPDATE OF语句中没有被指定,该游标用于获取该列,所以不能更新该列
-504 34000 不能引用一个游标,因为他不是定义到程序里的
-507 24501 在试图更新或者删除WHERE CURRENT OF前,必须打开游标
-508 24504 因为被引用的游标当前不是处于数据行上,所以不能被更新或删除
-509 42827 除了在游标上指定的那个表(该表由WHERE CURRENT OF语句引用的)以外,再也不能从别的表上更新数据
-510 42828 表或视图不能被修改
-511 42829 对不可修改的表或视图,FOR UPDATE OF语句无效
-512 56023 对远程对象的无效引用
-513 42924 一个别名不能再被定义成另外的别名
-514 26501 游标尚没有被准备
-516 26501 试图描述未准备好的SQL语句
-517 07005 因为SQL语句尚没有准备好,游标无效
-518 07003 试图执行尚没有准备好的SQL语句
-519 24506 当为游标的SQL语句发布一个准备语句是,游标不能是打开的
-525 51015 不能在已指定的程序包中执行SQL语句,因为在绑定时间内该程序包无效
-526 42995 在给定的上下文中,不能使用全局的临时表
-530 23503 对特定的约束名指定了无效的外健值
-531 23504 从版本5开始,父关键字的多行更新将试图删除一个外关键字依赖的父关键字值,在版本5以前,当引用主关键值外健值当前存在时,试图更新该主健值
-532 23504 删除操作违反了已指定的参照约束
-533 21501 多行插入无效,试图将多行插到自我引用的表中
-534 21502 可改变主健列值的更新语句不能在同一时刻用于更新多行
-535 21502 当从自我引用表中删除数据或者更新主健列时,不能指定WHERE CURRENT OF。不是版本5的子系统才调用该代码
-536 42914 因为某一特定表的参照约束存在,所以删除语句无效
-537 42709 在外健语句或主健语句的规范中,每个列的出现不能多于一次
-538 42830 无效的外健;不符合引用的表没有主健
-539 42888 不能定义外健,因为被引用的表没有主健
-540 57001 表定义不完整,直到为主健建立了唯一索引或UNIQUE语句、或者包含GENERATED BYDEFAULT属性的ROWID列
-542 42831 可以为空的列不允许作为主健的一部分包含在内
-543 23511 因为该表是指定了SET NULL删除规则的参照约束的父表而且检查约束不允许NULL,所以DELETE不能发生
-544 23512 不能用ALTER添加检查约束,因为已存在的某行与该检查约束冲突
-545 23513 INSERT或者UPDATE导致检查约束冲突
-546 42621 在CREATE或ALTER TABLE中指定的检查约束无效
-548 42621 因为指定的列而引起的检查约束无效
-549 42509 DYNAMICRULES(BIND)计划或程序包的无效SQL语句
-551 42501 用户试图对不拥有权限的特定的对象进行操作,或者表不存在
-552 42502 用户试图执行未被授权的操作
-553 42503 不能指定CURRENT SQLID,因为用户尚没有被允许改变那个ID
-554 42502 不能对你本身赋予一个权限
-555 42502 不能对你本身撤销一个权限
-556 42504 不能撤销用户没有拥有的权限
-557 42852 指定了不一致的授予或撤销关键词
-558 56025 为授予或撤销语句指定了无效的语句(一个或一组)
-559 57002 DB2权限机制已经禁用,授予或者撤销不能被发布
-567 42501 指定的权限ID缺少对指定的程序包的绑定权限
-571 25000 不允许多点更新
-573 42890 不能定义参照约束,因为已指定的父表中在指定的列上没有唯一健
-574 42864 指定的缺省与列定义冲突
-577 38002 试图修改用户自定义函数中的数据或者存储过程中的数据,但这些对象的建立没有选择MODIFIES SQL DATA选项
-579 38004 试图修改用户自定义函数中的数据或者存储过程中的数据,但这些对象的建立没有选择READ SQL DATA选项,也没有选择MODIFIES SQL DATA选项
-580 42625 CASE表达式中的结果表达式不能都是空的
-581 42804 CASE表达式中的结果表达式为不兼容的数据类型
-582 42625 SEARCHED-WHEN-CLAUSE中的查找条件指定了一个限定的、IN或EXISTS谓词
-583 42845 指定的函数失败,因为他不是决定性的,或者可能有外部动作
-585 42732 在当前路径中模式名不止一次出现
-586 42907 CURRENT PATH专用寄存器在长度上不能超过254字符
-587 428C6 项目引用的列表必须是同一个家族
-590 42734 在命名的存储过程或用户自定义的函数中的参数必须是独一无二的
-592 42510 没有授权权限,让你在WLM环境中建立的存储过程或者用户自定义函数
-601 42710 试图创建(或重命名)已经存在的对象
-602 54008 CREATE INDEX语句中指定的列太多
-603 23515 因为发现有重复值,所以不能建立唯一的索引
-604 42611 在CREATE或ALTER TABLE语句中的为数据类型指定的长度、精度以及标度无效
-607 42832 指定的INSERT、UPDATE或DELETE语句不能被发布,应为这些语句对DB2 CATLOG表执行写操作
-611 53088 当LOCKSIZE是TABLE或者TABLESPACE时,LOCKMAX必须为0
-612 42711 在同一个表、索引或试图中不允许有重复列名
-613 54008 主健或UNIQUE约束太长或者包含了太多的列
-614 54008 已经超过了索引的内部健长度的最大长度(255)限制
-615 55006 不能删除这个程序包,因为该程序包目前正在执行
-616 42893 指定的对象不能被删除,因为其他对象依赖于该对象
-617 56089 对于DB2版本6,1型索引无效。对于以前的版本,1型索引不能用LOCKSIZE ROW或LARGE表空间定义
-618 42832 对DB2 CATALOG表的请求操作时不允许的
-619 55011 DSNDB07不能修改,除非他先被停止了
-620 53001 对在DSNDB07中的表空间不允许指定该关键词
-621 58001 遇到了重复的DBID,遇到了系统问题
-622 56031 不能指定FOR MIXED DATA因为没有安装混合数据选项
-623 55012 不能为单一的表定义多个族索引
-624 42889 不能为单一的表定义多个主健
-625 55014 用主健定义的表要求唯一索引
-626 55015 不能发布ALTER语句来改变PRIQTY SECQTY或ERASE,除非先停止了表空间
-627 55016 不能发布ALTER语句来改变PRIQTY SECQTY或ERASE,除非先把表空间定义为使用存储器组的表空间
-628 42613 指定语句时相互排斥的(例如,不能分区一个分段的表空间)
-629 42834 因为该外健不能包含空值,所以SET NULL无效
-630 56089 不能为1型索引指定WHERE NOT NULL
-631 54008 无效的外健;要么是比254个字节长,要么包含的列数多于40
-632 42915 指定的删除规则禁止把这个表定义为已制定表的从属表
-633 42915 无效删除规则;必须使用特定的强制删除规则
-634 42915 在这种情况下,DELETE CASCADE不允许
-635 42915 删除规则不能有差异或者不能为SET NULL
-636 56016 在分区索引健的升序或降序规范中,分区所以必须与该规范一致
-637 42614 遇到重复的关键词
-638 42601 在CREATE TABLE语句中缺少列定义
-639 56027 带有SET NULL的删除规则的外健的可空列不能是分区索引的列
-640 56089 不能为这个表空间指定LOCKSIZE ROW,因为在该表空间中的表上定义了1型索引
-642 54021 唯一约束包含太多的列
-643 54024 检查约束超出了3800个字符的最大长度
-644 42615 在SQL语句中为关键词指定的值无效
-646 55017 在指定的分区表空间或者缺省表空间中不能创建表,因为指定的表空间已经包含了一个表
-647 57003 指定的缓冲池无效,因为他没有被激活
-650 56090 ALTER INDEX不能被执行;提供了原因代码
-651 54025 如果CREARE或ALTER TABLE被允许,表对象的描述词(object descriptor,OBD)将超过最大值(32KB)
-652 23506 遇到了EDITRPROC或VALIDPROC冲突
-653 57004 在分区表空间中的表不可用,因为分区索引尚未被创建
-655 56036 在卷的列表中,STOGROUP不能指定为特定的或不特定(“*”)的卷
-658 42917 当试图删除指定的对象时,无法删除该对象,该对象的删除必须通过删除与之相关联的对象完成
-660 53035 不正确的分区索引规范,必须为族索引定义有限制的关键字
-661 53036 分区索引没有指定恰当的分区数目
-662 53037 试图在未分区的表空间(分段的或简单的)上建立分区索引
-663 53038 为分区索引指定的关键字限制值是一个无效数字
-665 53039 为ALTER TABLESOACE语句指定了无效的PART语句
-666 57005 SQL语句不能被处理,因为指定的函数当前正处于进行过程中
-667 42917 不能明确的删除分区表空间的族索引,必须除去分区表空间来去掉分区索引
-668 56018 不能向用EDITPROC定义的表中添加列
-669 42917 不能显式的删除分区表空间中的表,必须删除分区表空间来删除表
-670 54010 表的记录长度超过了页面的大小
-671 53040 不能更改指定的表空间的缓冲池,因为这将改变表空间的页面大小
-672 55035 在命名的表上不允许DROP
-676 53041 只有4KB的缓冲池可被用于一个索引
-677 57011 缓冲池扩展失败,由于可用的虚拟内存的大小不足
-678 53045 为才分区索引中指定的限制健提供的值与数据类型不符
-679 57006 不能创建某一个特定对象,因为该对象的一个drop目前正在挂起
-680 54011 对DB2表不能超过750列
-681 23507 列违反了指定的FIELDPROC
-682 57010 不能载入FIELDPROC
-683 42842 列、单值类型、函数或者过程无效,因为不兼容语句。例如,指定的INTEGER具有FORBITDATA选项
-684 54012 指定的文字列表不能超过254个字节
-685 58002 FIELDPROC返回一个无效的域描述
-686 53043 用FIELDPROC定义的一个列不能与一个使用不同的FIELDPROC定义的列作比较
-687 53044 列不能与一个非兼容字段类型的列比较
-688 58002 返回不正确的数据
-689 54011 从属表定义了太多的列
-690 23508 数据定义的控制支持拒绝这个语句
-691 57018 命名的注册表不存在
-692 57018 命名的索引不存在,但命名的注册表需要该索引
-693 55003 命名的注册表/索引的命名列无效
-694 57023 DROP正在命名的注册表上挂起
-696 42898 由于相关的名字或者转换表的名字使用不正确,指定的触发器无效
-697 42899 FOR EACH语句被指定,因此与OLD合NEW相关的名字是不允许的,或者不能为一个BEFORE触发器指定OLD_TABLE和NEW_TABLE
-713 42815 指定的专用寄存器是无效的
-715 56064 命名的程序不能被运行,因为他依赖与你所安装的DB2版本的部件,但是你的数据中心没有安装这个部件
-716 56065 命名的程序使用这个版本的不正确的发行版本做了预编译
-717 56066 BIND失败,因为他依赖与你所安装的DB2版本的部件,但是你的数据中心没有安装这个部件
-718 56067 REBIND失败,因为IBMREQD列无效
-719 42710 不能BIND ADD一个已经存在的程序包
-720 42710 不能BIND REPLACE一个已经存在的程序包版本
-721 42710 程序包的一致性记号必须是独一无二的
-722 42704 绑定错误,因为指定的程序包不存在
-723 09000 一个触发的SQL语句接受到一个错误
-724 54038 达到了(16)级联间接的SQL语句的最大项目
-725 42721 对专门指定的寄存器提供了一个无效值
-726 55030 因为SYSPKSYSTEM条目,不能绑定这个程序包
-728 56080 指定的数据类型不能与私有协议发布一起使用
-729 429B1 用COMMIT ON RETURN定义的存储过程不能用作嵌套的CALL过程的目标
-730 56053 在只读的共享数据库中为表定义的参照完整性无效
-731 56054 VSAM数据集必须用SHAREOPTION(1.3)定义
-732 56055 被定义为只读型数据库却拥有没有定义空间或者索引空间的DB2子系统
-733 56056 只读共享数据库的定义不一致
-734 56057 一旦一个数据库被定义为ROSHARE READ,他将不能被更改为其他不同的ROSHARE状态
-735 55004 用DBID名称标识的数据库不再是一个只读共享数据库
-736 53014 命名的DBID无效
-737 53056 在这种状况下,不能建立一个隐含的表空间
-739 56088 因为同时指定了ALLOW PARALLEL和MODIELES SQL DATA这两个语句,因此已设定的函数将不能再被更改
-740 51034 在这种方式下不能用MODIELES SQL DATA定义指定的函数
-741 55030 已经为命名的共享组成员的数据定义了工作文件数据库
-742 53004 DSNDB07是隐含的工作文件数据库
-746 57053 在特定的触发器、存储过程或函数中的SQL语句违反嵌套SQL限制
-747 57054 指定的表是不可用的除非为LOB数据列建立起必须的辅助表
-748 54042 在指定的辅助表上已经有一个索引
-750 42986 不能对已指定的表重新命名,因为他至少在一个现存的视图或触发器中被引用
-751 42987 存储过程或用户自定义的函数试图执行一个不允许执行的SQL语句。DB2的线程被置于MUST_ROLLBACK状态
-752 0A001 无效CONNECT语句
-763 560A1 无效的表空间名
-764 560A2 LOB表空间必须与其相关的基表空间同在一个数据库中
-765 560A3 表和数据库不兼容
-766 560A4 不能对辅助表进行请求的操作
-767 42626 CREATE INDEX失败,因为在辅助表中为索引指定了列,或者因为没有为非辅助表的索引指定列
-768 560A50 不能为指定的列或者指定的分区建立辅助表,因为其辅助表已经存在
-769 53096 CREATE AUX TABLE的规格与基表不匹配
-770 530A6 指定的表必须有一个ROWID列,那么该表才可以包含一个LOB列
-771 428C7 无效的ROWID列规范
-797 42987 CREATE TRIGGER包含不被支持的语法
-798 428C9 不能把一个值插入到用GENERATED ALWAYS定义的ROWID列
-802 22012 某一特定操作发生了异常错误。被零除

22003 某一特定操作发生了异常错误。但不是被零除
-803 23505 不能插入行,因为这将违反唯一索引的约束
-804 07002 SQLDA的调用参数列表有误
-805 51002 在计划中没有发现DBRM或程序包名
-807 23509 对已指定的环境和连接,该程序包不可用
-808 08001 CONECT语句与程序中的第一个CONNECT语句不一致
-811 21000 当多行作为一内嵌的选择语句的返回结果是,必须使用游标
-812 22508 在CURRENT PACKAGESET中的ID集合是空白的,语句不能被执行
-815 42920 在一个内置选择语句或者一个基本谓词的子查询中,显式的或隐含的指定了GROUP BY或HAVING语句
-817 25000 执行SQL语句将可能导致禁止更新用户数据或DB2编目
-818 5103 计划<->载入组件的时间戳不匹配,在执行计划中没有从同一个预编译中建立DBRM,该预编译是作为组件载入的
-819 58004 视图不能重建,因为在DB2编目中存储的分析树长度为0
-820 58004 在这个DB2版本的DB2编目中遇到了无效值
-822 51004 在SQLDA中遇到了无效地址
-840 54004 在选择列表或插入列表中返回的项目太多
-842 08002 到指定位置的连接已经存在
-843 08003 SET CONNECTION或RELEASE语句无法执行,因为连接不存在
-870 58026 宿主变量描述符的个数不等于语句中宿主变量的个数
-872 51302 这个子系统已指定了有效的CCSID
-873 53090 同一SQL语句中,不能同时引用EBCDIC表中的定义的列和ASCII表中定义的列
-874 53901 指定对象的编码方案与其表空间的编码方案不匹配
-875 42988 指定的操作符不能用于ASCII数据
-876 53092 不能为指定的原因创建对象:提供了原因代码
-877 53093 数据库或表空间不允许用ASCII,必须使用EBCDIC
-878 53094 该PLAN——TABLE不能是ASCII,必须使用EBCDIC
-879 53095 指定对象的CREATE或ALTER语句不能将列、单值类型,某个存储过程或用户自定义函数的参数定义为以下类型:MAXED DATA,GRAPHIC,VARGRAPHIC,LONGVARGRAPHIC,因为系统没有为指定的编码方案定义相应的CCSID
-900 08003 应用处理没有连接到应用服务器,语句不能被执行
-901 58004 遇到时断时续的系统错误,该错误不能抑制后继的SQL语句的执行
-902 58005 内部控制块的指针错误,要求重新绑定
-904 57011 指定的资源不可用
-905 57014 超出了资源上限
-906 51005 因为重大错误,SQL语句无法执行
-908 23510 当前资源限制设施的规范或者自动重绑定的系统参数不允许BIND,REBIND,AUTOREBIND
-909 57007 对象已被删除
-910 57007 因为在该对象上挂起DROP,所以不能访问该对象
-911 40001 当前工作单元已被回滚
-913 57033 因为死锁或超时导致不成功执行
-917 42969 绑定程序包已经失败
-918 51021 SQL语句不能被执行,因为连接丢失
-919 56045 需要一个ROLLBACK
-922 42505 连接权限失败。试图从TSO、CICS或IMS访问DB2,同时相应的连接设施处于非活动的状态
-923 57015 因为DB2不可用,所以不能建立连接
-924 58006 遇到了DB2内部的连接错误:提供了原因代码
-925 2D521 SQL的COMMIT语句不能从CICS或IMS/TM发布
-926 2D521 SQL的ROLLBACK语句不能从CICS或IMS/TM发布
-927 51006 当正在连接的环境没有建立时,语言接口被调用。利用DSN命令激发该程序
-929 58002 数据获取退出已经失败(DPROP)
-939 51021 由于远程服务器的未请求的回滚,要求一个回滚
-947 56038 SQL语句失败,因为更新不能被传播(DPROP)
-948 56062 DDF没有启动,分布式操作无效
-950 42705 在SQL语句中指定的位置在SYSIBM.LOCATIONS中没有定义
-965 51021 存储过程非正常终止(在DB2 6之前的版本)
-981 57015 当前不是处于允许SQL的状态时,试图在RRSAF中执行SQL
-991 57015 调用连接不能建立一个到DB2的隐含或开放连接
-2001 53089 为储存过程指定的宿主变量参数的个数不等于预期的参数个数
-20003 560A7 不能为GRECP中的表空间或索引指定GBPCACHE NONE
-20004 560A8 对于WORKFILE对象。8KB或16Kb的缓冲池页面大小无效
-20005 54035 指定的对象类型超出了内部的ID极限
-20006 53097 当没有指定WLM环境时,LOB不能被指定为参数
-20070 53098 不能非LOB列建立一个辅助表
-20071 53099 必须指定WLM环境名
-20072 56052 指定的权限ID不拥有在触发器程序包上执行BIND所需的权限
-20073 42927 不能按照指定的要求更改命名的函数,因为在现存的视图定义中引用了该函数
-20074 42939 不能建立指定的对象,因为“SYS”是一个保留的前缀
-20100 56059 在被触发的SQL语句中有BIND错误,指定了错误的SQLCODE和SQLSTATE
-20101 56059 由于指定的原因代码,该函数失败
-20102 42849 在CREATE或ALTER FUNCTION语句中不能使用指定的选项
-20104 42856 更改一个CCSID失败
-20106 42945 不能改变表空间或数据库的CCSID,因为现存的试图引用
-30000 58008 DRDA分布协议错误;处理可以继续
-30002 57057 使用DRDA的分布式客户把OPEN语句连接到PREPARE,但PREPARE接受到一个SQLCODE为+495的警告
-30020 58009 DRDA分布协议错误;对话被解除
-30021 58010 DRDA分布协议错误;处理不能继续
-30030 58013 违反分布协议:COMMIT不成功,对话被解除(AS)
-30040 57012 因为不能得到资源,执行失败,处理可以继续(AS)
-30041 57013 因为不能得到资源,执行失败,处理不能成功的继续(AS)
-30050 58011 执行不成功,在BIND过程中不能执行语句
-30051 58012 特定的BIND过程不是处于活动状态(远程BIND),从而导致失败
-30052 42932 程序准备的假设错误
-30053 42506 程序包的拥有者遭遇授权失败
-30060 08004 RBD遭遇授权失败
-30061 08004 指定了无效或者没有存在的RDB
-30070 58014 目标子系统不支持这个命令
-30071 58015 目标子系统不支持这个对象
-30072 58016 目标子系统不支持这个参数
-30073 58017 目标子系统不支持这个参数值
-30074 58018 应答信息不被支持
-30080 08001 SNA通信错误
-30081 58019 TCP/IP通信错误
-30082 08001 由于安全冲突、通信失败:提供了原因代码
-30090 25000 指定的操作对远程执行失败
-30104 56095 在绑定选项与绑定值中有错误
-30105 56096 指定的绑定选项不兼容
posted @ 2012-12-14 10:04 何杨 阅读(444) | 评论 (0)编辑 收藏

OI导出Excel文档时,可以设置很多格式效果,比如:边框,字体,颜色等等。
本文仅仅列出颜色的列表展示,方便大家查阅。  
颜色Class名称short

BLACK8

BROWN60

OLIVE_GREEN59

DARK_GREEN58

DARK_TEAL56

DARK_BLUE18

INDIGO62

GREY_80_PERCENT63

DARK_RED16

ORANGE53

DARK_YELLOW19

GREEN17

TEAL21

BLUE12

BLUE_GREY54

GREY_50_PERCENT23

RED10

LIGHT_ORANGE52

LIME50

SEA_GREEN57

AQUA49

LIGHT_BLUE48

VIOLET20

GREY_40_PERCENT55

PINK14

GOLD51

YELLOW13

BRIGHT_GREEN11

TURQUOISE15

SKY_BLUE40

PLUM61

GREY_25_PERCENT22

ROSE45

TAN47

LIGHT_YELLOW43

LIGHT_GREEN42

LIGHT_TURQUOISE41

PALE_BLUE44

LAVENDER46

WHITE9

CORNFLOWER_BLUE24

LEMON_CHIFFON26

MAROON25

ORCHID28

CORAL29

ROYAL_BLUE30

LIGHT_CORNFLOWER_BLUE31

AUTOMATIC64
posted @ 2012-12-13 23:36 何杨 阅读(624) | 评论 (0)编辑 收藏

如果RSA/Eclipse总是处于Building中,可能是错误的工程在Wrokspace中导致的,此问题严重起来可能导致无法使用RSA/Eclipse.
我的处置办法如下:
1.将“Build Automatically”取消。
2.关闭RSA/Eclipse,如果Building还在处理中,在任务管理器中找到Eclipse进程,Kill掉。
3.再次打开RSA/Eclipse,删除掉可能导致Building出错的工程。如果实在不清楚,全部删除之。
4.再启用“Build Automatically”选项,此时Build会开始,然后就正常结束了。

有的网文说在Eclipse启动时加入参数:   -vmargs -Xmx512M能解决问题,我试了无效,可能和他遇到的问题不是一个。
posted @ 2012-11-09 08:39 何杨 阅读(335) | 评论 (1)编辑 收藏

在Servers窗口中,右键点击服务器,弹出菜单中选“Administration”,再选“Run Administrative Console”,如下图:
posted @ 2012-11-09 08:05 何杨 阅读(423) | 评论 (0)编辑 收藏

在Servers窗口中,找到目标服务器,右键点击,在弹出菜单中选属性。第三项就包括了Was服务器的常规信息。
posted @ 2012-11-08 15:18 何杨 阅读(348) | 评论 (0)编辑 收藏

右键点击工程,选属性一项,找到“Web Project Setting”选项,在Context Root中输入新的context,图示如下:
posted @ 2012-10-18 14:30 何杨 阅读(245) | 评论 (0)编辑 收藏

点击菜单windows->Preferences->server->websphere
将Allow applications containing errors to be published on a server一项勾选。

如果不进行这项设置,在部署时会出现以下错误。

Publish failed with errors, warnings or both. Please see server logs for more details.

 The application contains validation errors. Correct the errors in the Problems view before publishing the application on the server. If you want to allow applications containing errors to be published on the server, enable the Allow applications containing errors to be published on a server check box (Windows > Preferences >Servers > WebSphere).

No start tag (<p>).

但愿你不是出错了再回来找的。J

posted @ 2012-10-17 13:58 何杨 阅读(346) | 评论 (0)编辑 收藏

下是使用RSA(Rational Software Architect)时的一个Tip,在这里写下来,希望能对那些遇到和我同样困扰问题的人有些帮助。

使用RSA开发web程序时,会需要把应用发布到容器中,但有时RSA是没有显示Servers窗口的,使用“Show View”菜单也见不到。
此时无需慌乱,切换到Web视图,再使用“Show View”菜单,servers窗口就显示出来了。
以下是切换到Web视图的图示:


以下是使用“Show View”菜单,显示servers窗口的图示

以下是Servers窗口显示出来的图示



就这么简单,可有时寸劲遇到了也能让人烦一阵的。

posted @ 2012-10-16 13:32 何杨 阅读(213) | 评论 (0)编辑 收藏

下载地址:
http://www.blogjava.net/Files/heyang/Utf8Test20120927.rar

转化效果:
%E4%BD%95%E6%9D%A8%E5%88%B0%E6%AD%A4%E4%B8%80%E6%B8%B8%EF%BC%81
何杨到此一游!

有时候也挺好玩的。
posted @ 2012-09-27 23:48 何杨 阅读(354) | 评论 (2)编辑 收藏

2012年6月21日15:21:59

程序代码下载:
http://www.blogjava.net/Files/heyang/ViewDsSample.zip
注意这个程序是RSA中的Dynamic Web Project


如果需要建立数据源,请参考:
http://www.blogjava.net/heyang/archive/2012/06/21/381257.html

如果需要建立JDBC Provider,请参考:
http://www.blogjava.net/heyang/archive/2012/06/21/381254.html

由于是示例代码,所以比较简单,功能就是访问数据库中一张表,然后把数据在表格中显示出来。index.jsp中的代码如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ page language="java" autoFlush="true" isThreadSafe="true" buffer="10kb" %>
<%@ page import="javax.servlet.http.*"%>
<%@ page import="java.util.*,java.lang.*,java.math.*"%>


<%@ page import="java.sql.Connection"%>
<%@ page import="java.sql.DriverManager"%>
<%@ page import="java.sql.Statement"%>
<%@ page import="javax.naming.Context"%>
<%@ page import="javax.naming.InitialContext"%>
<%@ page import="javax.sql.DataSource"%>
<%@ page import="java.sql.ResultSet"%>


<html>
    
<head>
        
<title>View DataSource In Was</title>
    
</head>
    
    
<body>
        
<table width="100px" border="1">
        
<caption>Visit the data in DataSource</caption>    
        
<thead>
        
<tr>
            
<td width="50px">Id</td>
            
<td width="50px">Name</td>
        
</tr>    
        
</thead>
        
<tbody>
        
<%
            Context ctx
= new InitialContext();
            DataSource ds 
= (DataSource) ctx.lookup("jdbc/localdb2");// 注意这里需要和数据源配置中的jndi名对应上。
            
            Connection con 
= ds.getConnection();
            
String sql = "select * from SYSTEM.TESTTB0619";
            
            Statement stmt 
= con.createStatement();
            ResultSet rs
=stmt.executeQuery(sql);
            
            
while (rs.next()) {
                
String id = rs.getString("id");
                
String name = rs.getString("name");
                
                out.println(
"<tr>");
                out.println(
"<td>"+id+"</td>");
                out.println(
"<td>"+name+"</td>");
                out.println(
"</tr>");
            }
            
            
            rs.close();
            stmt.close();
            con.close();
        
%>
        
</tbody>
        
</table>
    
</body>
</html>

首页显示效果如下:
posted @ 2012-06-21 15:25 何杨 阅读(342) | 评论 (0)编辑 收藏

2012年6月21日14:54:37

在进行以下步骤前需要先增加一个JDBC Provider,如果没有,请参考http://www.blogjava.net/heyang/archive/2012/06/21/381254.html

01.左边点"Resources"->"JDBC"->"Data Sources",右边点"New"。


02.DataSource名自己定,jndi名是要给程序用的,两方面要协调一致,下一个框是选访问数据库的用户名密码,没有可以新建一个。


03.这一步是选JDBC Provider,http://www.blogjava.net/heyang/archive/2012/06/21/381254.html一文中所有工作就是为了这一步。


04.这一步的参数除了Dirver type不用动之外,其它的按照你的实际情况输入。


05.这一步就是选Finish。


06.这一步就是要点Save。


07.测试一下,连接成功了。




好了,下一步可以在程序中测试这个数据源DataSource是否好用了。
posted @ 2012-06-21 14:53 何杨 阅读(321) | 评论 (0)编辑 收藏

2012年6月21日14:29:40

1.左边点"Resource">"JDBC">"JDBC Provider",右边点"New".


2.按图示的选项进行选择,Provider名字自己定。


3.这一步是找两个关键的jar所在的目录,一个是db2jcc.jar,一个是db2jcc_license_cisuz.jar,如果安装了Db2的话,这两个jar会出来。在我机器上,
它们位于C:\Program Files\IBM\SQLLIB\java和C:\Program Files\IBM\SQLLIB_01\java中。


4.这一步点Finish就行了。


5.最后完成了。


Provider是给DataSource用的,在下一节就会看到。

2012年6月21日14:36:36
posted @ 2012-06-21 14:28 何杨 阅读(435) | 评论 (0)编辑 收藏

网络上有很多网页父子窗口通信的文章,自己也曾写过,现在看来,问题应该简单化了,没有那么复杂。
只需要:
opener+函数+隐藏域   即可,这里的函数和隐藏域都是父窗口的。

比如说,子窗口要取父窗口的数据,可以在父窗口中做一个隐藏域,打开子窗口前把值存储好,再写一个函数来取得隐藏域中的值,子窗口中就能用opener+函数名来取得这个值了。
反过来,父窗口要取子窗口的数据,可以在父窗口中做一个函数,子窗口中数据就绪后直接opener+函数名调用这个函数即可,参数就是数据。

这样做,省去了很多麻烦。如果隐藏域不允许,那么再考虑别的方法不迟。
posted @ 2012-05-14 22:43 何杨 阅读(298) | 评论 (0)编辑 收藏

通常的网页编程原则是把形式,内容和表现分开,这样页面组件的事件处理就转移到了
window.onload或是Dom.onready中,写在一起。

有时,如果对页面组建进行删除或是更改id,会导致js出现错误,找不到组件,结果下面的正确js也无法执行了。
在进行页面调整阶段这个问题很常见。

当然,修改过来是正确的做法,另外我们还可以通过组件检测来做,这样的好处是页面调整后,js无需改变。
以下代码供参考:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
 
<head>
  
<title> New Document </title>
  
<meta name="Generator" content="EditPlus">
  
<meta name="Author" content="">
  
<meta name="Keywords" content="">
  
<meta name="Description" content="">
 
</head>

 
<body>
  
<button id="btn1">BTN1</button>
  
<br/>
   
<button id="btn2">BTN2</button>
 
</body>
</html>

<script type="text/javascript">
<!--

if(document.getElementById("btn1")){
    document.getElementById(
"btn1").onclick=function(){
        alert(
1);
    };
}

if(document.getElementById("btn2")){
    document.getElementById(
"btn2").onclick=function(){
        alert(
2);
    };
}

//-->
</script>
posted @ 2012-05-14 14:17 何杨 阅读(235) | 评论 (0)编辑 收藏


<html>
    
<head>

        
<title>123</title>    
        
<style>
        
</style>        

    
</head>
    
<body>
        
<div>123</div>
        
<div>456</div>

        
<script>
            
            
function test(object){
              
var tag = object.innerHTML;
              alert(tag)
            }
            
var divs = document.getElementsByTagName('div');
            
for(var i = 0, len = divs.length; i < len; i++){
                divs[i].onclick 
= function(){
                    test(
this)
                }
            }
            
        
</script>
    
</body>
</html>
posted @ 2012-04-28 10:20 何杨 阅读(284) | 评论 (0)编辑 收藏

ApplicationContext context=ContextLoader.getCurrentWebApplicationContext();

当Spring启动起来后,取得上下文可以如此处理,上述代码适宜放在静态构造子中,然后将值传给一个静态变量。
posted @ 2012-04-20 17:31 何杨 阅读(381) | 评论 (0)编辑 收藏

在Web程序中,url重写后后会出现CSS失效的情况,即页面元素都在,但给它们加上的样式都无效了。

原因:
一般是加载CSS文件的路径在翻页后处于错误的位置,这时可以用FireFox打开网页,查看网页源码,再点击CSS下方的链接,看是否能链接到CSS文件,链接不到是报错的。

处置:
在html开始前加上如下代码:
<%  
    
String path = request.getContextPath();  
    
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";  
%>
<html>
    
<head>
        
<base href="<%=basePath%>">
        
<title>XXX</title>

    
</head>

接下来其它的CSS,JS,IMG写好相对地址就好了。
posted @ 2012-04-20 12:04 何杨 阅读(665) | 评论 (0)编辑 收藏

工程下载本工程适用于MyEclipse

WAR文件下载本War已经与WAS6.1测试过

一些重要的代码
appctx.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    
<bean id="userService" class="com.service.UserService">
    
</bean> 

</beans>

UserController.java
package com.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.domain.User;
import com.service.UserService;

@Controller
@RequestMapping(
"/user")
public class UserController{
    @Autowired
    
private UserService userService;
    
    
    @RequestMapping(
"/register")
    
public ModelAndView createUser(User user){
        userService.register(user);
        
        ModelAndView mav
=new ModelAndView();
        
        mav.setViewName(
"registerOk");
        mav.addObject(user);
        
        
return mav;
    }
    
    @RequestMapping(
"/login")
    
public ModelAndView login(User user){
        userService.login(user);
        
        ModelAndView mav
=new ModelAndView();
        
        mav.setViewName(
"loginOk");
        mav.addObject(user);
        
        
return mav;
    }
}

User.java
package com.domain;


public class User{
    
private String userName;
    
    
private String userPswd;
    
    
public String getUserName() {
        
return userName;
    }
    
public void setUserName(String userName) {
        
this.userName = userName;
    }
    
public String getUserPswd() {
        
return userPswd;
    }
    
public void setUserPswd(String userPswd) {
        
this.userPswd = userPswd;
    }
}

UserService.java
package com.service;

import com.domain.User;


public class UserService{
    
public boolean login(User user){
        
return true;
    }
    
    
public boolean register(User user){
        
return true;
    }
}
spring-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context
="http://www.springframework.org/schema/context"
    xsi:schemaLocation
="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd   
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd   
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"
>

    
<context:annotation-config />
    
    
<!-- 扫描 com.controller下标记了@Controller注解的类 -->
    
<context:component-scan base-package="com.controller" />
    
    
<!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->
    
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

    
<!-- 视图名称解析器 p:prefix前缀是路径,p:suffix是扩展名-->
    
<bean
        
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
        p:prefix
="/" p:suffix=".jsp" />

    
<bean id="multipartResolver"
        class
="org.springframework.web.multipart.commons.CommonsMultipartResolver"
        p:defaultEncoding
="utf-8" />
</beans> 

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation
="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
>
    
<display-name>SpringMVCSample01</display-name>

    
<welcome-file-list>
        
<welcome-file>index.jsp</welcome-file>
    
</welcome-file-list>

    
<context-param>
        
<param-name>contextConfigLocation</param-name>
        
<param-value>classpath:appctx.xml</param-value>
    
</context-param>
    
<listener>
        
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    
</listener>

    
<servlet>
        
<servlet-name>spring</servlet-name>
        
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        
<load-on-startup>1</load-on-startup>
    
</servlet>
    
<servlet-mapping>
        
<servlet-name>spring</servlet-name> 
        
<url-pattern>*.html</url-pattern>
    
</servlet-mapping>
</web-app>

login.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    
<head>
        
<title>登录页面</title>
    
</head>

    
<body>
        登录
<br/>
        
<form method="post" action="<c:url value="/user/login.html"/>">
            
<input type="text" name="userName"/><br/>
            
<input type="password" name="userPswd"/><br/>
            
<input type="submit" name="提交">
        
</form>
    
</body>
</html>
loginOk.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    
<head>
        
<title>登录成功页面</title>
    
</head>

    
<body>
        用户${user.userName}登录成功
    
</body>
</html>
posted @ 2012-04-17 16:51 何杨 阅读(2823) | 评论 (1)编辑 收藏

时不时有人说ImSample下载失效了,搞了个新地址,有要的自己去下载吧。
http://www.blogjava.net/Files/heyang/IMSample2012-4-11.rar
posted @ 2012-04-10 14:01 何杨 阅读(450) | 评论 (5)编辑 收藏

下载地址:
posted @ 2012-03-27 13:36 何杨 阅读(288) | 评论 (0)编辑 收藏

     摘要:                 IBM GDC DL Teambiz后台开发规范 (2012年3月9日修订版)                 撰写:何杨 2012年3月9日   &nb...  阅读全文
posted @ 2012-03-14 10:25 何杨 阅读(470) | 评论 (0)编辑 收藏

 

 

 

 

 

 

Teambiz中前台开发规范

 

 

 

 

 

 

 

作者:何杨

撰写日期:2012年3月9日

版本:1.00

更新日期:  

 

 

第一部分:规范目的

为了提高团队协作效率, 提高前台页面文件的可读性,可维护性和一致性,从而方便前后台人员维护管理, 输出高质量的文档, 特制订此文档.

本规范文档一经讨论确认, 前端开发人员必须按本文档规范进行前台页面开发. 如在执行过程中,文档确有不合时宜的地方,可及时提出, 经会议讨论后决定可以更改此文档后再执行。

第二部分:基本准则

符合web标准, 语义化html, 结构表现行为分离, 兼容性优良. 页面性能方面, 代码要求简洁明了有序, 尽可能的减小服务器负载, 保证最快的解析速度.

程序员应该书写项目组所有人都可以看的懂的代码. 简洁易懂是一种美德. 在你们编写程序时必须时刻为用户着想, 为服务器着想.

第三部分:前台分离制度

我们认为,前台页面混乱的根源之一在于一个页面担负了太多的任务。因此,必须把页面的结构,样式,行为三部分解构开来,这三部分的命名如下:

类型

名称

担负任务

说明

JSP

*.jsp

网页的结构

以下简称JSP

CSS

style.css

网页样式

以下简称CSS

JS

javascript.jsp

网页行为

以下简称JS

 

第四部分:JSP文件书写规范

1. 文档类型声明及编码: 统一为html5声明类型<!DOCTYPE html>; 编码统一为<meta charset="utf-8" />, 书写时利用IDE实现层次分明的缩进;

2. 非特殊情况下样式文件必须外链至<head>...</head>之间;非特殊情况下JavaScript文件必须外链至页面底部; 

3. 引入样式文件或JavaScript文件时, 须略去默认类型声明, 写法如下:

<link rel="stylesheet" href="..." />

<style>...</style>

 

<script src="..."></script>

4. 所有编码均遵循xhtml标准, 标签 & 属性 & 属性命名 必须由小写字母及下划线数字组成, 且所有标签必须闭合, 包括br (<br />), hr(<hr />)等; 属性值必须用双引号包括;

5. 充分利用无兼容性问题的html自身标签, 比如span, em, strong, optgroup, label,等等; 需要为html元素添加自定义属性的时候, 首先要考虑下有没有默认的已有的合适标签去设置, 如果没有, 可以使用须以"data-"为前缀来添加自定义属性,避免使用"data:"等其他命名方式;

6.结构化JSP,示例如下

<div id=”mainMenu”>

<ul>

<li><a href=”#”>首页</a></li>

<li><a href=”#”>介绍</a></li>

<li><a href=”#”>服务</a></li>

</ul>

</div>

很多编译器提供了格式化的工具对代码整形,希望多加利用.如果机器整形效果不如手动整形,请进行手动整形.

6. 尽可能减少冗余的div嵌套, 如<div class="box"><div class="welcome">欢迎访问XXX, 您的用户名是<div class="name">用户名</div></div></div>完全可以用以下代码替代: <div class="box"><p>欢迎访问XXX, 您的用户名是<span>用户名</span></p></div>;

9. 书写链接地址时, 必须避免重定向,例如:href="http://www.baidu.com/", 即须在URL地址后面加上“/”;

10. 在页面中尽量避免使用style属性,即style="…"; 如果需要初始化某元素的style属性,请在CSS中设置或是在JS函数window.onload中设置。

11. 能以背景形式呈现的图片, 尽量写入css样式中;

12. 给区块代码及重要功能(比如表格展现)加上注释, 方便后台添加功能;

第四部分:CSS文件书写规范

1. 文件编码统一为utf-8;

2.结构化CSS,如下

html,body {

            height:100%;

            margin:0px;

            font-size:12px;

}

body{

            margin-top: 5px;

            margin-bottom: 5px;

            margin-left: 5px;

            margin-right: 5px;

            text-align: center;

            font-size: 12px;       

            font-family:"宋体","Tahoma";

            background:#ffffff;             

            overflow-y:hidden;

}

img{

            border:0px;  

}

#header{

            margin:0px;

            padding:0px;

            border:0px solid #00ff00; 

            width:100%;

            height:75px;

            overflow:hidden;

}

2. 协作开发及分工: 架构师会根据各个模块, 同时根据页面相似程序, 事先写好大体框架文件, 分配给前端人员实现内部结构&表现&行为; 共用css文件style.css由架构师书写, 协作开发过程中, 每个页面请务必都要引入,此文件不可随意修改;

3. class与id的使用: id是唯一的并是父级的, class是可以重复的并是子级的, 所以id仅使用在大的模块上, class可用在重复使用率高及子级中;

4. class与id命名:命名要语义化,简明化,尽量使用简易的单词组合; 避免使用中文拼音,以下是约定俗成的一些命名例子,请多加利用:

名称

Id

名称

Id

页 眉

header

内 容

content

容 器

container

页 脚

footer

版 权

copyright

导 航

menu

主导航

mainMenu

子导航

subMenu

标 志

logo

标 语

banner

标 题

title

侧边栏

sidebar

搜 索

search

按 钮

btn

登 录

login

链 接

link

常用类的命名应尽量以常见英文单词为准,做到通俗易懂,并在适当的地方加以注释。对于二级类/ID命名,则采用组合书写的模式,后一个单词的首字母应大写:诸如“搜索框”则应命名为“searchInput”、“搜索图标”命名这“searchIcon”、“搜索按钮”命名为“searchBtn”。

5. css属性书写顺序, 建议遵循 布局定位属性-->自身属性-->文本属性-->其他属性. 此条可根据自身习惯书写, 但尽量保证同类属性写在一起. 属性列举: 布局定位属性主要包括: margin & padding & float(包括clear) & position(相应的 top,right,bottom,left) & display & visibility & overflow等; 自身属性主要包括: width & height & background & border; 文本属性主要包括: font & color & text-align & text-decoration & text-indent等;其他属性包括: list-style(列表样式) & vertical-vlign & cursor & z-index(层叠顺序)  & zoom等. 我所列出的这些属性只是最常用到的, 并不代表全部;

6. 书写代码前, 考虑并提高样式重复使用率;

7. 充分利用html自身属性及样式继承原理减少代码量, 比如:

<ul class="list"><li>这儿是标题列表<span>2010-09-15</span></ul>

定义

ul.list li{position:relative} ul.list li span{position:absolute; right:0}

即可实现日期居右显示.

8. 必须为大区块样式添加注释, 小区块适量注释;

9. 代码缩进与格式: 建议单行书写;

第五部分:JS文件书写规范

1. 文件编码统一为utf-8, 书写过程过, 每行代码结束必须有分号; 原则上所有功能均根据XXX项目需求原生开发, 以避免网上down直接宕下来的代码造成的代码污染;

2. 库引入: 原则上仅引入prototype库, 若需引入第三方库, 须与团队其他人员讨论决定;

3. 变量命名: 驼峰式命名. 原生JavaScript变量要求是纯英文字母, 首字母须小写, 如counter;另, 要求变量集中声明, 避免全局变量.

4. 类命名: 首字母大写, 驼峰式命名. 如 Counter;

5. 函数命名: 首字母小写驼峰式命名. 如add(count);

6. 命名语义化, 尽可能利用英文单词或其缩写;

7. 后期优化中, JavaScript非注释类中文字符须转换成unicode编码使用, 以避免编码错误时乱码显示;

8. 代码结构明了, 加适量注释. 提高函数重用率;

第六部分:注释规范

1. html注释: 注释格式 <!--这儿是注释-->, '--'只能在注释的始末位置,不可置入注释文字区域;

2. css注释: 注释格式 /*这儿是注释*/;

3. JavaScript注释, 单行注释使用'//这儿是单行注释' ,多行注释使用 /* 这儿有多行注释 */;示例:

/*****************************************************

* 将数组arr转化成为tableDatas

* 此举是为了更方便解析数据

* 何杨,2012年2月7日14:03:43

*****************************************************/

function getTableDatasFromArr(arr){

            var tableDatas=new Array();         

            // 遍历这个数组

            for(var i=0;i<arr.length;i++){

                        var node=arr[i];

                        var arr2=new Array();

                        for(var j=0;j<node.childNodes.length;j++){

                                    var child=node.childNodes.item(j);                                            

                                    arr2.push(child.childNodes[0].nodeValue);

                        }

                        // 向表格中添加行

                        tableDatas.push(arr2);

            }          

            return tableDatas;

}

posted @ 2012-03-14 10:24 何杨 阅读(220) | 评论 (0)编辑 收藏

http://www.llxxb.com/upload/source/Teambiz2012-2-29.rar

在此感谢 雷振杰  提供为此提供空间!
posted @ 2012-02-29 11:23 何杨 阅读(303) | 评论 (1)编辑 收藏

 

 

 

 

 

 

Teambiz中前台表单验证组件FormChecker

 

 

 

 

 

 

 

作者:何杨

撰写日期:2012年2月27日

版本:1.00

更新日期:  

 

 

第一部分:功能说明

对前台页面的表单组件(对于所有用.value能取到值的组件都适用)提供正则表达式验证功能。

第二部分:核心组件

名称

路径

说明

CheckItem

teambiz\WebRoot\page\js\formchecker.js

这个类表示一个页面检查项,参数有表单组件id,当不合法时提示的文字,验证表单组件内容的正则表达式和表征组件是否必填字段。

在页面中增添验证项时常会遇到这个类。

FormChecker

teambiz\WebRoot\page\js\formchecker.js

这个类表示一个前台组件正则表达式验证器。内含一个数组,以容纳多个验证项(CheckItem)

addCheckItem

teambiz\WebRoot\page\js\formchecker.js

FormChecker的数组中增添一个验证项。

在页面中增添验证项时常会遇到这个类。

checkTextBox

teambiz\WebRoot\page\js\formchecker.js

对一个checkItem进行检查,如果它是必填组件,使用正则表达式验证它,并返回验证的结果;如果它不是必填组件,且没有输入内容的话,返回真,否则依然按照正则表单时来验证它。


 

isValid

teambiz\WebRoot\page\js\formchecker.js

FormChecker的数组进行循环并逐个使用checkTextBox函数进行检查,当所有的检查项都符合验证条件后返回真;如果有一个检查项不符合条件,使用alert显示提示文字并将焦点至于该组件上。

用户在提交表单前应该调用这个函数得到表单的验证结果。

 

第三部分:CheckItem和FormChecker两个类的代码

以下代码请参见teambiz\WebRoot\page\js\ formchecker.js中同名函数

/*************************

*

*   Class:CheckItem

*   2009.08.23

**************************/

//-- Contructor

function CheckItem(textboxName,msg,validChar,isRequired){

            this.textboxName=textboxName;

            this.msg=msg;

            this.validChar=validChar;

            this.isRequired=isRequired;

}

 

/*************************

*

*   Class:FormChecker

*   2009.08.23

**************************/

//-- Contructor

function FormChecker(){

            this.checkItemArray=new Array;

}

//-- Add a check Item to array

FormChecker.prototype.addCheckItem=function(textboxName,msg,validChar,isRequired){

            var checkItem=new CheckItem(textboxName,msg,validChar,isRequired);

            this.checkItemArray[this.checkItemArray.length]=checkItem;

};

//-- Check text field in the form

FormChecker.prototype.checkTextBox=function(checkItem){

            var validChar=checkItem.validChar;

            var isRequired=checkItem.isRequired;

            var inputValue=$(checkItem.textboxName).value;

           

            if(isRequired!="true" && inputValue.length<1){

                        return true;

            }

            else{

                        var regexStr="^"+validChar+"$";

                        var regex=new RegExp(regexStr);

                        return regex.test(inputValue);

            }

};

//-- judge the validation of a form

FormChecker.prototype.isValid=function(){

            for(var i=0;i<this.checkItemArray.length;i++){

                        var       toBeCheckedObj=this.checkItemArray[i];

                       

                        var checkResult=this.checkTextBox(toBeCheckedObj);

                       

                        if(checkResult==true){

                                    continue;

                        }

                        else{               

                                    alert(toBeCheckedObj.msg);

                                    $(toBeCheckedObj.textboxName).focus();

                                   

                                    return false;

                        }

            }

            return true;

};

第四部分:使用CheckItem和FormChecker进行验证的代码

以下代码请参考:teambiz\WebRoot\page\jsp\user\register\javascript.jsp

1.初始化FormChecker及添加验证项目

formChecker=new FormChecker();

formChecker.addCheckItem("userName","请输入二到五位汉字的用户名","[\\u4E00-\\u9FA5]{2,5}","true");

formChecker.addCheckItem("userPswd","请输5位以上,最长20位的字母或数字组成的密码","(\\w){5,20}","true");

formChecker.addCheckItem("userPswd2","请输5位以上,最长20位的字母或数字组成的密码","(\\w){5,20}","true");

formChecker.addCheckItem("email","请输入您的电子邮件","\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\.\\w+([-.]\\w+)*","true");

 

2.得到表单的验证结果

function getCheckResult(){

            // 进行页面输入检查

            if(formChecker.isValid()==false){

                        return false;

            }

           

            var userPswd=$("userPswd").value;

            var userPswd2=$("userPswd2").value;

           

            if(userPswd!=userPswd2){

                        $("userPswd2").focus();

                        alert("前后两次密码必须一致.");

                        return false;

            }

           

            return true;

}

以上粗体部分就是得到FormChecker的验证结果。由于FormChecker只能对单个组件的文本内容进行正则表达式校验,无法对对多个组件进行比较,因此如果实际需要其它的验证项,可以在getCheckResult函数中进行添加。

3.注册按钮点击时间后的响应函数:

$("registerBtn").onclick=function(){

            if(getCheckResult()==true){

                        submitForm();

            }

};

 

第五部分:使用步骤

步骤

说明

参照

载入这批函数

teambiz中,这一载入一般放在style.css中。

<script src="page/js/formchecker.js" type="text/javascript"></script>

window_onload函数中初始化表单验证器并增添检查项。

 

formChecker=new FormChecker();

formChecker.addCheckItem("userName","请输入二到五位汉字的用户名","[\\u4E00-\\u9FA5]{2,5}","true");

formChecker.addCheckItem("userPswd","请输5位以上,最长20位的字母或数字组成的密码","(\\w){5,20}","true");

formChecker.addCheckItem("userPswd2","请输5位以上,最长20位的字母或数字组成的密码","(\\w){5,20}","true");

formChecker.addCheckItem("email","请输入您的电子邮件","\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\.\\w+([-.]\\w+)*","true");

使用FormChecker的isValid函数来得到验证结果。

 

function getCheckResult(){

            // 进行页面输入检查

            if(formChecker.isValid()==false){

                        return false;

            }

           

            ……

           

            return true;

}

注册按钮点击时间后的响应函数

 

$("registerBtn").onclick=function(){

            if(getCheckResult()==true){

                        submitForm();

            }

};

 

第六部分:小结

进行表单元素验证是程序员不得不做却又较为乏味的工作之一,FormChecker类能有助于减轻他们的负担,从而使得用正则表达式验证文本内容的工作变得简单,程序员只需要在正则表达式的编写上下些功夫或者求助于网络。

FormChecker的不足之处是验证模式单一,验证逻辑比较简单,但对于验证,似乎也没有多少共性的需求了,如果有希望大家能赐教。

posted @ 2012-02-29 10:41 何杨 阅读(472) | 评论 (0)编辑 收藏

 

 

 

 

 

 

Teambiz中后台参数容器RequestParamMap

 

 

 

 

 

 

 

作者:何杨

撰写日期:2012年2月27日

版本:1.00

更新日期:  

 

 

第一部分:功能说明

简化页面请求参数的取值和存放,解决乱码问题,并简化数据传输通道上函数参数的编写。

第二部分:核心组件

名称

路径

说明

RequestParamMap

teambiz\src\com\ibm\heyang\action\base\RequestParamMap.java

它是一个页面请求参数的容器,内含一个哈希表,以键值对的方式来存储请求参数的名和值。

它的构造函数接受一个哈希表,这个哈希表在AjaxAction的getRequestParamMap函数中被生成,并传入强制子类实现的process函数中,因此每个继承自AjaxAction的类中直接使用RequestParamMap对象即可,无需考虑它的由来。

有一点需要说明的是,由于非ASC码字符在URL中是不允许的,因此在使用Ajax.Request对象发起请求前使用javaScript函数eval两次对url进行转码,与之对应的,在AjaxAction的getRequestParamMap函数中使用UTF8Coder类decode方法又将其还原了回来,因此程序员无需担心乱码问题。

getParamValue

teambiz\src\com\ibm\heyang\action\base\RequestParamMap.java中同名函数。

程序员可以参数名为单位,使用这个函数取出参数的值,当参数名不存在,即请求参数中没有后台想要的值,一个异常将被抛出。按照teamBiz的异常传递体系,这个异常会在用户界面上显示出来,这样做有助于问题的快速定位。

addParam

teambiz\src\com\ibm\heyang\action\base\RequestParamMap.java中同名函数。

程序员可以将参数名和参数值添加到RequestParamMap,设计这个函数的考虑到很多参数如用户信息在请求中往往是不见的,需要在Action中从session或是其它地方取出再往后方传递。

 

第三部分:有关RequestParamMap使用的代码

1. RequestParamMap类的代码

/**

 * 页面请求参数容器

 * @author 何杨(heyanghy@cn.ibm.com)

 * @version 1.00

 * @time Feb 6, 2012 10:47:39 AM

 *

 */

public class RequestParamMap{

            // 存储页面请求参数的哈希表

            private Map<String,String> map;           

            /**

             * 构造函数

             * @param map

             */

            public RequestParamMap(Map<String,String> map){

                        this.map=map;

            }          

            /**

             * 按请求参数的名称取得请求参数的值

             * @param paramName

             * @return

             */

            public String getParamValue(String paramName) throws IllegalArgumentException{

                        if(map.containsKey(paramName)){

                                    return map.get(paramName);

                        }else{

                                   throw new IllegalArgumentException("找不到名为"+paramName+"的页面请求参数.");

                        }

            }

           

            /**

             * 添加一个参数

             * @param paramName

             * @param paramValue

             */

            public void addParam(String paramName,String paramValue){

                        map.put(paramName, paramValue);

            }

}

以上代码路径:teambiz\src\com\ibm\heyang\action\base\RequestParamMap.java

 

2. AjaxAction的getRequestParamMap函数

private RequestParamMap getRequestParamMap(HttpServletRequest request){

            Map<String,String> map=new HashMap<String,String>();

           

            for (Enumeration<?> e = request.getParameterNames(); e.hasMoreElements();) {

                        String name = (String) e.nextElement();

                        String[] values = request.getParameterValues(name);

                       

                        if (values != null && values.length >= 1) {

                                    String value=UTF8Coder.decode(values[0]);

                                    map.put(name, value);

                        }

            }

           

            return new RequestParamMap(map);

}

以上代码路径:teambiz\src\com\ibm\heyang\action\base\AjaxAction.java

 

3.继承自AjaxAction的Action类中对RequestParamMap的使用

public final class FetchExecuterAction extends AjaxAction {

            private static Logger logger = Logger.getLogger(FetchExecuterAction.class);

           

            public void process(ActionMapping mapping, ActionForm form,

                                    HttpServletRequest request, HttpServletResponse response,RequestParamMap paramMap)

                                    throws Exception {

                        logger.trace("取得执行者名单Action");

                                   

                        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                        PrintWriter out = response.getWriter();

                                   

                        RelationService service=SpringUtil.getRelationService();

                        Long userId=(Long)request.getSession().getAttribute("userId");

                        if(userId!=null){

                                    paramMap.addParam("userId", String.valueOf(userId));

                                    paramMap.addParam("userName", "自己");

                                    paramMap.addParam("status", Relation.Status_Agree);

                                   

                                    String xml=service.getExecuterXml(paramMap);

                                   

                                    out.println("<response>");

                                    out.println("<status>ok</status>");

                                    out.println(xml);

                                    out.println("</response>");

                                   

                        }else{

                                    out.println("<response>");

                                    out.println("<status>ng</status>");

                                    out.println("<text>请登录后再来执行此操作</text>");

                                    out.println("</response>");

                        }

            }

}

以上代码来自:teambiz\src\com\ibm\heyang\action\relation\FetchExecuterAction.java

 

4.后台DAO类对RequestParamMap的使用

public String getExecuterXml(RequestParamMap paramMap) throws Exception{

            String userId=paramMap.getParamValue("userId");

            String userName=paramMap.getParamValue("userName");

            String status=paramMap.getParamValue("status");

           

            StringBuilder sb=new StringBuilder();

            sb.append("    select");

            sb.append("        tb01.toUserId as id,");

            sb.append("        tb02.name as name");

            sb.append("    from");

            sb.append("        teambiz_relation");

            sb.append("        tb01,");

            sb.append("        teambiz_user");

            sb.append("        tb02");

            sb.append("    where");

            sb.append("        tb01.toUserId=tb02.id");

            sb.append("        and");

            sb.append("        tb01.fromUserId="+userId+"");

            sb.append("        and");

            sb.append("        tb01.status='"+status+"'");

            sb.append("    order by");

            sb.append("        tb01.id");

            String sql=sb.toString();

           

            List<?> ls=fetchRecords(sql,new NameValueRowMapper());

           

            StringBuilder sb2=new StringBuilder();

            sb2.append(new NameValueList(ls).asXML());

            sb2.append("<node>");

            sb2.append("<id>"+userId+"</id>");

            sb2.append("<name>"+userName+"</name>");

            sb2.append("</node>");

           

            return sb2.toString();

}

以上代码来自:teambiz\src\com\ibm\heyang\dao\RelationDao.java

 

第四部分:小结

函数参数如果杂乱很不利于一些基类中共通函数的编写,比如分页函数,在RequestParamMap类的帮助下,这个问题能够得到解决。它附带的自动生成对象,解码,无参数时抛出异常要给程序中参数的取值,转码和异常处理带来了方便.

RequestParamMap类体积很小,功能也不复杂,但对后台的整个代码结构的改善带来了莫大好处,类似这种组件是值得发掘的。

 

posted @ 2012-02-29 10:41 何杨 阅读(399) | 评论 (0)编辑 收藏

 

 

 

 

 

 

Teambiz中与表格操作相关的函数

 

 

 

 

 

 

 

作者:何杨

撰写日期:2012年2月26日

版本:1.00

更新日期:  

 

 

第一部分:功能说明

提供向表格行的单元格中添加文本,链接,图片等是操作表格内容的常见操作函数。它们在诸如addDatasToTable之类的函数常常被使用。

第二部分:核心组件

名称

路径

说明

createTextTd

teambiz\WebRoot\page\js\dom.js中同名函数。

创建一个仅含文本的单元格。

createLink

teambiz\WebRoot\page\js\dom.js中同名函数。

创建一个链接,它是为createLinkTd函数准备的。

createLinkTd

teambiz\WebRoot\page\js\dom.js中同名函数。

创建一个仅含链接的单元格,当程序员需要在单元格中需要创建链接或是需要通过js伪协议调用js函数可以使用它。

createImageTd

teambiz\WebRoot\page\js\dom.js中同名函数。

创建一个仅含图片的单元格,当需要用图标表示数据的状态时可以使用它。

createTitledLink

teambiz\WebRoot\page\js\dom.js中同名函数。

创建一个带提示性说明(tooltiptext)的链接,它是为createTitledLinkTd函数准备的

createTitledLinkTd

teambiz\WebRoot\page\js\dom.js中同名函数。

创建一个包含提示性说明链接的单元格,它比createLinkTd更具用户友好型。

createIamgeLink

teambiz\WebRoot\page\js\dom.js中同名函数。

创建一个图片链接,它是为createImageLinkTd函数使用的。

createImageLinkTd

teambiz\WebRoot\page\js\dom.js中同名函数。

创建一个包含图片链接的单元格,如果图片比文字更加形象时可以考虑用它取代createLinkTd和createTitledLinkTd

createImageTextTd

teambiz\WebRoot\page\js\dom.js中同名函数。

创建一个兼具图片和文字说明的单元格。

createStartSearchRowBy

teambiz\WebRoot\page\js\changepage.js中同名函数。

创建一个colspan为40的表格行,内含图片和文字,一般在开始查询时使用。

createNgRowBy

teambiz\WebRoot\page\js\changepage.js中同名函数。

创建一个colspan为40的表格行,内含文字,一般从后台没有得到相要的数据时使用。

 

第三部分:实际代码

以下代码请参见teambiz\WebRoot\page\js\dom.js中同名函数

/******************************************************

* create a text cell

* 2011-3-1 9:27:07 heyang

******************************************************/

function createTextTd(text){

            var cell=document.createElement("td");

            cell.appendChild(document.createTextNode(text));  

            return cell;

}

 

/******************************************************

* create a image cell

* 2011-3-1 9:27:07 heyang

******************************************************/

function createImageTd(imageUrl){

            var cell=document.createElement("td");           

            var image=document.createElement("img");

            image.setAttribute("src",imageUrl);

            cell.appendChild(image);  

            return cell;

}

/******************************************************

* create a link

* 2011-3-1 9:27:07 heyang

******************************************************/

function createLink(text,url){

            var link=document.createElement("a");

            link.appendChild(document.createTextNode(text));

            link.setAttribute("href",url);          

            return link;

}

/******************************************************

* create a link cell

* 2011-3-1 9:27:07 heyang

******************************************************/

function createLinkTd(text,url){

            var link=createLink(text,url);

 

            var cell=document.createElement("td");

            cell.appendChild(link);       

            return cell;

}

/******************************************************

* create a titled link

* 2011-7-9 10:46:50 heyang

******************************************************/

function createTitledLink(text,title,url){

            var link=document.createElement("a");

            link.appendChild(document.createTextNode(text));

            link.setAttribute("href",url);

            link.setAttribute("title",title);       

            return link;

}

/******************************************************

* create a Titled link cell

* 2011-7-9 10:46:50 heyang

******************************************************/

function createTitledLinkTd(text,title,url){

            var link=createTitledLink(text,title,url);

            var cell=document.createElement("td");

            cell.appendChild(link);       

            return cell;

}

/******************************************************

* create a Iamge link

* 2011-3-1 9:27:07 heyang

******************************************************/

function createIamgeLink(imageUrl,url){

            var link=document.createElement("a"); 

            var image=document.createElement("img");

            image.setAttribute("src",imageUrl);       

            link.appendChild(image);

            link.setAttribute("href",url);          

            return link;

}

/******************************************************

* create a Iamge linked table cell

* 2011-3-1 9:27:07 heyang

******************************************************/

function createImageLinkTd(imageUrl,url){

            var cell=document.createElement("td");           

            cell.appendChild(createIamgeLink(imageUrl,url));      

            return cell;

}

/******************************************************

* create a Iamge and text cell

* 2012-1-9 10:31:31 heyang

******************************************************/

function createImageTextTd(imageUrl,text){

            var cell=document.createElement("td");           

            var image=document.createElement("img");

            image.setAttribute("src",imageUrl);

            cell.appendChild(image);  

            cell.appendChild(document.createTextNode(text));  

            return cell;

}

 

第四部分:使用步骤

步骤

说明

参照

载入这批函数

teambiz中,这一载入一般放在style.css中。

<script src="page/js/dom.js" type="text/javascript"></script>

根据实际情况使用这批函数

 

teambiz\WebRoot\page\jsp\task\sent\javascript.jsp中addDatasToTable函数,这个函数基本使用到了上面提到的所有函数。

 

第五部分:小结

使用DOM生成文字,链接,图片等元素是繁重的劳动,将它们归纳成函数有利于提高程序员的生产率,并把精力集中于更值得投放精力的方向上。

 

posted @ 2012-02-29 10:38 何杨 阅读(209) | 评论 (0)编辑 收藏

 

 

 

 

 

 

Teambiz中MyTable类

 

 

 

 

 

 

 

作者:何杨

撰写日期:2012年2月26日

版本:1.00

更新日期:  

 

 

第一部分:功能说明

帮助程序员更轻松的操作前台的表格。

第二部分:核心组件

名称

路径

说明

MyTable

teambiz\WebRoot\page\js\myTable.js

一个JavaScript类,用于操作表格。实际上,它代表的是table的tbody部分,而不包括caption,thead,tfoot。

MyTable

同上文件的同名函数

这是MyTable类的构造函数,传入tbody的id,得到表格的tbody部分。

clear

同上文件的同名函数

一次性删除tbody的所有行。

在查询开始前基本都有这一步以清除以往的数据。

removeFirstRow

同上文件的同名函数

删除tbody的第一行。

这个函数在实际中使用很少。

getRowCount

同上文件的同名函数

得到tbody中所有行的个数。

当需要计算当前显示多少行时可以用到。

appendRow

同上文件的同名函数

tbody底部添加一行,并且给奇偶行赋予不同的样式。

逐行往表格中添加数据时常用到它。

removeRow

同上文件的同名函数

删除tr的id为传入参数的行。

当删除对象成功时需要调用这一函数。

refreshRowColor

同上文件的同名函数

给奇偶行赋予不同的样式。

一般在appendRow和removeRow中被调用,外界也可主动调用。

 

第三部分:实际运用代码说明

以下代码请参见teambiz\WebRoot\page\jsp\relation\sent\javascript.jsp中search函数。

1. 得到表格并清除原有行

var userTable=new MyTable("userTable");

userTable.clear();

以上代码就是新建一个MyTable对象并清除原有行的过程,MyTable构造函数接受一个tbody的id,请与页面中tbody的实际ID相对应。

 

2. 向表格添加行

userTable.appendRow(createStartSearchRowBy("page/img/waiting.gif","开始查询已经发送的联系..."));

userTable.appendRow(createNgRowBy("没有查询到已经发送的联系."));

以上代码就是向tody中添加一个tr的过程,至于createStartSearchRowBy,createNgRowBy两个函数我们将在后文详述。

 

以上代码路径:teambiz\WebRoot\page\js\changePage.js

 

3. 向表格中添加一个完整的行。

var arr=tableDatas[i];                     

// 创建行

var row=document.createElement("tr");           

                       

// 加入复选框

var checkBox=document.createElement("input");

checkBox.setAttribute("type","checkbox");

checkBox.setAttribute("id",arr[0]);

 

var td=document.createElement("td");

td.appendChild(checkBox);                      

row.appendChild(td);        

 

row.appendChild(createTextTd(arr[1]));

row.appendChild(createTextTd(arr[2]));

row.appendChild(createTextTd(arr[3]));

row.appendChild(createTextTd(arr[4]));

row.appendChild(createTextTd(arr[5]));

row.appendChild(createTextTd(arr[6]));

 

userTable.appendRow(row);

以上代码完整显示使用DOM创建tr以及一个个td,并往td中添加对象的过程。根据实际情况的不同,我们可能会往行row中添加文本,链接,图片,图片链接等对象,TeamBiz为此类事务设计了一批函数以简化代码编写,这将在后面的文章详述。

 

以上代码位置:teambiz\WebRoot\page\jsp\relation\sent\javascript.jsp中addDatasToTable函数。

 

4.页面表格

<table class="stocktable" width="100%" cellspacing="0">

            <caption>

                        <select id="pageSizeCbo" onchange='fetchDatas(0)'>

                                    <option value="20">20</option>

                                    <option value="50">50</option>

                                    <option value="100">100</option>

                                    <option value="1000">1000</option>

                        </select>

            总记录数<span id="recordCount">0</span> 总页数<span id="pageCount">0</span> 当前第<span id="currentPage">0</span>页 <span id="pageData">0</span></caption>

            <thead>

                        <tr>

                                    <th width="28"><input type="checkbox" id="selectAllChk" onclick="selectAllCheckBox()"/></th>

                                    <th width="17%">发送用户</th>

                                    <th width="16%">接收用户</th>

                                    <th width="16%">接收用户邮件</th>

                                    <th width="16%">接收所属组名</th>

                                    <th width="16%">接收所属公司</th>

                                    <th width="16%">联系状态</th>

                        </tr>

            </thead>

            <tbody id="userTable">

                        <tr class="odd">

                                    <td colspan="40"><img src='page/jsp/relation/create/img/waiting.gif'/> 查询中,请稍候...</td>

                        </tr>

            </tbody>

             <tfoot>

                        <tr>

                                    <td colspan="40" align="right" width="100%">

                                                <div class="submitDiv">

                                                            <label for="gotoPageBtn">&nbsp;</label>

                                                            <input type='button' name='gotoPageBtn' onchange='gotoPage()' value='转到' />第<input type='text' id='pageIndexTxt' onchange='gotoPage()' size='1' />页&nbsp;页码:<span id="footPageData"></span>

                                                </div>

                                    </td>

                        </tr>

            </tfoot>

</table>

以上代码中,红色粗体部分的“userTable”就是需要往MyTable构造函数中传入的参数,而黑色粗体部分就是MyTable类诸函数实际操作的区域。

以上代码位置: teambiz\WebRoot\page\jsp\relation\sent\content.jsp

 

第四部分:使用步骤

步骤

说明

参照

载入MyTable类

teambiz中,这一载入一般放在style.css中。

<script src="page/js/myTable.js" type="text/javascript"></script>

创建MyTable对象

由于作用域的不同,这一过程可能会使用多次,但应该避免使用全局的myTable对象。

var table=new MyTable(“tableID”);

操作MyTable对象

使用teambiz\WebRoot\page\js\myTable.js中定义的多个函数操作表格对象,如果这些函数不能满足您的需求,可以参照原有行数的模式来创建新的函数。

 

 

 

 

第五部分:小结

表格是前台程序操作的主要对象之一,将表格的常用操作加以归纳综合,就形成了MyTable类,它能减少重复代码,减少出错的可能行,减轻劳动和增加代码的一致性,如果我们在编写程序时多加归纳总结,还会诞生出更多相似的类出来。

 

posted @ 2012-02-29 10:37 何杨 阅读(322) | 评论 (0)编辑 收藏

     摘要:             Teambiz中分页之前台处理               作者:何杨 撰写日期:2012年2月25日 版本:1.02 更新日期:  2012年2月27日     第一部分:功...  阅读全文
posted @ 2012-02-29 10:36 何杨 阅读(254) | 评论 (0)编辑 收藏

 

 

 

 

 

 

Teambiz中分页之后台处理

 

 

 

 

 

 

 

作者:何杨

撰写日期:2012年2月25日

版本:1.00

更新日期:  

 

 

第一部分:功能说明

分页是Web程序的常见功能之一,此文主要讲述后台对分页功能的处理。

第二部分:核心组件

名称

路径

说明

BaseService

teambiz\src\com\ibm\heyang\service\base\BaseService.java

此抽象类是诸Service类的基类,它提供了专用于分页的函数pagedSearch,用户只需传入相应的SQL语句,RequestParamMap实例和dao实例即可完成分页功能,实际上后两者一个是在AjaxAction中自动生成的,一个是Sping中配置的,因此,用户只需书写正确的查询SQL语句即可。

由于DB2数据库分页操作的特殊性,它需要分页时加入排序项,因此若数据源是DB2,那么请换用功能相似的pagedSearch4DB2函数。

JdbcDao

teambiz\src\com\ibm\heyang\dao\base\JdbcDao.java

此抽象类是诸Dao类的基类,它提供了getSqlCount,pageSearchList两个函数以实现分页功能,前者用于得到结果集的总数,后者用于取得某一页的结果集。

若数据库是DB2,请换用功能相似的pageSearchList4DB2。

 

第三部分:关键代码说明

1. BaseService中的pagedSearch函数:

public String pagedSearch(String sql,RequestParamMap paramMap,JdbcDao dao) throws Exception{

            int currentPage=Integer.parseInt(paramMap.getParamValue("start"));

            int pageSize=Integer.parseInt(paramMap.getParamValue("pageSize"));

           

            StringBuilder sb=new StringBuilder();

            sb.append("<currentPage>"+currentPage+"</currentPage>");

           

            // 取得总记录数

            long recordCount=dao.getSqlCount(sql);

            sb.append("<recordCount>"+recordCount+"</recordCount>");

           

            // 得到总页数

            long pageCount=0;

            if((recordCount % pageSize)==0){

                        pageCount=recordCount/pageSize;

            }

            else{

                        pageCount=recordCount/pageSize+1;

            }          

            sb.append("<pageCount>"+pageCount+"</pageCount>");

           

            NameValueList nvList=dao.pageSearchList(sql,currentPage*pageSize, (currentPage+1)*pageSize);

            sb.append(nvList.asXML());

           

            return sb.toString();

}

这个函数对数据库进行了两次查询,一次是取出SQL语句能得到的记录总数,一次是取出当前页的数据,另外从paramMap中取出了当前页和一页可以容纳的记录数等数据,有了这些数据,进行一点计算,就能获得前台页面需要的当前页,总记录数,页数和当前页记录等数据,最后此函数将所有数据都变换为XML格式的字符串。

 

2. JdbcDao的getSqlCount函数

public int getSqlCount(String sql) throws Exception{

            RecordCounter rc=new RecordCounter(sql,this.getJdbcTemplate());

            return rc.getCount();

}

这个类利用RecordCounter类对SQL语句进行了一定程序的处理,然后取出这个SQL语句能查询出的记录总数量,RecordCounter类代码如下:

public class RecordCounter{

            private String sql;

           

            private JdbcTemplate jdbcTemplate;

           

            /**

             * 构造函数

             * @param sql

             * @param jdbcTemplate

             */

            public RecordCounter(String sql,JdbcTemplate jdbcTemplate){

                        this.sql=sql;

                        this.jdbcTemplate=jdbcTemplate;

            }

           

            /**

             * 得到SQL语句查询到的记录数,对外的关键语句

             * @author: 何杨(heyanghy@cn.ibm.com)

             * @date : Apr 23, 2011

             * @time : 11:09:35 AM

             * @return

             */

            public int getCount() throws Exception{

                        StringBuilder sb=new StringBuilder();

                        sb.append("    select ");

                        sb.append("        count(*) as recordCount ");

                        sb.append("    from ("+sql+") t ");

                        String sql=sb.toString();

 

                        List<?> ls = jdbcTemplate.query(sql, (new IntegerRowMapper()));

                        Integer i=(Integer)ls.get(0);

                       

                        return i.intValue();

            }

}

以上代码路径:teambiz\src\com\ibm\heyang\dao\rowmapper\RecordCounter.java

 

3. JdbcDao类的fetchPageRecords和fetchPageRecords4DB2函数。

下面两个函数用于取出分页的数据,按照数据库的不同使用不同的部分或是换用不同的函数。

/**

 * 查询分页数据,如果是Oracle则放开上面一段,如果是MySql则放开下面一段

 * @author: 何杨(heyanghy@cn.ibm.com)

 * @date : Mar 29, 2011

 * @time : 3:34:44 PM

 * @param start

 * @param end

 * @param sql

 * @param mapper

 * @return

 */

protected final List<?> fetchPageRecords(int start,int end,String sql,RowMapper mapper){

            StringBuilder sb=new StringBuilder();

           

            // Oracle

            /*sb.append(" Select                              ");

            sb.append("        *                            ");

            sb.append(" from                                ");

            sb.append("        (                            ");

            sb.append("         Select                      ");

            sb.append("                t01.*,               ");

            sb.append("                rownum as newRowNum ");

            sb.append("         from                        ");

            sb.append("                (                    ");

            sb.append(sql);

            sb.append("                ) t01                ");

            sb.append("         where                       ");

            sb.append("                rownum<='"+end+"'    ");

            sb.append("        )                            ");

            sb.append(" where                               ");

            sb.append("        newRowNum>'"+start+"'        ");*/

           

            // MySql

            sb.append(sql+" limit "+start+","+(end-start));

            String sql2=sb.toString();

           

            return this.getJdbcTemplate().query(sql2,mapper);

}

 

/**

 * 专门为DB2制作的查询分页数据,特殊的地方是比上面的函数多了一个Order by

 * @param start

 * @param end

 * @param sql

 * @param orderBy

 * @param mapper

 * @return

 */

protected final List<?> fetchPageRecords4DB2(int start,int end,String sql,String orderBy,RowMapper mapper){

            StringBuilder sb=new StringBuilder();

           

            // Db2

            sb.append(" Select                              ");

            sb.append("        *                            ");

            sb.append(" from                                ");

            sb.append("        (                            ");

            sb.append("         Select                      ");

            sb.append("                table01.*,               ");

            sb.append("                ROW_NUMBER() OVER(ORDER BY "+orderBy+" ) AS ROWNUM ");

            sb.append("         from                        ");

            sb.append("                (                    ");

            sb.append(sql);

            sb.append("                ) table01 )               ");

            sb.append("         where                       ");

            sb.append("                ROWNUM >"+start+" and ");

            sb.append("                ROWNUM <="+end+" ");

 

            String sql2=sb.toString();

            return this.getJdbcTemplate().query(sql2,mapper);

}

 

第四部分:使用步骤

步骤

说明

参照

Dao类中编写需要进行分页查询的SQL语句,并用函数进行包装。

建议对SQL进行良好的整形。

teambiz\src\com\ibm\heyang\dao\RelationDao.java中的getSentRelationSql函数。

Service类中撰写调用dao中的分页查询函数

teambiz\src\com\ibm\heyang\service\RelationService.java中的pagedSearchMySentRelation函数。

Action中调用Service中的分页查询函数

如果需要在paramMap中增加新的参数,可以使用com.ibm.heyang.action.base.RequestParamMap类的addParam函数

teambiz\src\com\ibm\heyang\action\relation\SearchSentRealationAction.java类

 

第五部分:小结

后台的分页处理,实际上需要程序员动脑筋的地方就是SQL语句的编写,其它都是固定模式的操作,TeamBiz通过BaseService和JDBCdao两个类中相应函数的帮助,固化了这些固定的部分,程序员只要正确调用即可,这在一定程度上减轻了程序员的工作量,降低了人为出错的可能。

 

通过不同分页SQL语句的采用,TeamBiz能适应三种数据库,Oracle,MySQL和Db2,如果要增添更多数据库的支持,对分页SQL进行改写即可。

 

posted @ 2012-02-29 10:35 何杨 阅读(262) | 评论 (0)编辑 收藏

 

 

 

 

 

 

Teambiz中三种特殊RowMapper的使用

 

 

 

 

 

 

作者:何杨

撰写日期:2012年2月25日

版本:1.00

更新日期:

 

 

 

第一部分:功能说明

针对特殊目的的查询,TeamBiz提供了一系列的RowMapper类以减轻程序员的劳动。

第二部分:核心组件

名称

路径

说明

IntegerRowMapper

teambiz\src\com\ibm\heyang\dao\rowmapper\IntegerRowMapper.java

只需进行数量查询时,如select count(*) from tb,明确只会返回一行一列,这时建议使用这个类。

StringRowMapper

teambiz\src\com\ibm\heyang\dao\rowmapper\StringRowMapper.java

当只查询一列时,如select a from table,建议使用这个类。

UserRowMapper

eambiz\src\com\ibm\heyang\dao\rowmapper\UserRowMapper.java

当需要从JDBCTemplate查询到的链表中取出对象时,建议仿照这个类制作自己的RowMapper类

 

第三部分:各种RowMapper类的具体使用

1. IntegerRowMapper。

StringBuilder sb=new StringBuilder();

sb.append("    select ");

sb.append("        count(*) as recordcount");

sb.append("    from teambiz_menu");

String sql=sb.toString();

List<?> ls=this.getJdbcTemplate().query(sql, new IntegerRowMapper());

Integer count=(Integer)(ls.get(0));

以上代码路径:teambiz\src\com\ibm\heyang\dao\MenuDao.java中isNoMenu函数。

 

2. StringRowMapper

StringBuilder sb=new StringBuilder();

sb.append("    select");

sb.append("        t01.group_name");

sb.append("    from");

sb.append("        sys_group");

sb.append("        t01,");

sb.append("        sys_user");

sb.append("        t02");

sb.append("    where");

sb.append("        t01.groupid=t02.groupid");

sb.append("        and");

sb.append("        t02.userid="+userid+"");

String sql=sb.toString();

 

// 查询

List<?> ls = this.getJdbcTemplate().query(sql,new StringRowMapper());

最后得到的ls就是一个包含字符串元素的链表,要取值对其进行遍历即可。

3. UserRowMapper的使用示例

StringBuilder sb=new StringBuilder();

sb.append("    select ");

sb.append("          ID, ");

sb.append("          name, ");

sb.append("          email, ");

sb.append("          pswd, ");

sb.append("          groupName, ");

sb.append("          companyName,");

sb.append("          level");

sb.append("    from teambiz_user");

sb.append("    where name='"+name+"' and ");

sb.append("          pswd='"+pswd+"' ");

String sql=sb.toString();

 

List<?> ls = this.getJdbcTemplate().query(sql, (new UserRowMapper()));

 

if(ls.size()==1){

            return (User)ls.get(0);

}else{

            throw new Exception("用户名或密码错误!");

}

以上代码路径:teambiz\src\com\ibm\heyang\dao\UserDao.java中的getUserByNamePswd函数。

 

第四部分:小结

对数据库进行各种查询是程序员的常见任务之一,如果能适当运用以上类,能减少代码的重复程度及减轻他们的劳动强度。

posted @ 2012-02-29 10:34 何杨 阅读(368) | 评论 (0)编辑 收藏

 

 

 

 

 

 

Teambiz中从Sql到XML的转化过程

 

 

 

 

 

 

 

作者:何杨

撰写日期:2012年2月23日

版本:1.00

更新日期:2012年2月24日

 

 

第一部分:功能说明

将后台编写的SQL语句,向数据库请求后获得的数据,整理成XML格式的文本。

第二部分:核心组件

名称

路径

说明

JdbcDao

com.ibm.heyang.dao.base.JdbcDao

此类中的fetchRecords函数用来取得数据库中的数据,

NameValueRowMapper

com.ibm.heyang.dao.rowmapper.NameValueRowMapper

此类用于将进行数据库查询得到的行集转化为一个NameValue链表对象。

NameValue

com.ibm.heyang.domain.NameValue

此类用于存储行集中某字段的名称和值,在将对象链表转化为XML的过程中使用了它的函数asXML()。

NameValueList

com.ibm.heyang.domain.NameValueList

内含一个链表,用于容纳NameValue对象链表,在将对象链表转化为XML的过程中使用了它的函数asXML()。

 

第三部分:从SQL语句向XML的转化过程
NameValueRowMapper负责查询结果集一个行的转换,对于其中的每个字段,会形成一个字段名和字段值的NamaValue对象,然后放到一个类型为List<NameValue>的链表中。最终,这个链表对应着这个行集,链表里面的每个元素对应着一个字段(包含其名及值)。

NameValueList用于容纳每个行形成的链表,它本身和查询结果集是对应的。

得到最终的NameValueList之后,调用其asXML方法,将遍历其中的每个元素,得到行集链表,再遍历其中的NameValue对象,再调用每个对象的asXML函数,得到XML文本。

以下展示了两个关键函数:

NameValueList对象的asXML函数如下:

public String asXML() {

            StringBuilder sb=new StringBuilder();    

            for(Object obj:list){

                        List<NameValue> ls=(List<NameValue>)obj;              

                        sb.append("<node>");

                        for(NameValue nv:ls){

                                    sb.append(nv.asXML());

                        }

                        sb.append("</node>");

            }

            return sb.toString();

}

以上粗体部分是每个行的标志,在前台页面对XML进行解析时还要使用到它,这已经形成了前后台之间的一个约定。

NameValue对象的asXML函数如下:

public String asXML() {

            StringBuilder sb=new StringBuilder();

            sb.append("<"+name+">");

            sb.append(StringUtils.isBlank(value)?"-":value);

            sb.append("</"+name+">");       

            return sb.toString();

}

第四部分:效果展示

SQL语句示例:

select text, url, level from teambiz_menu where level<=2 order by level

使用SQL语句从数据库查询出来的结果集:


最终得到的XML文本:

<node>

            <text>登出</text>

            <url>Logout.do</url>

            <level>0</level>

</node>

<node>

            <text>修改自己信息</text>

            <url>Goto.do?page=/page/jsp/user/modify/index.jsp</url>

            <level>1</level>

</node>

<node>

            <text>建立联系</text>

            <url>Goto.do?page=/page/jsp/relation/create/index.jsp</url>

            <level>1</level>

</node>

<node>

            <text>我发出去的联系</text>

            <url>Goto.do?page=/page/jsp/relation/sent/index.jsp</url>

            <level>1</level>

</node>

<node>

            <text>发给我的联系</text>

            <url>Goto.do?page=/page/jsp/relation/received/index.jsp</url>

            <level>1</level>

</node>

<node>

            <text>创建任务</text>

            <url>Goto.do?page=/page/jsp/task/create/index.jsp</url>

            <level>1</level>

</node>

<node>

            <text>我发出去的任务</text>

            <url>Goto.do?page=/page/jsp/task/sent/index.jsp</url>

            <level>1</level>

</node>

<node>

            <text>发给我的任务</text>

            <url>Goto.do?page=/page/jsp/task/received/index.jsp</url>

            <level>1</level>

</node>

<node>

            <text>今日待办任务/已办任务</text>

            <url>Goto.do?page=/page/jsp/task/tododone/index.jsp</url>

            <level>1</level>

</node>

<node>

            <text>用户管理</text>

            <url>#</url>

            <level>2</level>

</node>

 

第五部分:使用步骤

步骤

说明

参照

编写SQL语句

编写一个正确的查询语句,建议使用SqlToolBox进行整形工作。

com.ibm.heyang.dao.MenuDao中的函数getMenuByUserLevel中的SQL语句。

使用fetchRecords函数得到结果集。

这个函数处于com.ibm.heyang.dao.base.JdbcDao类中,无需改动,只需要传入正确的sql语句和RowMapper即可。

com.ibm.heyang.dao.MenuDao中的函数getMenuByUserLevel中的List<?> ls=super.fetchRecords(sql,new NameValueRowMapper());一句。

将结果集用NameValueList包装起来

将结果集传入NameValueList类的构造函数即可。

com.ibm.heyang.dao.MenuDao中的函数getMenuByUserLevel中的return new NameValueList(ls);一句。

将结果集转化为XML

使用NameValueList类的asXML函数。

com.ibm.heyang.service.MenuService的getMenuByUserLevel函数。

 

第六部分:小结

编写SQL语句并将其转化为前台可以辨识的格式是程序员的主要工作负担,采用以上方式的好处有:

1.整个过程中,一个函数fetchRecords和三个对象NameValueRowMapper,NameValue,NameValueList都是系统提供的,程序员无需编码,而只需把SQL语句写好,放到DAO类的一个函数中就可以了。

2.任何查询类的SQL语句,无论字段类型如何,都可以用如上方式处理。

3.如果有特殊的查询方式,com.ibm.heyang.dao.rowmapper下还提供了很多类供使用,如针对select count(*) from tb的IntegerRowMapper类,针对select * from tb where id=XX 的MapRowMapper类,及将将一行记录转化成一个包含键值对的链表的StringRowMapper等,用户也可参照UserRowMapper来书写自己的RowMapper类。这些类的使用将给编码带来较大遍历,关于它们将另行文详述。

posted @ 2012-02-29 10:32 何杨 阅读(204) | 评论 (0)编辑 收藏

 

 

 

 

 

 

Teambiz中前台页面对XHR对象从后台取回的XML的处理

 

 

 

 

 

 

 

作者:何杨

撰写日期:2012年2月24日

版本:1.00

更新日期:2012年2月25日

 

 

第一部分:功能说明

XHR从后台得到XML文本后,使用DOM对其进行解析。

第二部分:核心组件

名称

路径

说明

Ajax.Request

teambiz\WebRoot\page\js\prototype-1.6.0.3.js

Prototype提供的Ajax请求对象,它将被用来想后台发出异步请求并获取反馈。

ajaxObj

它就是XMLHttpRequest对象(简称XHR)。

ajaxObj.responseText

XHR对象获得的反馈文本,在需要查看反馈的XML时会用到它。

ajaxObj.responseXML

XHR对象获得的反馈XML,也是前端需要解析的数据来源。

status

反馈XML第一个status节点的值,当它为ok是意味着顺利得到了后端传来的信息;当它为ng意味着前后端通道是通畅的,但由于某种原因不能获得想要的数据,这个原因可能是用户缺乏权限,后端组件未准备好,后他SQL调用出现异常或是运行异常。这个变量需要在前后端有固定约定才能发挥功用。

arr

包含反馈XML中所有node节点的数组。它也依赖于前后端有固定的约定。这是一个临时变量,真正发挥功用的是tableDatas。

tableDatas

它本身是一个数组,而内部元素也是一个数组,正如其名称描述的那样,它是一个表格形式的数据,它的“行”相当于SQL查询结果集的行,它的“列”相对于结果集的字段值集合,它的“单元格”就是数据。

之所以采用这个对象是因为在使用上相对于arr更加方便,进行一次遍历再通过数组下标就能访问到每个数据。

 

第三部分:三种前台对取回XML的处理

1.如果前台仅需status一个量。

有时,前台仅需status就能进行判定后台是否实现了自己的目的,如进行登录,变更等操作,对status直接进行判断即可,对后台进行CUD操作常会这样处理,示例代码如下:

new Ajax.Request(url,{    

               method:'get',    

               onSuccess: function(ajaxObj){   

                                    // alert(ajaxObj.responseText);

                                    hideLoadingWnd();

                                      

                                    var status=ajaxObj.responseXML.getElementsByTagName("status")[0].firstChild.data;

                                   

                                    if(status=="ok"){

                                                window.location.href="Goto.do?page=/page/jsp/task/tododone/index.jsp";

                                    }

                                    else{

                                                // 返回错误信息

                                                hideLoadingWnd();

                                               

                                                var text=ajaxObj.responseXML.getElementsByTagName("text")[0].firstChild.data;

                                                alert(text);

                                    }

               },    

               onFailure: function(){

                                    hideLoadingWnd();

                                    alert("服务器没有响应.");                                         

               }  

            }

);

以上代码所在路径:teambiz\WebRoot\page\jsp\user\login\javascript.jsp中submitForm函数。

 

2.如果前台需要按照节点名称取出传回XML的值。

有时,前台需要明确取出某个名称的节点值(意图获得后台处理的状态),这时可以如同取出status的值一样,从ajaxObj中取出想要的值,示例代码如下:

var currentPage=ajaxObj.responseXML.getElementsByTagName("currentPage")[0].firstChild.data;

var recordCount=ajaxObj.responseXML.getElementsByTagName("recordCount")[0].firstChild.data;

var pageCount=ajaxObj.responseXML.getElementsByTagName("pageCount")[0].firstChild.data;

// 设置分页数据

setPage(recordCount,currentPage,pageCount);         

以上代码路径:teambiz\WebRoot\page\jsp\task\sent\javascript.jsp中search函数。

3.如果前台需要表格形式的数据

对后台的查询操作常进行这种处理,这时需要用到系统转化出来的tableDatas对象,示例代码如下:

/*****************************************************

* 取得后方菜单

* 何杨,2012年2月7日11:40:34

*****************************************************/

function fetchMenuFromBg(){

            $("menuBar").innerHTML="";

           

            // 组合URL

            var url=encodeURI('FetchMenu.do?');

            url=encodeURI(url);           

            // 发出Ajax请求

            new Ajax.Request(url,{    

           method:'get',    

           onSuccess: function(ajaxObj){  

                // alert(ajaxObj.responseText);

                var status=ajaxObj.responseXML.getElementsByTagName("status")[0].firstChild.data;               

                                                if(status=="ok"){

                                                            // 找到所有节点放入数组

                                                            var arr=ajaxObj.responseXML.getElementsByTagName("node");

                                                            if(arr.length==0){

                                                                        alert("没有得到返回数据.");

                                                            }                                                          

                                                            var tableDatas=new Array();                                 

                                                            // 遍历这个数组

                                                            for(var i=0;i<arr.length;i++){

                                                                var node=arr[i];

                                                                        var arr2=new Array();

                                                                        for(var j=0;j<node.childNodes.length;j++){

                                                                            var child=node.childNodes.item(j);                                                                 arr2.push(child.childNodes[0].nodeValue);

                                                                        }

                                                                        // 向表格中添加行

                                                                        tableDatas.push(arr2);

                                                            }                                                          

                                                            // 显示菜单

                                                            showMenu(tableDatas);

                                                }

                                                else{

                                                            var text=ajaxObj.responseXML.getElementsByTagName("text")[0].firstChild.data;

                                                            alert(text);

                                                }

           },    

           onFailure: function(){

                        hideLoadingWnd();

                                                alert("服务器没有响应.");                                         

           }  

        }

           );

};

 

/*****************************************************

* 显示菜单

* 何杨,2012年2月7日14:03:43

*****************************************************/

function showMenu(tableDatas){

            var ul=document.createElement("ul");  

            for(var i=0;i<tableDatas.length;i++){

                        var arr=tableDatas[i];

                        var text=arr[0];

                        var url=arr[1];                      

                        var link=document.createElement("a");

                        link.appendChild(document.createTextNode(text));

                        link.setAttribute("href", url);

                       

                        var li=document.createElement("li");

                        li.appendChild(link);

                        ul.appendChild(li);

            }          

            $("menuBar").appendChild(ul);    

}

以上代码路径:teambiz\WebRoot\page\js\common.js,其中tableDatas的产生用getTableDatasFromArr进行了一定程度的简化。

 

第四部分:使用步骤

步骤

说明

参照

编写向后端发起请求的函数

请参照上面的fetchMenuFromBg函数书写新函数,主要需要修改的地方在URL和处理tableDatas的函数,其它部分无需变化。

teambiz\WebRoot\page\js\common.js中的fetchMenuFromBg函数。

编写处理tableDatas的函数(可选)

遍历方式请参照上面的showMenu函数,取得数据后进行DOM操作需要自行处理。

teambiz\WebRoot\page\js\common.js中的showMenu函数。

 

第五部分:小结

在前后台有一定约定的前提下(status,node),通过一系列对象的配合,我们轻松完成从SQL查询结果集到前台能使用的结果集的转换,这些对象及其使用方法绝大多数都是固定的或是仅需稍加改变的,程序员主要需要考虑的是最初的SQL语句和最终的DOM处理过程,中间只用按部就班的完成装配工作。

这种方式的优势在于:

1.减轻了编码量,同时也减少了出错的可能。

2.易用,因为SQL相对于HQL更容易被人接受。

3.比页面循环标签更具表现性。

这种方式的主要缺点在于:

1. JS和DOM操作需要程序员加以小心。

2.如果字段含有特殊字符可能会造成XML解析异常,但对此无需过于担心,需要注意的多在备注这样的字段中,可以在需要特殊处理再进行处理。

posted @ 2012-02-29 10:32 何杨 阅读(273) | 评论 (0)编辑 收藏

 

 

 

 

 

 

TeamBiz中Ajax的基本运用

 

 

 

 

 

 

 

作者:何杨

撰写日期:2012年2月23日

版本:1.03

更新日期:2012年2月28日

 

 

第一部分:功能说明

提供前台页面到后台程序的异步请求响应通道。

第二部分:核心组件

名称

路径

说明

Prototype1.6.0.3

teambiz\WebRoot\page\js\prototype-1.6.0.3.js

Prototype是一个有历史的JS类库,TeamBiz中主要使用了它的Ajax部分及$函数。

注意,Teambiz并非对Prototype产生依赖,Prototype为Teambiz提供的仅是Ajax.Rquest对象及$函数而已,因为teambiz已经包含了普适版本的$函数,因此换用别的JS框架并不困难。

AjaxAction

teambiz\src\com\ibm\heyang\action\base\AjaxAction.java

AjaxAction是所有响应Ajax异步请求的Action的基类,它主要提供以下四项功能:

1.设置Response;

2.将url中的请求参数解码后放入RequestParamMap对象中;

3.强制子类实现函数process;

4.当子类的process函数中出现异常时,接受异常并包装成XML传给前台页面。

RequestParamMap

teambiz\src\com\ibm\heyang\action\base\RequestParamMap.java

RequestParamMap内部包含一个哈希表,以键值对的方式存储前台URL中的参数及其值。

RequestParamMap对象的生成在于AjaxAction的getRequestParamMap函数中。

它主要提供以下功能:

1.将参数集约化,此举能简化后台函数的编写。

2.当后台函数使用其内部不存在的参数时,它能自主抛出一个异常,通过AjaxAction的包装传给前台,使得编写函数的程序员能快速进行错误定位。

3.对前台编写的参数进行UTF-8解码,此举与前台对URL进行两次UTF8编码配合,统一解决了非ASC码字符传送产生乱码的问题。

Ajax.Request

定义于prototype-1.6.0.3.js中

Prototype中定义的Ajax请求对象,其参数有四个,URL,请求方法,成功函数和失败函数。相对于传统方式,它的可控性更高。

 

第三部分:前台和后台的约定

考虑到代码解读和人工解读的双重便利性,TeamBiz采用XML而不是JSON作为前后台数据的载体,此XML采用了一些约定以规范化编码。

Ajax异步调用过程中,后台需要两组数据来说明响应细节,一个是状态,如果它的值是OK的话,说明已经取得了请求想要的数据,此时向前台传出的XML会类似如下格式:

<response>

<status>ok</status>

<node>

<a>a</a>

<b>b</b>

</node>

</response>

如果它的值是NG的话,说明后台能响应,但由于某种原因(用户未登录,用户缺乏权限,参数缺失,后台组件尚未就绪,异常抛出等,前二者需要程序员编码,后两者框架已经代为实现),不能传回请求想要的数据,此时向前台传出的XML会类似如下格式:

 

<response>

<status>ng</status>

<text>请登录后再来执行此操作</text>

</response>

 

后台进行如上约定后,前台就可以采用如下统一的格式来处理XHR响应:

new Ajax.Request(url,{    

           method:'get',    

           onSuccess: function(ajaxObj){   

                        // alert(ajaxObj.responseText);   // 这里不要随意删去,有时需要打开屏蔽以观察后台传来的XML文本                   

                var status=ajaxObj.responseXML.getElementsByTagName("status")[0].firstChild.data;

                                                                                               

                                                if(status=="ok"){

                                                            ....// 状态为ok时的处理

                                                }

                                                else{

                                                            ....// 状态为ng时的处理

                                                }

           },    

           onFailure: function(){

                                                ....// 后台没有响应时的处理

           }  

        }

);

 

第四部分:使用步骤

步骤

说明

参照

在前台编写向后台发出请求的JS函数。

在此函数需要进行三件事:

1.编写URL。

2.对URL进行UTF8编码。

3.会使用一个Ajax.Request对象向后台发出请求。

teambiz\WebRoot\page\js\common.js中fetchMenuFromBg函数。

在后台编写响应前端请求的Action

Action需要继承自AjaxAction。在其process函数中主要进行以下三件事:

1.权限验证。

2.使用后端组件取得前端想要的数据。

3.以XML方式将数据传回。

teambiz\src\com\ibm\heyang\action\menu\FetchMenuAction.java

struts-config.xml注册Action

由于完全不需要静态或动态的form,此Action格式很简单,仅包含path,type和scope三部分。

teambiz\WebRoot\WEB-INF\struts-config.xml中的

<action path="/FetchMenu" type="com.ibm.heyang.action.menu.FetchMenuAction" scope="request" >

</action>

 

第五部分:小结

TeamBiz中全部向后台的请求都是通过Ajax异步方式实现的,相对于传统方式,它有以下优势:

1.由于只需要提取必要的资源,因此占用资源少。

2.有多种状态,多个函数用来处理后台的响应,这使得控制更加多样化。

3.由于前台在请求时处于静止状态,因此无需刻意保存前台页面数据。

4.由于不需要编写form,forward等元素,使得控制文件编写简单方便。

posted @ 2012-02-29 10:31 何杨 阅读(203) | 评论 (0)编辑 收藏

posted @ 2012-02-29 10:30 何杨 阅读(174) | 评论 (0)编辑 收藏

 

 

 

 

 

 

Teambiz整体介绍

 

 

 

 

 

 

 

作者:何杨

撰写日期:2012年2月27日

版本:1.00

更新日期:  

 

 

第一部分:TeamBiz说明

TeamBiz是一个处理团队成员之间事务的Web程序,用户可以使用它给自己或者别人规定任务,完成给自己的任务或是跟踪分给他人的事务。

TeamBiz差异化的一点在于基本使用Ajax方式进行前后台交互,后台查询数据库后传回的是XML,前台进行解析并使用DOM进行页面操作。系统在前后台提供了一系列类来协助程序员完成常见编码任务,相信这能减轻程序员的负担并提高代码的一致性。

TeamBiz是一个框架性说明程序,在此程序的基础上还可以完成扩充,如菜单改写成树样式,后台增加更多的领域对象和服务类等。

TeamBiz遗憾的一点在于没有解决当领域对象及其对应的表数据增加时系统复杂度的同时增加,也许再引入一个或多个中间层次能将熵维持在一个能控制的限度内,如果你知道怎么去做,请写信告诉我。(heyanghy@cn.ibm.com,heyang78@gmail.com)

第二部分:TeamBiz使用的框架

名称

说明

Stuts1.3.8

Teambiz使用了Struts的控制层功能和Tile及极少数标签。

Spring2.5

Teambiz使用了Spring的IoC和JDBCTemplate。

Hibernate3.0

Teambiz使用Hibernate进行单个领域对象的创建和更新。

Prototype1.6.0.3

Teambiz使用了Prototype的Ajax.Request,$,window.load三部分。

 

第二部分:TeamBiz其它相关事项

名称

说明

数据库

MySql5.2,如果需要更换数据库,请修改teambiz\cfg\appctx-datasource.xml中数据源配置并检查Dao类中诸Sql是否能在新数据库中正常运行。

开发环境

MyEclipse9,将程序包导入即可运行。

 

posted @ 2012-02-29 10:25 何杨 阅读(273) | 评论 (0)编辑 收藏

通常,我们可以如下所示制作横向菜单:
#commonUsedDocumentContainerDiv ul{
    margin
:0px;
    padding
:0px;
    list-style-type
:none;
    vertical-align
:middle  ;
}

#commonUsedDocumentContainerDiv li a
{
    width
:130px;  
    height
:75px;
    line-height
:32px;
    
    font-family
:"宋体","Tahoma"; 
    font-size
:14px;   
    font-weight
:bold;           
    color
:#000000;
    
    text-decoration
:none;
    text-align
:left;  
    
    background
:#ffffff;
}

#commonUsedDocumentContainerDiv li a:hover
{
    width
:130px;  
    height
:75px;
    line-height
:32px;
    
    font-family
:"宋体","Tahoma"; 
    font-size
:14px;   
    font-weight
:bold;           
    color
:#0000ff;
    
    text-decoration
:none;
    text-align
:left;  
    
    background
:#ffffff;
}

这样做,在FF或是ie8以上的版本中,都没有问题,但是ie6有问题,具体上看来本来应该是一横排的菜单变成了阶梯状,一下子就难看了。

这是因为ie6对ul/li的解释方式所致,要解决这个问题也很简单,对li的样式也进行设置就行了,如下的粗体部分:
#commonUsedDocumentContainerDiv ul{
    margin
:0px;
    padding
:0px;
    list-style-type
:none;
    vertical-align
:middle  ;
}

#commonUsedDocumentContainerDiv li
{
    float
:left;
    display
:block;
    
    width
:130px;  
    height
:75px;
    
    background
:#ffffff;
}


#commonUsedDocumentContainerDiv li a
{
    width
:130px;  
    height
:75px;
    line-height
:32px;
    
    font-family
:"宋体","Tahoma"; 
    font-size
:14px;   
    font-weight
:bold;           
    color
:#000000;
    
    text-decoration
:none;
    text-align
:left;  
    
    background
:#ffffff;
}

#commonUsedDocumentContainerDiv li a:hover
{
    width
:130px;  
    height
:75px;
    line-height
:32px;
    
    font-family
:"宋体","Tahoma"; 
    font-size
:14px;   
    font-weight
:bold;           
    color
:#0000ff;
    
    text-decoration
:none;
    text-align
:left;  
    
    background
:#ffffff;
}

另外需要注意的是,li a和li a:hover中照样可以设置display:block,如果li a 或者li a:hover 有背景还非得如此不可,这和网上流传甚广的方案不一样,看来知识不能拿来就用,还需要自己尝试一下。
posted @ 2012-02-14 15:31 何杨 阅读(356) | 评论 (0)编辑 收藏

先看代码:
#contentContainer{
    margin-top
:10px;
    padding
:0px;
    border
:0px solid #336699;
    
    width
:100%;
    
    overflow-x
:hidden;
}

当div的宽度基本和浏览器可控宽度一致时,滚动条就会出现,最麻烦的是会出现两个,一个div的,一个浏览器的。

这时,可以如上所示,将超出部分隐藏,这样滚动条就不会出现了。

IE上效果是滚动条彻底没有,但是FF只是把滚动条置灰,两者还是有区别的。
posted @ 2012-02-14 15:19 何杨 阅读(663) | 评论 (0)编辑 收藏

#detailInstructionContentDiv{
    margin
:0px;
    padding-top
:10px;
    padding-left
:22px;

    border
:0px solid #336699;
    
    width
:150px;
    height
:230px;
    
    text-align
: left;
    
    font-family
:"宋体","Tahoma"; 
    font-size
: 12px;    
    font-weight
:normal;
    color
:#333333;
    
    white-space
:normal;
}

见以上粗体部分,比wordbreak之类的好用得多。
posted @ 2012-02-14 15:13 何杨 阅读(652) | 评论 (0)编辑 收藏

页面代码,其中粗体部分是需要你根据实际情况进行修改的,其它保持原状:
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<HTML>
<title>标题</title>
<BODY>
<center><OBJECT CLASSID="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" WIDTH="1440" HEIGHT="772" CODEBASE="http://active.macromedia.com/flash5/cabs/swflash.cab#version=7,0,0,0">
<PARAM NAME=movie VALUE="1_1.swf">
<PARAM NAME=play VALUE=true>
<PARAM NAME=loop VALUE=false>
<PARAM NAME=wmode VALUE=transparent>
<PARAM NAME=quality VALUE=low>
<EMBED SRC="1_1.swf" WIDTH=1440 HEIGHT=772 quality=low loop=false wmode=transparent TYPE="application/x-shockwave-flash" PLUGINSPAGE="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash">
</EMBED>
</OBJECT></center>
<SCRIPT src='swf.js'></script>
</BODY>
</HTML>

导入的swf.js代码如下:
obj=document.getElementsByTagName('object');
for (var i=0; i<obj.length; ++i)
  obj[i].outerHTML
=obj[i].outerHTML;
posted @ 2012-02-13 11:04 何杨 阅读(1004) | 评论 (2)编辑 收藏

如果以如下方式打开新窗口:
<href="javascript:openWindow('swf/1_1.jsp','',1440,772);" >示例</a>

那么,原窗口会变成一个含有[Object]字符的窗口。

换用下面方式即可,注意下面粗体部分的void(0),它表示没有返回值:
<href="javascript:openWindow('swf/1_1.jsp','',1440,772);void(0);" >示例</a>

下面的openCenterWindow函数仅供参考:
function openWindow(url,windowName,width,height){
    
var left = 0;     
    
var top = 0;       
      
    
var wnd=window.open(url,windowName,"height="+height+",width="+width+",top="+top+",left="+left+",resizable=yes,scrollbars=yes,status=no,location=no,");
    
return wnd;
}
posted @ 2012-02-13 10:59 何杨 阅读(1131) | 评论 (1)编辑 收藏

说明:
1.下载http://www.apache.org/dyn/closer.cgi/poi/release/bin/poi-bin-3.7-20101029.zip后,将poi-3.7目录下的jar包放入lib目录, 再将此工程载入Eclipse/MyEclipse即可。
2.界面中文本框供输出数据量用,在我的T410上测试数据量在3.5W~3.6W之间,再多就报java.lang.OutOfMemoryError错误。附带提一下输出数据量的问题,如果修饰单元格的代码越简单,那么能输出的数据就越多,反之数据就少了。
3.主要代码如下:

Sevlet代码:
package com.heyang.action;


import java.io.BufferedOutputStream;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import com.heyang.service.DownloadService;

/**
 * POI下载的Servlet
 * 
@author heyang
 *
 
*/
public class DownloadServlet extends HttpServlet {
    
private static final long serialVersionUID = 56890894234786L;
    
    
public void doPost(HttpServletRequest request, HttpServletResponse response)
            
throws ServletException, java.io.IOException {
        String fileName
="download.xls";
        response.setHeader(
"Content-disposition""attachment; filename="+fileName);// 设定输出文件头   
        response.setContentType("application/msexcel");// 定义输出类型 
        
        
try{
            
int rowCount=Integer.parseInt(request.getParameter("rowCount"));
            
            
// 表头行
            String[] headers=new String[]{"更新ID","账期","基站编号","基站名称","站点状态","部门名称","站点类型","占用类型","预提(元)","未核销金额","上期未核销","开始月份","结束月份","上期抄表数","本期抄表数","电价","电量","本期报账(元)","补提(元)","预提汇总(元)","成本中心","专业","本期报账单号","基站类别","线损"};
            DownloadService service
=new DownloadService();

            HSSFWorkbook workbook
=service.generateWorkbook(rowCount, headers.length);

            ServletOutputStream out 
= response.getOutputStream();
            BufferedOutputStream bos 
= new BufferedOutputStream(out);        
            workbook.write(bos);
            bos.flush();
            bos.close();
            
        }
catch(Exception ex){
            ex.printStackTrace();
        }
        
        
return ;
    }
        
    
public void doGet(HttpServletRequest request, HttpServletResponse response)
            
throws ServletException, java.io.IOException {
        doPost(request, response);
    }
}

Service代码:
package com.heyang.service;

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;


/**
 * 下载服务类
 * 
 * 
@author heyang
 *
 
*/
public class DownloadService{
    
/**
     * 生成工作簿对象
     * 
@param rowCount
     * 
@param columnCount
     * 
@return
     
*/
    
public HSSFWorkbook generateWorkbook(int rowCount,int columnCount) throws Exception{
        HSSFWorkbook workbook 
= new HSSFWorkbook(); //产生工作簿对象
        HSSFSheet sheet = workbook.createSheet(); //产生工作表对象
        String value=null;
        
        HSSFRow row 
= null;
        HSSFCell cell 
= null;
        
        
for(int i=0;i<rowCount;i++){
            row 
= sheet.createRow(i);//创建一行
            
            
for(int j=0;j<columnCount;j++){
                value
=""+i+","+j;
                
                cell 
= row.createCell(j);
                cell.setCellValue(value);
                
                cell 
= null;
            }
            
            row 
= null;
        }
        
        row 
= null;
        cell 
= null;
        
        
return workbook;
    }
}

4.工程下载地址:
posted @ 2012-02-01 15:48 何杨 阅读(744) | 评论 (0)编辑 收藏

1.Select控件在页面上的写法:
<select id="monthSelectCbo">
    
<option value="01">01</option>
    
<option value="02">02</option>
    
<option value="03">03</option>
    
<option value="04">04</option>
    
<option value="05">05</option>
</select>

2.设定select控件的当前项:
可以用:
$(
"monthSelectCbo").value=month;
也可以用:
$(
"monthSelectCbo").selectedIndex=1;

3.取得select控件的当前内容:
var month= $("monthSelectCbo").value; 

4.取得select空间选择项的序号:
var selIndex=$("monthSelectCbo").selectedIndex;

5.清除select控件的所有原有值:
var myListbox=$("belongToCompanyCbo");

for(var i=myListbox.options.length-1;i>=0;i--){
    myListbox.remove(i);
}

6.使用JavaScript给Select控件设定值:
var newOption=new Option;
newOption.value
="Beijing";
newOption.text
="北京";
monthSelectCbo.add(newOption);
posted @ 2012-01-12 11:31 何杨 阅读(264) | 评论 (0)编辑 收藏

父窗口调用子窗口函数实现是挺简单的,如下:
var wnd = window.open("XXX.html");
wnd.showDatas(datas);
以上代码中,showDatas是定义在子窗口的函数,datas是父窗口要给子窗口的数据。
需要注意的事,使用open语句打开窗口后,窗口未必能把所有代码全部载入,因此showDatas函数未必调用有效。
如果要有效,可以先把数据传递给子窗口,再在子窗口中延时调用showDatas函数。
如此,父窗口中的代码如下:
var wnd = window.open("XXX.html");
wnd.datas=datas;// 传递数据给子窗口
子窗口中的代码如下:
setTimeout(showDatas(window.datas),1000);// 延时时间可进行调整。
如上,父窗口调用子窗口函数才算完美。

反过来,子窗口要调用父窗口的函数要用opener对象,如:
opener.showMessages(msgs);
以上代码中,showMessages是定义在父窗口的函数,msgs是子窗口要给父窗口的数据。

2012年5月9日增补:
父窗口未必需要传数据给子窗口,而是子窗口需要操作父窗口的某些区域如div时,可以在父窗口打开子窗口的函数前将这个div的id找个地方(隐藏区域)存起来,当然这个地方不需要显示,当子窗口需要操作这个div时,直接调用父窗口的js函数即可,这个函数可以先从隐藏区域中得到div的id,再根据这个id操作div。
posted @ 2012-01-11 15:28 何杨 阅读(1413) | 评论 (0)编辑 收藏

下载地址:

效果:

核心代码:
<%@ page contentType="text/html; charset=UTF-8"%>

<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>

<title>Dtree Sample</title>
<link rel="stylesheet" rev="stylesheet" href="web/css/style.css" type="text/css" />
<link rel="stylesheet" rev="stylesheet" href="web/css/dtree.css" type="text/css" />
<script src="web/js/dtree.js" type="text/javascript"></script>
</head>

<body>

<div id="treeDiv">
    
<div class="dtree">
        
<p><href="javascript: d.openAll();">全展开</a> | <href="javascript: d.closeAll();">全收起</a></p>
        
<script type="text/javascript">
            
<!--
    
            d 
= new dTree('d');
    
            d.add(
0,-1,'Root');
            d.add(
1,0,'1','web/jsp/1.jsp','显示1.jsp','rightFrame','','',false);
            d.add(
2,0,'2','web/jsp/2.jsp','显示2.jsp','rightFrame','','',false);
            d.add(
3,0,'3','web/jsp/3.jsp','显示3.jsp','rightFrame','','',false);
            d.add(
4,0,'4','web/jsp/4.jsp','显示4.jsp','rightFrame','','',false);
            d.add(
5,1,'李逵','test?page=likui','显示李逵','rightFrame','','',false);
            d.add(
6,1,'宋江','test?page=sj','显示宋江','rightFrame','','',false);
            d.add(
7,1,'鲁智深','test?page=lzs','显示鲁智深','rightFrame','','',false);           
    
            document.write(d);
    
            
//-->
        </script>
    
</div>
</div>
<div id="contentDiv">
    
<iframe id="index_mainframe" name="rightFrame" class="index_mainframe" src="web/jsp/blank.jsp" frameborder="0" scrolling="no" ></iframe>
</div>

</body>
</html>

dtree的css,js代码都不复杂,如果对其稍加改造,可以做出更眩的东西来。
posted @ 2012-01-04 19:44 何杨 阅读(308) | 评论 (0)编辑 收藏

说明:以下代码能原样复制输入XML的所有节点和属性,虽说使用ESQL和JavaCompute很容易完成此任务。但是将以下代码稍作修改,就可以对输入进行筛选,剪裁和重构的工作。

输入:
<id="1"><id="2">3</b></a>

代码:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
<xsl:template match="node()">
        
<xsl:copy>
            
<xsl:apply-templates select="@*|node()"/>
        
</xsl:copy>
    
</xsl:template>
 
    
<xsl:template match="@*">
        
<xsl:attribute namespace="{namespace-uri()}" name="{name()}">
            
<xsl:value-of select="."/>
        
</xsl:attribute>
    
</xsl:template>
 
    
<xsl:template match="text()">
        
<xsl:value-of select="."/>
    
</xsl:template>
</xsl:stylesheet>

输出:
<?xml version="1.0" encoding="UTF-8"?><id="1"><id="2">3</b></a>
posted @ 2011-12-21 20:14 何杨 阅读(589) | 评论 (1)编辑 收藏

     摘要: 1.使用Substring进行字符串截取输入:Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><date>122811</date>输出:Code highlighting produced by Actipro CodeHig...  阅读全文
posted @ 2011-12-14 09:49 何杨 阅读(377) | 评论 (0)编辑 收藏

数据源(students.xml):
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="xsheet.xsl"?>
<students>
    
<student id="123">
        
<name>Andy</name>
        
<score>69</score>
    
</student>
    
<student id="345">
        
<name>bill</name>
        
<score>88</score>
    
</student>
    
<student id="678">
        
<name>Felix</name>
        
<score>96</score>
    
</student>
    
<student id="987">
        
<name>Zerg</name>
        
<score>72</score>
    
</student>
    
<student id="236">
        
<name>Grrr</name>
        
<score>59</score>
    
</student>
</students>

XSL文件(xsheet.xsl):
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    
    
<xsl:template match="/">
        
<html>
        
<head>
            
<title>成绩单</title>
        
</head>
        
<body>
            
<table border="1">
                
<caption>学生成绩单</caption>
                
<tr>
                    
<td>序号</td>
                    
<td>ID</td>
                    
<td>姓名</td>
                    
<td>成绩</td>
                
</tr>
                
<xsl:for-each select="students/student">
                
<xsl:sort order="descending"  select="score"/>
                    
<tr>
                        
<xsl:choose>
                            
<xsl:when test="position() mod 2 = 1">
                                
<xsl:attribute name="style">background:#336699;</xsl:attribute>
                            
</xsl:when>                            
                            
<xsl:otherwise>
                                
<xsl:attribute name="style">background:#00ffcc;</xsl:attribute>
                            
</xsl:otherwise>
                        
</xsl:choose>
                    
                        
<td><xsl:value-of select="position()"/></td>
                        
<td><xsl:value-of select="@id"/></td>
                        
<td><xsl:value-of select="name"/></td>
                        
<xsl:choose>
                            
<xsl:when test="score &gt; 60">
                                
<td><xsl:value-of select="score"/></td>
                            
</xsl:when>                            
                            
<xsl:otherwise>
                                
<td><font color="red"><xsl:value-of select="score"/></font></td>
                            
</xsl:otherwise>
                        
</xsl:choose>
                    
</tr>
                
</xsl:for-each>
            
</table>
            
<br/>
            
<table border="1">
                
<caption>统计表格</caption>
                
<tr><td>总分</td><td><xsl:value-of select="sum(//score)"/></td></tr>
                
<tr><td>个数</td><td><xsl:value-of select="count(/students/student)"/></td></tr>
                
<tr><td>及格人数</td><td><xsl:value-of select="count(/students/student[score > 60])"/></td></tr>    
                
<tr><td>平均分</td><td><xsl:value-of select="sum(//score) div count(/students/student)"/></td></tr>                            
            
</table>
        
</body>
        
</html>
    
</xsl:template>
    
</xsl:stylesheet>

用IE打开数据源文件的效果:


XSLT相关知识请参考:
http://soft-app.iteye.com/blog/916652
posted @ 2011-12-12 21:26 何杨 阅读(401) | 评论 (0)编辑 收藏

需要一个Mapping节点时,XMLTansformation节点通常是一个不错的选择,它可以使用XSLT将输入的XML转变成另一种形式的 XML,其开发速度高于在Compute节点中书写ESQL和在JavaCompute节点中书写Java代码,其缺陷在于缺乏访问外部数据的手段,有时 还需要上述两种节点的帮助。

XMLTransformation节点在Transformation选择项下,需要指定XSL文件的位置,可以通过其StylesheetName和StyleSheetDirectory来指定。以下是一个转换的例子:

输入:
<employees><employee id="001">Andy</employee><employee id="002">Bill</employee><employee id="034">Cindy</employee></employees>

转换XSL:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    
    
<xsl:template match="/">
        
<users>
        
<xsl:for-each select="employees/employee">
            
<user>
                
<sn><xsl:value-of select="position()"/></sn>
                
<id><xsl:value-of select="@id"/></id>
                
<name><xsl:value-of select="text()"/></name>
                
<pswd><xsl:value-of select="concat(@id,'_',text())"/></pswd>
            
</user>
        
</xsl:for-each>
        
</users>
    
</xsl:template>
    
</xsl:stylesheet>

输出:
<?xml version="1.0" encoding="UTF-8"?><users><user><sn>1</sn><id>001</id><name>Andy</name><pswd>001_Andy</pswd></user><user><sn>2</sn><id>002</id><name>Bill</name><pswd>002_Bill</pswd></user><user><sn>3</sn><id>034</id><name>Cindy</name><pswd>034_Cindy</pswd></user></users>
posted @ 2011-12-12 19:44 何杨 阅读(747) | 评论 (0)编辑 收藏

代码:
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import com.ibm.broker.javacompute.MbJavaComputeNode;
import com.ibm.broker.plugin.MbElement;
import com.ibm.broker.plugin.MbException;
import com.ibm.broker.plugin.MbMessage;
import com.ibm.broker.plugin.MbMessageAssembly;
import com.ibm.broker.plugin.MbOutputTerminal;


public class subflow_JavaCompute extends MbJavaComputeNode {

    
public void evaluate(MbMessageAssembly inAssembly) throws MbException {
        MbOutputTerminal out 
= getOutputTerminal("out");
        MbOutputTerminal alt 
= getOutputTerminal("alternate");

        MbMessage inMessage 
= inAssembly.getMessage();
        MbMessage outMessage 
= new MbMessage(inMessage);
        MbMessageAssembly outAssembly
=new MbMessageAssembly(inAssembly,outMessage);
        
        MbElement document
=outMessage.getRootElement();
        MbElement root
=document.getLastChild().getFirstChild();

        
try{
            Set
<String> selfDefNSSet=new HashSet<String>();// 用来存储自定义的名称空间名
            traverseAndRemoveNils(root,selfDefNSSet);// 遍历节点删除特定属性
            
            
if(selfDefNSSet.size()>0){
                traverseAndRemoveSelfDefNSNode(root,selfDefNSSet);// 遍历节点删除自定义名称空间节点
            }
        }
        
catch(Exception ex){
            ex.printStackTrace();
        }
        
        out.propagate(outAssembly);
    }

    
    
private void traverseAndRemoveNils(MbElement elm,Set<String> selfDefNSSet) throws Exception{
        
// get all the attributes of current element
        List <MbElement> attrSet = (List <MbElement>)elm.evaluateXPath("@*"); 
        
for(MbElement attr:attrSet){
            String name
=attr.getName().toString();
            String value
=attr.getValue().toString();
            
            
if(isNillAttr(name,value)){
                attr.detach();
            }
            
            
if(isSelfDefNS(name,value)){
                String[] arr
=name.split(":");
                selfDefNSSet.add(arr[
1]);
                attr.detach();
            }
        }
        
        
// get all sub elements of current element
        List <MbElement> nodeset = (List <MbElement>)elm.evaluateXPath("*"); 
        
for(MbElement childElm:nodeset){
            
// recursion
            traverseAndRemoveNils(childElm,selfDefNSSet);
        }
    }
    
    // 判断是否特定属性,a:nil,b:nil都算
    
private boolean isNillAttr(String name,String value){
        String patternStr
="(\\w+)(:nil)";
          
        
boolean result1 = Pattern.matches(patternStr, name);
        
boolean result2="true".equals(value);
        
        
return result1&&result2;
    }
    // 判断是否自定义名称空间
    
private boolean isSelfDefNS(String name,String value){
        String patternStr
="(xmlns:)(\\w+)";
          
        
boolean result = Pattern.matches(patternStr, name);
        
        
return result;
    }
   
    
private void traverseAndRemoveSelfDefNSNode(MbElement elm,Set<String> selfDefNSSet) throws Exception{
        String name
=elm.getName().toString();
        
        
if(isSelfDefNSNode(name,selfDefNSSet)){
            elm.detach();
        }
        
        
// get all sub elements of current element
        List <MbElement> nodeset = (List <MbElement>)elm.evaluateXPath("*"); 
        
for(MbElement childElm:nodeset){
            
// recursion
            traverseAndRemoveSelfDefNSNode(childElm,selfDefNSSet);
        }
    }
    // 判读节点是否自定义名称空间的限定名
    
private boolean isSelfDefNSNode(String name,Set<String> selfDefNSSet){
        String[] arr
=name.split(":");
        
        
if(arr.length==2){
            String ns
=arr[0];
            
            
return selfDefNSSet.contains(ns);
        }
else{
            
return false;
        }
    }
}

输入:
<contactInfo xmlns:ns1="http://tbccorp.com/Services/CustomerMgt/v1/"><homePhoneNumber as:b="c"><key xsi:nil="true"/><value></value></homePhoneNumber><workPhoneNumber><ns1:a>1644</ns1:a><key xsi:nil="true"/><value ns1:nil="true">5</value></workPhoneNumber><ns1:b>1949</ns1:b><mobilePhoneNumber xmlns:ns1="http://tbccorp.com/Services/CustomerMgt/v1/"><key xsi:nil="true"/><value>3159867097</value></mobilePhoneNumber></contactInfo>

输出:
<contactInfo><homePhoneNumber as:b="c"><key/><value/></homePhoneNumber><workPhoneNumber><key/><value>5</value></workPhoneNumber><mobilePhoneNumber><key/><value>3159867097</value></mobilePhoneNumber></contactInfo>
posted @ 2011-12-09 23:40 何杨 阅读(1563) | 评论 (0)编辑 收藏

     摘要: Cache的作用:在并发环境中减少重复性的对后台的调用,从而提高运行效率。Cache必须要做到的:1.保证Cache中的数据与后台系统数据的一致性。2.Cache必须要减少访问后台的操作以提高效率。如果不能同时做到以上两点,则Cache失去了意义。Cache的基本操作:Read(Get):按键值从Cache中取得想要的数据;Write(Put):将键值对放到Cache中;Reset(RemoveA...  阅读全文
posted @ 2011-09-27 15:32 何杨 阅读(523) | 评论 (0)编辑 收藏

     摘要: 注:以下Cache未加时效处理,是比较简陋的Cache方案。AbstractCacheMap基类,用来定义和限制子类的操作:Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->package cachemap.base;/** *&nb...  阅读全文
posted @ 2011-09-27 10:00 何杨 阅读(968) | 评论 (0)编辑 收藏

任务:熟悉Subflow的使用

Subflow即子流程,当主流程的某个分支较有独立性且复杂是可以采用子流程的形式。
子流程必须具备一个Input和Output节点作为输入和输出,而主流程可以通过“Add Subflow”的方式将定义好的子流程加入进来,当作一个普通节点来使用。

Input和Output节点在Contruction中,以下是使用子流程的一个例子。

使用了子流程的主流程:


定义的子流程:


例程:
posted @ 2011-09-23 09:40 何杨 阅读(699) | 评论 (0)编辑 收藏

任务:使用JavaCompute节点进行XML转化

一.如图建立Flow


二.编辑JavaCompute节点的Java代码如下:
import com.ibm.broker.javacompute.MbJavaComputeNode;
import com.ibm.broker.plugin.*;


public class flow_JavaCompute extends MbJavaComputeNode {

    
public void evaluate(MbMessageAssembly inassembly) throws MbException {
        MbOutputTerminal out 
= getOutputTerminal("out");
        
// MbOutputTerminal alt = getOutputTerminal("alternate");

        MbMessage inMessage 
= inassembly.getMessage();
        MbMessage outMessage 
= new MbMessage(inMessage);
        MbMessageAssembly outAssembly
=new MbMessageAssembly(inassembly,outMessage);
        
        MbElement root
=outMessage.getRootElement();
        MbElement rootElm
=root.getLastChild().getFirstChild();

        MbElement employee1
=rootElm.createElementAsLastChild(MbElement.TYPE_NAME,"empoyee",null);
        employee1.setValue(
"Andy");
        
        MbElement employee2
=rootElm.createElementAsLastChild(MbElement.TYPE_NAME,"empoyee",null);
        employee2.setValue(
"Bill");
        MbElement id 
= employee2.createElementAsFirstChild(MbElement.TYPE_NAME_VALUE,"id""221415");
        
        out.propagate(outAssembly);
        outMessage.clearMessage();
    }

}

三.输入XML如下
<employees><employee>Hy</employee></employees>

四.输出XML如下:
<employees><employee>Hy</employee><empoyee>Andy</empoyee><empoyee id="221415">Bill</empoyee></employees>
注意这里面的代码操作与我们常见XML很不一样,一个是取根节点处,一个是给节点设置值处,一个是给节点增加属性处。

五.工程从这里下载
http://www.blogjava.net/Files/heyang/JavaCompute0922_01.rar
posted @ 2011-09-22 16:21 何杨 阅读(1739) | 评论 (0)编辑 收藏

ESQL:
CREATE COMPUTE MODULE flow_Compute
    
CREATE FUNCTION Main() RETURNS BOOLEAN
    
BEGIN
        
SET OutputRoot.XML.employee.uuid = UUIDASCHAR;
        
SET OutputRoot.XML.employee.uuid2 = UUIDASBLOB;
        
        
SET OutputRoot.XML.employee.(XML.Attribute)id ='123';
        
SET OutputRoot.XML.employee.name = 'Felix';
        
SET OutputRoot.XML.employee.age = 33;

        
SET OutputRoot.XML.employee.address[1] = 'Dalian 88';
        
SET OutputRoot.XML.employee.address[2] = 'Beijing 188';
        
SET OutputRoot.XML.employee.address[3] = 'Shanghai 288';

        
SET OutputRoot.XML.employee.title.VALUE = NULL;
        
        
SET OutputRoot.XML.employee.salary VALUE = NULL;

        
SET OutputRoot.XML.employee.Comments.(XML.Content)=NULL;

        
RETURN TRUE;
    
END;
END MODULE;

Result XML:
<employee id="123"><uuid>1d1932fe-b2a9-484d-8d32-e70440288914</uuid><uuid2>239143b0384e46ff9bb50a34c8b28732</uuid2><name>Felix</name><age>33</age><address>Dalian 88</address><address>Beijing 188</address><address>Shanghai 288</address><title/><salary></salary><Comments/></employee>
posted @ 2011-09-21 16:52 何杨 阅读(836) | 评论 (0)编辑 收藏

Compute节点的ESQL是:
CREATE COMPUTE MODULE flow_Compute
    
CREATE FUNCTION Main() RETURNS BOOLEAN
    
BEGIN
        
-- XML操作示例

        
SET OutputRoot.XML.employee.(XML.Attribute)id = '001';
        
SET OutputRoot.XML.employee.name = 'Felix';
        
SET OutputRoot.XML.employee.age = 33;

        
SET OutputRoot.XML.employee.address[1] = 'Dalian 88';
        
SET OutputRoot.XML.employee.address[2] = 'Beijing 188';
        
SET OutputRoot.XML.employee.address[3] = 'Shanghai 288';

        
SET OutputRoot.XML.employee.title.VALUE = NULL;
        
        
SET OutputRoot.XML.employee.salary VALUE = NULL;

        
SET OutputRoot.XML.employee.Comments.(XML.Content)=NULL;

        
RETURN TRUE;
    
END;
END MODULE;

最终得到的XML是:
<employee id="001"><name>Felix</name><age>33</age><address>Dalian 88</address><address>Beijing 188</address><address>Shanghai 288</address><title/><salary></salary><Comments/></employee>

工程下载:
posted @ 2011-09-21 16:13 何杨 阅读(547) | 评论 (0)编辑 收藏

任务:给根节点加上属性。

步骤:
仍然是使用一个MQ input节点,一个MQ output节点和一个Compute节点,Compute节点的ESql如下:
CREATE COMPUTE MODULE flow_Compute
    
CREATE FUNCTION Main() RETURNS BOOLEAN
    
BEGIN
        
SET OutputRoot = InputRoot;
        
        
DECLARE Count Integer 0;
        
SET Count=CARDINALITY(InputRoot.XML.employees.employee[]);
        
        
SET OutputRoot.XML.employees.(XML.Attribute)count=Count;
        
        
RETURN TRUE;
    
END;
END MODULE;

上图粗体部分为关键,它的作用是给employees节点增加了一个属性Count.

输入的XML分别如下:
<employees><employee><id>001</id><name>张飞</name><age>28</age></employee><employee><id>002</id><name>关羽</name><age>29</age></employee><employee>    <id>003</id><name>赵云</name><age>30</age></employee></employees>

输入和输出的XML分别如下:
<employees count="3"><employee><id>001</id><name>张飞</name><age>28</age></employee><employee><id>002</id><name>关羽</name><age>29</age></employee><employee>    <id>003</id><name>赵云</name><age>30</age></employee></employees>

工程下载:
posted @ 2011-09-21 13:22 何杨 阅读(533) | 评论 (0)编辑 收藏

其它和前例一样,但遍历代码如下:


CREATE COMPUTE MODULE flow_Compute
    
CREATE FUNCTION Main() RETURNS BOOLEAN
    
BEGIN
        
-- 员工总数
        DECLARE Count INTEGER 0;
        
-- 得到XML中员工总数
        SET Count=CARDINALITY(InputRoot.XML.employees.employee[]);
        
        
-- 员工姓名汇总
        DECLARE Names CHARACTER;
        
SET Names='';
                
        
-- 最大年龄
        DECLARE MaxAge INTEGER 0;
        
        
-- 年龄合计
        DECLARE SumAge INTEGER 0;
        
        
-- 当前年龄
        DECLARE CurrAge INTEGER 0;
        
        
-- 循环变量        
        FOR CurrItem AS InputRoot.XML.employees.employee[] DO
            
-- 字符串拼接 
            SET Names=Names || CurrItem.name ;
            
SET Names=Names || ',';
            
            
-- 字符串转换成整数再进行年龄合计 
            SET CurrAge = CAST(CurrItem.age AS INTEGER);
            
SET SumAge=SumAge+CurrAge;
            
            
-- 得到最大年龄
            IF MaxAge<CurrAge THEN
                
SET MaxAge=CurrAge;
            
END IF;
        
END FOR;
        
        
        
-- 平均年龄
        DECLARE AvgAge FLOAT;
        
SET AvgAge=SumAge/Count;
        
        
-- 拼接输出XML
        SET OutputRoot.XML.summary.count=Count;
        
SET OutputRoot.XML.summary.names=Names;
        
SET OutputRoot.XML.summary.maxAge=MaxAge;
        
SET OutputRoot.XML.summary.avgAge=CAST(AvgAge AS CHARACTER);
        
        
RETURN TRUE;
    
END;

END MODULE;

相比较而言,这种方式更简洁方便。

下载地址:
http://www.blogjava.net/Files/heyang/ESqlTest0920_02.rar
posted @ 2011-09-21 11:29 何杨 阅读(738) | 评论 (0)编辑 收藏

任务:将如下输入XML变成如下输出XML
输入XML:
<employees><employee><id>001</id><name>张飞</name><age>28</age></employee><employee><id>002</id><name>关羽</name><age>29</age></employee><employee>    <id>003</id><name>赵云</name><age>30</age></employee></employees>

输出XML:
<summary><count>3</count><names>张飞,关羽,赵云,</names><maxAge>30</maxAge><avgAge>2.9E+1</avgAge></summary>

我们需要做一个Input节点和一个Output节点以及一个Comput节点,并设置Compute节点的ESQL如下:
CREATE COMPUTE MODULE flow_Compute
    
CREATE FUNCTION Main() RETURNS BOOLEAN
    
BEGIN
        
-- 员工总数
        DECLARE Count INTEGER 0;
        
-- 得到XML中员工总数
        SET Count=CARDINALITY(InputRoot.XML.employees.employee[]);
        
        
-- 员工姓名汇总
        DECLARE Names CHARACTER;
        
SET Names='';
                
        
-- 最大年龄
        DECLARE MaxAge INTEGER 0;
        
        
-- 年龄合计
        DECLARE SumAge INTEGER 0;
        
        
-- 当前年龄
        DECLARE CurrAge INTEGER 0;
        
        
-- 循环变量        
        DECLARE I INTEGER 1;
        
WHILE I<=Count DO
            
-- 字符串拼接
            SET Names=Names || InputRoot.XML.employees.employee[I].name ;
            
SET Names=Names || ',';
            
            
-- 字符串转换成整数再进行年龄合计
            SET CurrAge = CAST(InputRoot.XML.employees.employee[I].age AS INTEGER);
            
SET SumAge=SumAge+CurrAge;
            
            
-- 得到最大年龄
            IF MaxAge<CurrAge THEN
                
SET MaxAge=CurrAge;
            
END IF;
            
            
SET I=I+1;
        
END WHILE;
        
        
-- 平均年龄
        DECLARE AvgAge FLOAT;
        
SET AvgAge=SumAge/Count;
        
        
-- 拼接输出XML
        SET OutputRoot.XML.summary.count=Count;
        
SET OutputRoot.XML.summary.names=Names;
        
SET OutputRoot.XML.summary.maxAge=MaxAge;
        
SET OutputRoot.XML.summary.avgAge=CAST(AvgAge AS CHARACTER);
        
        
RETURN TRUE;
    
END;

END MODULE;

本例工程下载地址:
http://www.blogjava.net/Files/heyang/ESqlTest0920_01.rar
posted @ 2011-09-21 10:59 何杨 阅读(681) | 评论 (0)编辑 收藏

任务:由于上一节传递到OutQ和OutQ1中的地址仍为原来的形式,现需要修改成对应的文字,即把
<address>大连/上海</address>变成<address>大连</address>或<address>上海</address>的形式。

1.修改Compute节点的ESQL,增加修改输出XML的一句:


CREATE COMPUTE MODULE flow_Compute
    
CREATE FUNCTION Main() RETURNS BOOLEAN
    
BEGIN
        
        
DECLARE Address CHARACTER;
        
DECLARE Addresses CHARACTER InputRoot.XML.mail.address;
        
DECLARE I INTEGER 0;
        
DECLARE J INTEGER;
        
DECLARE LEN INTEGER LENGTH(Addresses);
        
        
WHILE (I<LEN) DO
            
SET OutputRoot = InputRoot;
            
SET J=I+1;
            
SET Address=SUBSTRING(Addresses FROM J FOR 2);
            
            
SET OutputRoot.XML.mail.address=Address;-- 修改输出的地址部分
            SET OutputLocalEnvironment.Destination.RouterList.DestinationData[1].labelName = Address;
        
            PROPAGATE;
            
SET I=J+2;
        
END WHILE;
        
        
RETURN FALSE;
    
END;

END MODULE;


2.下图显示了修改地址后的结果:


-The End-
posted @ 2011-09-20 10:51 何杨 阅读(536) | 评论 (0)编辑 收藏

任务:ESQL中字符串处理


1.继续沿用上次的工程,注意修改两个Label节点的Label Name为汉字形式,并改写Compute节点的ESQL如下:
CREATE COMPUTE MODULE flow_Compute
    
CREATE FUNCTION Main() RETURNS BOOLEAN
    
BEGIN
        
        
DECLARE Address CHARACTER;
        
DECLARE Addresses CHARACTER InputRoot.XML.mail.address;
        
DECLARE I INTEGER 0;
        
DECLARE J INTEGER;
        
DECLARE LEN INTEGER LENGTH(Addresses);
        
        
WHILE (I<LEN) DO
            
SET OutputRoot = InputRoot;
            
SET J=I+1;
            
SET Address=SUBSTRING(Addresses FROM J FOR 2);
            
SET OutputLocalEnvironment.Destination.RouterList.DestinationData[1].labelName = Address;
        
            PROPAGATE;
            
SET I=J+2;
        
END WHILE;
        
        
RETURN FALSE;
    
END;

END MODULE;

2.将以下文本传入InQ:
<mail><id>0001</id><address>大连/上海</address></mail>

3.OutQ和OutQ1都将收到信息,如下图显示。




4.本例工程下载地址
http://www.blogjava.net/Files/heyang/InputOutputTest0919.rar

-The End-
posted @ 2011-09-20 10:34 何杨 阅读(555) | 评论 (0)编辑 收藏

任务:熟悉RouteToLabel节点,Label节点及Catch的使用

1.RouteToLabel节点在Routing下,与Filter节点在一起,label节点也在里面。如下图拖拽出一个RouteToLabel节点,两个Label节点。


2.再增加一个MQ Output节点Mq output2,关联到OutQ3。这个节点作用是当Compute导向出现异常(如address是深圳)时将信息发到OutQ3上。注意MQ
Mq output2到Mq Input的连线的起点和终点。


3.设置Compute节点的Compute Mode类型为ALL,这是为了在其中书写新的ESQL做的准备。


4.编辑Compute节点的新的ESQL。

SET OutputLocalEnvironment.Destination.RouterList.DestinationData[1].labelName = InputRoot.XML.mail.address;
这条语句会查看输入XML的mail节点的address节点的内容,如果能找到对应(mail节点的address节点的内容==Label节点的Label Name)的Label节点,则将消息导向到这个Label的后端;如果找不到的话,则将信息导向到Compute节点来源节点的catch端。

5.设置Label节点一(大连)的Label Name。


6.设置Label节点二(上海)的Label Name。


7.给各条连线加上断点,用以观察消息的流向。


8.当消息为“<mail><id>0001</id><address>dalian</address></mail>”时,如愿,消息被导向到了MQ Output。


-The End-
posted @ 2011-09-19 17:13 何杨 阅读(817) | 评论 (0)编辑 收藏

任务:熟悉Filter节点的使用。

1.Filter节点在Routing菜单下。


2.增加一个Filter节点和一个Output节点(与OutQ1关联),并如下连线。注意Filter的出口,MQ output是连到False口,而MQ Output1是连到true口。


3.连线完毕后Filter节点出现错误状态,此时我们需要编辑其ESQL,附带也把Compute节点的ESQL也编辑一下。


4.以下是Compute节点和Filter节点的新SQL。


5.启动测试后,向InQ输入XML文本如下:



6.OutQ1收到了转化分流后的结果,其内容正是我们想要的。


7.让我们改变一下小明的分数再测试一下:


8.结果如ESQL所料,OutQ得到了最终的信息。


-The end-
posted @ 2011-09-19 15:42 何杨 阅读(728) | 评论 (2)编辑 收藏

任务:熟悉Compute节点的使用及ESQL的基本写法。
注意:本节其它节点属性和上一节一样。

1.Compute节点在Transformation菜单下:


2.在MQInput节点和MQ Output节点之间插入一个Compute节点。由于没有设置节点属性,此时节点带有错误图标。


3.右键点击Compute节点,点击“Open ESQL”菜单。


4.在打开的窗口中输入下面文字。

第一句意思是从输入内容赋值到输出内容。
第二句意思是在employee节点下增加cnname节点
第三句意思是删除原有employee节点下的name节点
其它语句都是固定写法。

5.在InQ中输入XML文本,待会看看进过Compute节点转化后这段文本会变成什么样子。


6.查看OutQ中的输出结果,确实达到了ESQL语句的目的。


7.使用rfhutil.exe读取OutQ中的内容。


-The end-
posted @ 2011-09-19 14:53 何杨 阅读(1491) | 评论 (6)编辑 收藏

目的:学习使用Input和Output节点并继续熟悉WMB环境。

1.右键点击项目区,选择新建“Message Flow Project”.


2.右键点击刚才创建的项目,在其下建立一个“Message Flow”。


3.点击刚才创建的flow.msgflow,拖曳出一个MQInput节点和MQOutput节点。


4.点击下图红框中的图标,将两个节点连接起来。


5.如下图所示,注意箭头的起点位置。下图图标显示了错误和警告,这表示应该设置它们的属性,使其能和Queue对应起来。


6.打开Websphere MQ Explorer,在Queue manager "MB7QMGR"下建立两个消息队列,取名为InQ和OutQ。


7.右键点击MQ Input节点,点击属性,在下面的Q name处写入InQ。


8.邮件点击MQ Output节点,在属性中指定Queue manager name和Queue Name。


9.在项目下创建一个Message Broker Archive.这个用来将项目打包发布。


10.点击刚才创建的bar.bar,在右边点击按钮“Build Broker Archive”。


11.在IBM Websphere MQ Explorer中,右键点击InQ,选择“Put Test meesage”菜单。断点状态显示信息已经从MQ Input节点发送了出来。


12.将断点跑完,再在MQ Explorer中右键点击OutQ,选择“browse message”菜单,在弹出的窗口中可以看到,信息已经发送到了OutQ中。


-The End-
posted @ 2011-09-19 13:09 何杨 阅读(1291) | 评论 (3)编辑 收藏

本节任务:
     熟悉进行WMB开发需要用到的软件及环境.
 
1.WebSphere MQ及其操作工具WebSphere MQ Explorer:
       MB 的运行依赖于 MQ,所以首先要安装 MQ,MQ是就是 IBM 的消息中间件产品,IBM 几乎所有 SOA 相关的产品,都是构建于 MQ 之上的,没有 MQ 强大的消息传输能力,那么 IBM 很多产品都做不起来。你可以把MQ当成一个传输通道,只要往里面放东西,MQ 就会把消息传到目的地。      
       WebSphere MQ Explorer是用来操作MQ的工具,我们需要利用它来建立队列管理器及队列.下图就是WebSphere MQ Explorer的操作界面:
      

2.IBM WebSphere Message Broker Explorer:    
      IBM WebSphere Message Broker(以下称为 Message Broker)可以作为企业服务总线使用,提供用于各种协议的通用连接以及为使用结构化和非结构化数据的应用程序提供数据转换功能。WebSphere Message Broker(代理)的两个核心功能就是:“消息路由”和“消息格式转换”。它相当于一个公共服务中心。MB 接收所有消息,然后自动分析其中的内容,找到相应的目的地,进行路由转发;此外,MB 还可以进行消息转换,这就像是自动翻译信件. MB本质上也是一个服务总线,所有的服务组件接入到MB中,服务将消息塞给MB,MB来决定怎么转发,这样让服务愈加成为一个独立的实体,和其他服务的耦合性进一步降低,从而达到 SOA 的境界。(题外话:我个人觉得,SOA把业务分离出来的想法是好的,奈何当前所有模拟业务流程的工作流从根基上来说就是背离现实的,这就是SOA赖以生存的基础.因此SOA做得再好也只是修补性工作).
       下图是WMB的整体架构图:
          

3.WebSphere Message Broker Toolkit 7.0:
       这是操作WebSphere Message Broker的开发环境,它是基于Eclipse做成的,因此上手很快.我们大部分的工作都要依赖它来完成.
      
       以下是WebSphere Message Broker Toolkit的界面介绍:
             
      1 号区域是一个消息流,可以看到非常直观:从 MQ 读入—  —  计算(转换成 web service 格式)—  —发送 http 请求到 web service 的 url—  —  计算(转换回 MQ 消息格式)—  —  放入 MQ。
      2 号区域是节点选择面板,MB 自带了几十种节点给我们选择,同时我们也可以自己创建节点。
      3 号区域是属性面板,当你选择某个节点时,可以在其中编辑节点的属性。
      4 号区域是域连接面板,开发好的消息流和消息格式,必须首先在 MBT 中连接到对应的配置管理器,再将打包好的流程部署到对应的 broker 中,这个过程也可以由命令行完成。
      5 号区域则类似 eclipse 的项目集合,里面是所有的 MB 项目。

4.rfhutil.exe:

       这个工具用来往队列上发送消息以及读取消息,它是可选的,没有它我们也可以依靠WebSphere MQ Explorer来完成同样的工作.
      

本节结束。
posted @ 2011-09-18 16:31 何杨 阅读(3933) | 评论 (0)编辑 收藏

当网页提交时,如果提交内容较多时或者服务器响应较慢时容易有一段延迟,此事若是采用等待页面可加强用户使用感觉,具体实现如下:

网页内容:
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib uri="/WEB-INF/tld/struts-html.tld" prefix="html"%>
<%@ taglib uri="/WEB-INF/tld/struts-logic.tld" prefix="logic"%>
<%@ taglib uri="/WEB-INF/tld/struts-bean.tld" prefix="bean"%>
<%@ taglib uri="/WEB-INF/tld/struts-tiles.tld" prefix="tiles"%>

<style type="text/css">
    <!--
    
    
/*弹出层的STYLE*/
    .popupLoadingDiv 
{
        border
: 1px solid #336699;
        background
:#ffffff url(web/img/content_top_bg.gif) repeat-x 0px -20px;
        padding
:5px;
        text-align
: center;
        line-height
: 40px;
        font-size
: 12px;
        font-weight
: bold;
        z-index
:99;
        width
: 300px;
        height
: 120px;
        left
:50%;/*FF IE7*/
        top
: 50%;/*FF IE7*/
        
        margin-left
:-150px!important;/*FF IE7 该值为本身宽的一半 */
        margin-top
:-60px!important;/*FF IE7 该值为本身高的一半*/
        
        margin-top
:0px;
        
        position
:fixed!important;/*FF IE7*/
        position
:absolute;/*IE6*/
        
        _top
:       expression(eval(document.compatMode &&
                    document.compatMode=='CSS1Compat') ?
                    documentElement.scrollTop + (document.documentElement.clientHeight-this.offsetHeight)/2 :
/*IE6*/
                    document.body.scrollTop + (document.body.clientHeight - this.clientHeight)/2)
;/*IE5 IE5.5*/
    
    
}
    
    .grayBackground 
{
        background-color
: #ccc;
        width
: 150%;
        height
: 100%;
        left
:0;
        top
:0;/*FF IE7*/
        
        filter
:alpha(opacity=50);/*IE*/
        opacity
:0.5;/*FF*/
        z-index
:1;
        
        position
:fixed!important;/*FF IE7*/
        position
:absolute;/*IE6*/
        
        _top
:       expression(eval(document.compatMode &&
                    document.compatMode=='CSS1Compat') ?
                    documentElement.scrollTop + (document.documentElement.clientHeight-this.offsetHeight)/2 :
/*IE6*/
                    document.body.scrollTop + (document.body.clientHeight - this.clientHeight)/2)
;/*IE5 IE5.5*/
    
    
}
    
    #loadingDivTitleDiv
{
        font-size
:14px;  
        font-weight
:bold;       
        color
:#000000;
        text-align
:center;
        border-bottom
:1px dashed #336699;
    
}
    #loadingDivImgDiv
{
        padding-top
:5px;
        padding-bottom
:5px;
    
}
    #loadingDivInstructionDiv
{
        font-size
:12px;  
        font-weight
:normal;       
        color
:#000000;
        text-align
:center;
    
}
/*The END*/
    -->
</style>

<div id="loadingDiv" class="popupLoadingDiv" style="display:none">
    
<div id="loadingDivTitleDiv">提交中</div>
    
<div id="loadingDivImgDiv">
        
<img id="loadingImg" src="web/page/common/loading/loading.gif" border="0"/>
    
</div>
    
<div id="loadingDivInstructionDiv">正在提交,请稍候</div>
</div>
<div id="grayBackgroundDiv" class="grayBackground" style="display:none;">
    
<!-- 用来保持在选择框上的IFrame -->
    
<iframe id="innerFrame" style="position:absolute;z-index:-1;width:100%;height:100%;top:0;left:0;scrolling:no;" frameborder="0" src="about:blank">
    
</iframe>
</div>

<script language="javascript">
<!--

/*****************************************************
* 显示载入中div
* 何杨 2011年7月25日11:43:54
****************************************************
*/
function showLoadingWnd(){
    document.getElementById(
"loadingDiv").style.display="block";
    document.getElementById(
"grayBackgroundDiv").style.display="block";
    
    window.setTimeout('replayImg()', 
3000);
}

/*****************************************************
* 重新加载图片
* 何杨 2011-7-25 11:43:34
****************************************************
*/
function replayImg(){ 
   
var loadingImg = document.getElementById("loadingImg");
   loadingImg.src
=loadingImg.src;
}
//-->
</script>

在页面上如下载入上述页面:
<jsp:include page="/web/page/common/loading/loading.jsp" flush="true" />

需要弹出此窗口时使用如下JS函数:
showLoadingWnd()

代码从这里下载:
http://www.blogjava.net/Files/heyang/loading2011-09-09.rar

实现效果如图:
posted @ 2011-09-09 12:38 何杨 阅读(942) | 评论 (1)编辑 收藏

select sysdate+1  from dual -- 明天
select sysdate+1/24  from dual -- 1个小时后
select sysdate+1/(24*60)   from dual --1分钟后
select sysdate+1/(24*60*60)  from dual -- 一秒后
posted @ 2011-08-05 14:20 何杨 阅读(1563) | 评论 (0)编辑 收藏

parseInt函数常用来将字符串转化成数字,需要注意的是,如果参数的第一位是‘0’,如果不指定进制,它会默认按八进制转化,这就不是我们想要的结果了。
因此,为安全期间,最好在使用此函数时加上十进制,如下
var n=parseInt('08',10);

posted @ 2011-08-04 12:31 何杨 阅读(197) | 评论 (0)编辑 收藏

在ie6中,如果给Table表格的表投行TH设定背景图片,将导致IE6出现无响应的Bug,实例代码如下:
Table.stock th{
    font-size
:13px;
    font-weight
:normal;
    background-color
:#f2f9ff;
    
    color
:#333333;
    height
:20px;
    line-height
:20px;
    text-align
:center;
    
    border-left
:1px solid #d0d0d0;
    border-right
:1px solid #d0d0d0;
    border-bottom
:1px solid #d0d0d0;
    
    
/*background-image:url(titBg.gif); it will make IE6 no response.*/
    
/*background:#f2f9ff url(thbg.png) repeat-x;    it will also make IE6 no response.*/
}   

如果在IE8中则没有这样的问题,如果被迫适应IE6,只有取消上面粗体部分。
posted @ 2011-07-08 11:10 何杨 阅读(480) | 评论 (0)编辑 收藏

1.到Axis2网站下载Axis2的最新版本。
2.将下载包解压到本地。
3.设置环境变量AXIS2_HOME,其值为下载包的解压目录。
4.打开CMD,进入AXIS2_HOME指定目录下的bin目录。
5.使用命令wsdl2java -uri http://localhost:8088/AHCMS2_Service531/services/service?wsdl  -p client -s -o stub来生成Java代码。
执行完毕后,你会发现bin目录会多了一个stub文件夹,Java代码就在其中。

posted @ 2011-06-22 17:09 何杨 阅读(3033) | 评论 (0)编辑 收藏

BarCode4j确实简单易用,Sample稍微改写一下就可以达到目的了。
BarCode4j网址:http://sourceforge.net/projects/barcode4j/

二维码图片示例:


代码下载(注:代码是Sample的源码,基本没有改写,)
http://www.blogjava.net/Files/heyang/BarCodeTest.rar
posted @ 2011-06-15 17:13 何杨 阅读(2762) | 评论 (1)编辑 收藏

     摘要: 代码如下:1.Application类Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->package com.ibm.ahcms2.tool.jacob.word;import com.jacob.activeX.ActiveXCo...  阅读全文
posted @ 2011-06-04 20:12 何杨 阅读(4747) | 评论 (1)编辑 收藏

package com.heyang;

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;

public class ModifyWordDocument {
    
public static void main(String[] args) throws Exception {
        
// 初始化com的线程,非常重要!!使用结束后要调用 realease方法
        ComThread.InitSTA();

        
// 实例化ActiveX组件对象:对word进行操作
        ActiveXComponent wrdCom = new ActiveXComponent("Word.Application");

        
// 获取Dispatch的Documents对象
        Dispatch wrdDocs = wrdCom.getProperty("Documents").toDispatch();

        
// 设置打开的word应用程序是否可见
        wrdCom.setProperty("Visible"new Variant(true));

        
// 打开一个已经存在的文档
        Dispatch doc = Dispatch.call(wrdDocs, "Open""c:\\abc.doc")
                .toDispatch();

        
// 获得当前word文档文本
        Dispatch docSelection = Dispatch.get(wrdCom, "Selection").toDispatch();

        
// 从selection所在位置开始查询
        Dispatch find = Dispatch.call(docSelection, "Find").toDispatch();

        
// 设置要查找的内容
        Dispatch.put(find, "Text""测试");
        
// 向前查找
        Dispatch.put(find, "Forward""True");
        
// 设置格式
        Dispatch.put(find, "Format""True");
        
// 大小写匹配
        Dispatch.put(find, "MatchCase""True");
        
// 全字匹配
        Dispatch.put(find, "MatchWholeWord""True");

        Dispatch.call(find, 
"Execute").getBoolean();
        Dispatch.put(docSelection, 
"Text""岳飞");

        
// 另存为
        Dispatch.call(doc, "SaveAs"new Variant("C:\\abc.doc")); // 保存一个新文档

        
// 保存关闭
        if (doc != null) {
            Dispatch.call(doc, 
"Save");
            Dispatch.call(doc, 
"Close"new Variant(true));
            doc 
= null;
        }

        
// 关闭word文件
        wrdCom.invoke("Quit"new Variant[] {});
        
// 释放com线程。根据jacob的帮助文档,com的线程回收不由java的垃圾回收器处理
        ComThread.Release();
    }
}
posted @ 2011-06-03 11:42 何杨 阅读(949) | 评论 (0)编辑 收藏

package com.heyang;

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;


public class CreateWordDocument{
    
public static void main(String[] args) throws Exception{
        
// 初始化com的线程,非常重要!!使用结束后要调用 realease方法
        ComThread.InitSTA();
        
        
// 实例化ActiveX组件对象:对word进行操作
        ActiveXComponent wrdCom= new ActiveXComponent("Word.Application");
        
        
// 获取Dispatch的Documents对象
        Dispatch wrdDocs=wrdCom.getProperty("Documents").toDispatch();
        
        
// 设置打开的word应用程序是否可见
        wrdCom.setProperty("Visible"new Variant(true));
        
        
// 创建一个新的文档
        Dispatch doc = Dispatch.call(wrdDocs, "Add").toDispatch();
        
        
// 获得当前word文档文本
        Dispatch docSelection = Dispatch.get(wrdCom, "Selection").toDispatch();
        
        
// 输入文字
        Dispatch.put(docSelection, "Text""测试Text");

        
// 另存为
        Dispatch.call(doc, "SaveAs"new Variant("C:\\abc.doc")); // 保存一个新文档

        
// 保存关闭
        if (doc != null) {
            Dispatch.call(doc, 
"Save");
            Dispatch.call(doc, 
"Close"new Variant(true));
            doc 
= null;
        }
        
        
// 关闭word文件
        wrdCom.invoke("Quit"new Variant[] {});        
        
// 释放com线程。根据jacob的帮助文档,com的线程回收不由java的垃圾回收器处理
        ComThread.Release();
    }
}
posted @ 2011-06-03 11:16 何杨 阅读(396) | 评论 (0)编辑 收藏

用途:使用Java操作Office组件如Word,Excel等。
官方网址:http://danadler.com/jacob/
1.9版本下载页:http://download.csdn.net/source/709878
也可以从我的地址下载:http://www.blogjava.net/Files/heyang/jacob-Successfully.rar

使用方法:
jacob.jar放到包路径中;
jacob.dll放到C:\WINDOWS\system32下,有时有不配合出错的文件,网上给出解决方案是用1.7的jar配合1.9的dll使用,我试了一下效果还可以。

相关介绍文章:
http://blog.csdn.net/hemingwang0902/archive/2009/07/25/4377994.aspx
http://blog.csdn.net/helloxtayfnje/archive/2009/12/04/4935037.aspx
http://ishare.iask.sina.com.cn/f/7936765.html?from=like
http://jeady.blog.hexun.com/13957703_d.html
http://blog.csdn.net/Matol/archive/2010/11/26/6038087.aspx
http://hi.baidu.com/mingfang0219/blog/item/9648822c5469173a349bf701.html
posted @ 2011-06-02 21:04 何杨 阅读(284) | 评论 (0)编辑 收藏

           this.getJdbcTemplate().execute(
                
new CallableStatementCreator() {
                    
public CallableStatement createCallableStatement(Connection con) throws SQLException {
                        String storedProc 
= "{call updatetractractcode(?, ?)}";// 调用的存储过程
                        CallableStatement cs = con.prepareCall(storedProc);
                        cs.setInt(
1, contractId);// 设置输入参数的值
                        cs.registerOutParameter(2, java.sql.Types.INTEGER);// 注册输出参数的类型
                        return cs;
                    }
                }, 
new CallableStatementCallback() {
                    
public Object doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
                        cs.execute();
                        
return cs.getString(2);// 获取输出参数的值
                }
            });
posted @ 2011-06-02 09:05 何杨 阅读(1130) | 评论 (0)编辑 收藏

几个使用JDBC Template常用的工具类

第一:IntegerRowMapper

代码:

public class IntegerRowMapper implements RowMapper {

      public Object mapRow(ResultSet rs, int index) throws SQLException {

            Integer c = new Integer(0);

            c = rs.getInt(1);

            return c;

      }

}

用途:

SQL只是取数量时,可以采用这个类减少一些代码,示例如下:

StringBuilder sb=new StringBuilder();

sb.append("    SELECT");

sb.append("        count(*)");

sb.append("    FROM");

sb.append("        tb_contract");

sb.append("    WHERE");

sb.append("        contract_id='"+id+"' ");

String sql=sb.toString();

 

List<?> ls = this.getJdbcTemplate().query(sql, (new IntegerRowMapper()));

Integer i = (Integer) ls.get(0);

 

第二:StringRowMapper

代码:

public class StringRowMapper implements RowMapper {

      public Object mapRow(ResultSet rs, int index) throws SQLException {

            String c=new String(rs.getString(1));

        return c;

      }

}

用途:当SQL语句只返回一个字符串类型的定值时,采用这个类能减少部分代码,示例如下:

StringBuilder sb=new StringBuilder();

sb.append("    select");

sb.append("         user_name as name");

sb.append("    from");

sb.append("        TB_SYS_USER");

sb.append("    where");

sb.append("         user_id='"+userId+"'");

String sql=sb.toString();

 

List<?> ls = this.getJdbcTemplate().query(sql, (new StringRowMapper()));

String usrName=(String)ls.get(0);

 

第三:RecordCounter

代码:

public class RecordCounter{

      private String sql;

     

      private JdbcTemplate jdbcTemplate;

     

      /**

       * 构造函数

       * @param sql

       * @param jdbcTemplate

       */

      public RecordCounter(String sql,JdbcTemplate jdbcTemplate){

            this.sql=sql;

            this.jdbcTemplate=jdbcTemplate;

      }

     

      /**

       * 得到SQL语句查询到的记录数,对外的关键语句

       * @author: 何杨(heyanghy@cn.ibm.com

       * @date : Apr 23, 2011

       * @time : 11:09:35 AM

       * @return

       */

      public int getCount() throws Exception{

            StringBuilder sb=new StringBuilder();

            sb.append("    select ");

            sb.append("        count(*) as recordCount ");

            sb.append("    from ("+sql+") t ");

            String sql=sb.toString();

           

            class MyRowMapper implements RowMapper {

                  public Object mapRow(ResultSet rs, int index) throws SQLException {

                        Integer c = new Integer(0);

 

                        c=rs.getInt("recordCount");

 

                        return c;

                  }

            }

 

            List<?> ls = jdbcTemplate.query(sql, (new MyRowMapper()));

            Integer i=(Integer)ls.get(0);

           

            return i.intValue();

      }

}

用途:分页时常需要得到SQL语句查询得到的总记录数,采用这个类可以减少部分代码。

示例:略

 

第四:MapRowMapper

代码:

public class MapRowMapper implements RowMapper {

      public Object mapRow(ResultSet rs, int index) throws SQLException {

            List<Map<String,String>> ls=new ArrayList<Map<String,String>>();

       

        int n=rs.getMetaData().getColumnCount();

       

        for(int i=1;i<=n;i++){

            try{

                  Map<String,String> map=new HashMap<String,String>();

                  map.put(rs.getMetaData().getColumnName(i).toLowerCase(), rs.getString(i));

                 

                  ls.add(map);

            }

            catch(Exception ex){

                  continue;

            }

        }

       

        return ls;

      }

}

用途:一般来说,当查询只会返回一条记录时,如按ID得到一条记录,会使用这个Mapping器。得到的对象可以用来给对象赋值。示例如下:

StringBuilder sb=new StringBuilder();

sb.append("    select");

sb.append("        *");

sb.append("    from");

sb.append("        TB_CONTRACT ");

sb.append("    where");

sb.append("        contract_id='"+id+"'");

String sql=sb.toString();

 

List<?> ls = this.getJdbcTemplate().query(sql, (new MapRowMapper()));

 

Map<String,String> map = new HashMap<String,String>();

 

List<?> ls2=(List<?>)ls.get(0);

 

for(Object obj:ls2){

      Map<String,String> mapTemp=(Map<String,String>)obj;

     

      map.putAll(mapTemp);

}

第五:NameValueRowMapper

代码:

public class NameValueRowMapper implements RowMapper {

      public Object mapRow(ResultSet rs, int index) throws SQLException {

            List<NameValue> ls=new ArrayList<NameValue>();

       

        int n=rs.getMetaData().getColumnCount();

       

        for(int i=1;i<=n;i++){

            NameValue nv=new NameValue(rs.getMetaData().getColumnName(i).toLowerCase(),rs.getString(i));

            ls.add(nv);

        }

       

        return ls;

      }

}

 

public class NameValue extends BaseDomainObj{

      private String name;

      private String value;

     

      /**

       * 无参数构造函数

       */

      public NameValue(){

           

      }

     

      /**

       * 双参数构造函数

       * @param name

       * @param value

       */

      public NameValue(String name,String value){

            this.name=name;

            this.value=value;

      }

     

      public String getName() {

            return name;

      }

      public void setName(String name) {

            this.name = name;

      }

      public String getValue() {

            return value;

      }

      public void setValue(String value) {

            this.value = value;

      }

     

      public String asXML() {

            StringBuilder sb=new StringBuilder();

           

            sb.append("<"+name+">");

            sb.append(StringUtils.isBlank(value)?"-":value);

            sb.append("</"+name+">");

           

            return sb.toString();

      }

}

 

public class NameValueList extends BaseDomainObj{

      // 内含NameValue的链表

      private List<?> list;

     

      /**

       * 无参数构造函数

       */

      public NameValueList(){

           

      }

     

      /**

       * 带参数构造函数

       * @param list

       */

      public NameValueList(List<?> list){

            this.list=list;

      }

     

      @SuppressWarnings("unchecked")

      public String asXML() {

            StringBuilder sb=new StringBuilder();

           

           

            for(Object obj:list){

                  List<NameValue> ls=(List<NameValue>)obj;

                 

                  sb.append("<node>");

                  for(NameValue nv:ls){

                        sb.append(nv.asXML());

                  }

                  sb.append("</node>");

            }

           

           

            return sb.toString();

      }

 

      public void setList(List<?> list) {

            this.list = list;

      }

 

      public List<?> getList() {

            return list;

      }

}

说明:将一行记录转化成一个包含键值对的链表,在NameValueList的帮助下能方便的把从数据库得到的行集转化为一段XML

StringBuilder sb=new StringBuilder();

sb.append("    SELECT ");

sb.append("        *");

sb.append("    FROM tb_contract ");

sb.append("    WHERE contract_id='"+id+"'");

String sql=sb.toString();

 

List<?> ls=this.getJdbcTemplate().query(sql,new NameValueRowMapper());

 

NameValueList list=new NameValueList(ls);

 

String xml=list.asXML();

 

 

 

 

 

posted @ 2011-06-01 18:17 何杨 阅读(542) | 评论 (0)编辑 收藏

例如,父窗体中有一个JS方法名为showText(text),则在子窗体中,调用这个函数的方法是:
this.opener.showText("123ABC");
posted @ 2011-05-30 16:15 何杨 阅读(258) | 评论 (0)编辑 收藏

     摘要: 当一个div是以绝对定位方式,采用display="block"方式将其显示时,会发生select框出现在div上方的情况,这时的解决办法是在div放置一个iframe,具体代码如下(粗体部分是不被select遮挡的核心代码,另需要注意的是,有时要用JavaScript调整iframe的高度和宽度!):Code highlighting produced by Actipro CodeHighli...  阅读全文
posted @ 2011-05-29 12:55 何杨 阅读(2333) | 评论 (0)编辑 收藏

具体如下:
<bean:write name="log" property="nextActivity" filter="false"/>

如果nextActivity中有HTML如<br>,<div>等需要按照HTML显示的话,必须加上
属性filter="false",否则会把<br>,<div>这种文本内容显示出来。

posted @ 2011-05-29 11:21 何杨 阅读(1363) | 评论 (3)编辑 收藏

以前我们使用+或则concat对列进行合并,但将行合并就需要程序的支持,如Java或是PL/SQL,这样做有时可能会带来一些小麻烦。
如果是Oracle数据库的话,借助wmsys.wm_concat函数的帮助,可以对行进行合并:
如某用户表有如下数据:


使用SQL:
select  wmsys.wm_concat(name) from EMP
的效果如下:


也就是说wmsys.wm_concat能将行合并起来,并用逗号分隔开来。在取子类别,一对多关系中一方取多方数据时这个函数能起到事半功倍的效果。

凡事总有解决之道,所以要保持沉稳,坚强和自信。
posted @ 2011-05-29 11:00 何杨 阅读(633) | 评论 (0)编辑 收藏

这种方法还是比较迅速的,具体用法请见下面代码:

<html>
    
<head>
        
<title>test</title>
    
</head>
    
<body>
        
<id="link" href="www.baidu.com">百度</a>
        
<input type="button" onclick="showLinkText()" value="显示链接文字"/>
    
</body>
</html>

<script language="javascript">
<!--
function $(id){
    
return document.getElementById(id);
}

//-- 显示链接文字
function showLinkText(id){
    alert($(
"link").innerText);    
}

//-->
</script>

少看电视少上网,少看闲书少扯谈。
posted @ 2011-05-29 10:37 何杨 阅读(275) | 评论 (0)编辑 收藏

类代码:
/*************************
*
*   Class:CheckItem
*   2009.08.23
**************************/
//-- Contructor
function CheckItem(textboxName,msg,validChar,isRequired){
    this.textboxName=textboxName;
    this.msg=msg;
    this.validChar=validChar;
    this.isRequired=isRequired;
}

/*************************
*
*   Class:FormChecker
*   2009.08.23
**************************/
//-- Contructor
function FormChecker(){
    this.checkItemArray=new Array;
}

//-- Add a check Item to array
FormChecker.prototype.addCheckItem=function(textboxName,msg,validChar,isRequired){
    var checkItem=new CheckItem(textboxName,msg,validChar,isRequired);
    this.checkItemArray[this.checkItemArray.length]=checkItem;
}

//-- Check text field in the form 
FormChecker.prototype.checkTextBox=function(checkItem){
    var validChar=checkItem.validChar;
    var isRequired=checkItem.isRequired;
    var inputValue=$(checkItem.textboxName).value;
    
    if(isRequired!="true" && inputValue.length
<1){
        return true;
    }
    else{
        var regexStr
="^"+validChar+"$";
        var regex
=new RegExp(regexStr);
        return regex.test(inputValue);
    }
}

//-- judge the validation of a form
FormChecker.prototype.isValid
=function(){
    
for(var i=0;i<this.checkItemArray.length;i++){
        
var    toBeCheckedObj=this.checkItemArray[i];
        
        
var checkResult=this.checkTextBox(toBeCheckedObj);
        
        
if(checkResult==true){
            
continue;
        }
        else{        
            alert(toBeCheckedObj.msg);
            $(toBeCheckedObj.textboxName).focus();
            
            return false;
        }                
    }

    return true;
}


页面代码:
/*****************************************************
* 窗口载入时调用的启动函数
*****************************************************/
var formChecker;
window.onload=function(){
    // 设置主菜单的当前菜单项
    setMainmenuCurrentItem(0);
    
    // 设置侧边菜单的当前菜单项
    setSidemenuCurrentItemByText("合同起草");
    
    // 取得合同类别的数据
    // 填充下拉列表框数据
    new TypeListbox("contractTypeFirst","0","contractTypeSecond","");
    new TypeListbox("contractTypeSecond",$("contractTypeFirst").value,"contractTypeThird","");
    
    // var today=getToday();
    // $("createTime").value=today; // 屏蔽了合同起草时间,故这里也屏蔽。何杨,2011年5月6日9:20:34
    // $("maintenanceEndTime").value=today;
    
    // 初始化检查项
    formChecker=new FormChecker();
    formChecker.addCheckItem("contractName","请输入一到一百位的合同名",".{1,100}","true");
    formChecker.addCheckItem("contractTypeThird","请点击下拉列表框依次选择合同类别",".{1,100}","true");
    formChecker.addCheckItem("contractAmount","请输入数字形式的合同总金额(金额限制百亿内)","([0-9]{1})(\\d{0,9})","true");
    formChecker.addCheckItem("vendorName","请点击右边图标选择合同对方名称。",".{1,}","true");
    formChecker.addCheckItem("fulfillCycle","请输入数字形式的合同履行期限,以月为单位(最多十位数字)","([1-9]{1})(\\d{0,9})","true");
    formChecker.addCheckItem("maintenanceStartTime","请点击右边的按钮选择模板选择维保起始日期","(\\d{4})-(\\d{1,2})-(\\d{1,2})","false");
    formChecker.addCheckItem("maintenanceEndTime","请点击右边的按钮选择模板选择维保结束日期","(\\d{4})-(\\d{1,2})-(\\d{1,2})","false");
    
    formChecker.addCheckItem("contractBriefFile","请输入零到五百字的合同所属项目概况或依据的文件",".{1,500}","false");
    formChecker.addCheckItem("contractDecision","请输入零到一千字的项目决策过程",".{1,1000}","false");
    formChecker.addCheckItem("remark","请输入零到两百五十个字的补充说明",".{1,250}","false");
    formChecker.addCheckItem("maintenanceDescription","请输入零到一千个字的维保描述",".{1,1000}","false");
}

/*********************************************************************
*  得到表单的检查结果
*  何杨,2011-4-17 14:31:40
*********************************************************************/
function getCheckResult(){
    // 进行页面输入检查
    if(formChecker.isValid()==false){
        return false;
    }
    
    // 维保起始日期
    var maintenanceStartTime=$("maintenanceStartTime").value;
    
    // 维保结束日期
    var maintenanceEndTime=$("maintenanceEndTime").value;
    
    // 维保起始日期和维保结束日期做比较
    if(isNotEmptyString(maintenanceStartTime)==true && isNotEmptyString(maintenanceEndTime)==true){
        if(isReasonable(maintenanceStartTime,maintenanceEndTime)==false){
            alert("维保结束日期必须晚于维保起始日期.");
            $("maintenanceEndTime").focus();
            return false;
        }
    }
    
    return true;
}
posted @ 2011-05-23 08:58 何杨 阅读(225) | 评论 (0)编辑 收藏



js类代码:
/*************************************
*
*   Class:ContractTypeListboxOne
*   2011-5-18 20:08:00
**************************************/
//-- 构造函数
function TypeListbox(id,parentId,nextId,nextParentId){
    this.id=id;
    this.parentId=parentId;
    this.nextId=nextId;
    this.nextParentId=nextParentId;
    
    this.init();
    this.fillData($(this.id),parentId);
}

//-- 初始化
TypeListbox.prototype.init=function(){
    var ctrl=$(this.id);
    var me=this;
        
    ctrl.onchange=function(){
        me.changeEvent();
    }    
}

//-- 变化事件
TypeListbox.prototype.changeEvent=function(){
    var ctrl=$(this.id);
    
    if(this.nextId.length>0 && this.nextId!="none"){
        this.fillData($(this.nextId),ctrl.value);
    }
}

//-- 填充数据
TypeListbox.prototype.fillData=function(myListbox,parentId){
    /*if(parentId.length
<|| parentId=="none"){
        
return;
    }*/

    var url
=encodeURI('GetContractType.do?parentId='+parentId);
    
url=encodeURI(url);
    
    
new Ajax.Request(url,{     
           method:'get',     
           onSuccess: function(ajaxObj){    
                  // alert(ajaxObj.responseText);  
                var status
=ajaxObj.responseXML.getElementsByTagName("status")[0].firstChild.data;
                                
                
if(status=="ok"){
                    
// 返回正确信息

                    // 找到所有节点放入数组,为避免麻烦,节点名统一都设置成node比较好,不用实例变了,这里就要改变一次。
                    var arr
=ajaxObj.responseXML.getElementsByTagName("node");
                    
var length=arr.length;

                    
for(var i=myListbox.options.length-1;i>=0;i--){
                        myListbox.remove(i);
                    }
                    
                    var newOption=new Option;
                    newOption.value="";
                    newOption.text="--请选择--";
                    myListbox.add(newOption);

                    if(length>0){
                        // 遍历这个数组
                        for(var i=0;i
<length;i++){
                            var node
=arr[i];
                                                
                            
var id=node.getElementsByTagName("id")[0].firstChild.data;
                            
var name=node.getElementsByTagName("name")[0].firstChild.data;
                            
                            
var newOption=new Option;
                            newOption.value
=id;
                            
newOption.text=name;
                            
myListbox.add(newOption);
                        }
                    }
                    
                    myListbox.selectedIndex
=0;
                    
myListbox.fireEvent("onchange");
                }
                else{
                    // 返回错误信息
                    var text
=ajaxObj.responseXML.getElementsByTagName("text")[0].firstChild.data;
                    
alert(text);
                }
           },     
           onFailure: function(){ 
               alert("无法取得服务器的响应");
           }   
        }
      ); 
}


页面下拉列表框:

<tr>

<td width="100%" colspan="10">

<div class="inputText">

<label for="classOneCbo">合同类别:</label>

<select id="classOneCbo">

<option value="" selected>--请选择--</option>

</select>

<font color="#003366">-</font>

<select id="classTwoCbo">

<option value="" selected>--请选择--</option>

</select>

<font color="#003366">-</font>

<select id="classThreeCbo">

<option value="" selected>--请选择--</option>

</select>

</div>

</td>

</tr>


页面JS初始化代码:

/*****************************************************

* 窗口载入时调用的启动函数

* 何杨,2011年4月22日16:59:16

*****************************************************/

window.onload=function(){

// 设置主菜单的当前菜单项

setMainmenuCurrentItem(0);

// 设置侧边菜单的当前菜单项

setSidemenuCurrentItemByText("待办事项");

// 填充下拉列表框数据

new TypeListbox("classOneCbo","0","classTwoCbo","");

new TypeListbox("classTwoCbo",$("classOneCbo").value,"classThreeCbo","");

// 开始检索初始数据

search(0);

}




posted @ 2011-05-19 14:50 何杨 阅读(632) | 评论 (1)编辑 收藏

<html>
    
<head>
        
<title>test</title>
    
</head>
    
<body>
        
<select id="mySelect">
            
<option value="1">地球</option>
            
<option value="2">火星</option>
            
<option value="3">木卫二</option>
            
<option value="4">冥王星</option>
            
<option value="5">参宿四</option>
            
<option value="6">人马座</option>
        
</select>
    
</body>
</html>

<script language="javascript">
<!--
window.onload
=function(){
    
var listBox=new ListBox("mySelect");
    
}


function $(id){
    
return document.getElementById(id);
}


//-- 类构造函数
function ListBox(id){
    
this.id=id;
    
this.init();    
}

//--类的初始化函数,将控件的onchange事件交给类的changeEvent事件处理
ListBox.prototype.init=function(){
    
var ctrl=$(this.id);
    
var me=this;
        
    ctrl.onchange
=function(){
        me.changeEvent();
    }

    
}

// onchange事件产生时弹出下拉列表控件的值
ListBox.prototype.changeEvent=function(){
    
var ctrl=$(this.id);
    alert(ctrl.value);
}

//-->
</script>
posted @ 2011-05-19 08:15 何杨 阅读(204) | 评论 (0)编辑 收藏

一般来说,出现这种异常是因为传递给远程方法的参数不能实例化所致,比如有一个参数是复合类型,里面包括Calendar,Date,BigDecimal等形式的数据,需要把这些非基本类型的数据new出来赋值,然后再调用就好办了。基本类型和String等数据则不用理会。



posted @ 2011-04-09 21:16 何杨 阅读(7714) | 评论 (0)编辑 收藏

Table.stock tr{
    onmouseover 
: expression(onmouseover=function (){this.style.backgroundColor ='#b3ddfb'}); 
    onmouseout  : expression(onmouseout=function () 
{this.style.backgroundColor =''});
}
posted @ 2011-03-30 19:51 何杨 阅读(361) | 评论 (0)编辑 收藏

一.以目录形式打开某个较深不易记忆的目录。
explorer  path
例子:explorer C:\Program Files\IBM\SDP70\runtimes\base_v61\profiles\AppSrv01\logs\server1

二.控制台方式进入某个目录。
在此目录下建一个bat文件,里面只写cmd三个字。然后创建快捷方式到桌面就可以了。

posted @ 2011-03-16 23:38 何杨 阅读(209) | 评论 (0)编辑 收藏

将程序从一个容器换到另一个容器,总会有各种意料之外的困难需要解决,近日本人需要将一个Web工程从Tomcat环境转移到WebSphere环境,经历了一番周折,特地将此经过记录下来,也许它能对将要进行如此经历的人其一点帮助作用,另外在此也向网络同仁和工作中的同事表示感谢。

原环境:
程序:SSH
容器:Tomcat6.0
数据库:MySql5

新环境:
程序:SSH
容器:WebSphere6.1
数据库:Oracle10g

移植过程中的第一个困难,是WebSphere不认识Web.xml中的Struts taglib.原文字(适用于Tomcat)如下:
<!-- Struts的TLDS -->
    
<taglib>
        
<taglib-uri>/WEB-INF/tld/app.tld</taglib-uri>
        
<taglib-location>/WEB-INF/tld/app.tld</taglib-location>
    
</taglib>

    
<!-- Struts Tag Library Descriptors -->
    
<taglib>
        
<taglib-uri>/WEB-INF/tld/struts-bean.tld</taglib-uri>
        
<taglib-location>/WEB-INF/tld/struts-bean.tld</taglib-location>
    
</taglib>

    
<taglib>
        
<taglib-uri>/WEB-INF/tld/struts-html.tld</taglib-uri>
        
<taglib-location>/WEB-INF/tld/struts-html.tld</taglib-location>
    
</taglib>

    
<taglib>
        
<taglib-uri>/WEB-INF/tld/struts-logic.tld</taglib-uri>
        
<taglib-location>/WEB-INF/tld/struts-logic.tld</taglib-location>
    
</taglib>

这个问题因为之前有所准备,在网络上找到了答案,将上述文字包在<jsp-config>节点中即可,修改后(对Tomcat和WebSphere均适用)的文字如下:
<!-- Struts的TLDS -->
    
<jsp-config>
        
<taglib>
            
<taglib-uri>/WEB-INF/tld/app.tld</taglib-uri>
            
<taglib-location>/WEB-INF/tld/app.tld</taglib-location>
        
</taglib>

        
<!-- Struts Tag Library Descriptors -->
        
<taglib>
            
<taglib-uri>/WEB-INF/tld/struts-bean.tld</taglib-uri>
            
<taglib-location>
                /WEB-INF/tld/struts-bean.tld
            
</taglib-location>
        
</taglib>

        
<taglib>
            
<taglib-uri>/WEB-INF/tld/struts-html.tld</taglib-uri>
            
<taglib-location>
                /WEB-INF/tld/struts-html.tld
            
</taglib-location>
        
</taglib>

        
<taglib>
            
<taglib-uri>/WEB-INF/tld/struts-logic.tld</taglib-uri>
            
<taglib-location>
                /WEB-INF/tld/struts-logic.tld
            
</taglib-location>
        
</taglib>
    
</jsp-config>

如此处理后,首页显示出来了,随即翻页遇到了问题,在IE中是翻页出现404错误,在FF中好一点,它告诉我WebSphere无法解析struts配置文件struts-config.xml。
起初我以为是中文问题,删除struts-config.xml中所有中文注释问题依旧,接下来在网络中寻找,还真有和我遇到一样问题的难友,但没人提出解决方案,正在挠头之际,我们的PM忽然说是否JDK不一致,检查一下,本机用的是1.6,而WebSphere自带1.5的,将本机也调成1.5后,问题解决! 真是只有咒语能解开咒语。

再下来,在表单提交时遇到了乱码问题,这是因为之前听信网络意见,将Web.xml中的filter都去掉了,结果自然乱码。此时感觉网络传闻未必可信,于是将filter又重新加上,乱码没有了。看来不经亲自尝试而盲从网络传闻是要吃亏的。

再下来,程序要访问数据库了,于是在WebSphere6.1中设置了数据源,再在Spring配置文件中进行了设置,如下:
<bean id="dataSource"
        class
="org.springframework.jndi.JndiObjectFactoryBean">
        
<property name="jndiName"
            value
="java:comp/env/jdbc/*******DS">
        
</property>
</bean> 


这样写在Tomcat中好用,在WebSphere不好用,正在挠头之际,PM告我别的项目有同样的写法,于是一看,java:comp/env/这部分是不需要的,直接把数据源JNDI名写在Value中就可以了。
<bean id="dataSource"
        class
="org.springframework.jndi.JndiObjectFactoryBean">
        
<property name="jndiName"
            value
="jdbc/*******DS">
        
</property>
</bean> 

其它数据库移植的问题就交给了Hibernate。至此问题全部解决。

事后来看,WebSphere6.1对中文,SSH的支持还是很好的,只是有些特定的地方和传统的Tomcat中的项目不太一样,注意一下就好了,未必有想象中的困难。遇到困难时,向有同样经历的人请教比自己在网络上搜寻要快很多。
posted @ 2011-03-16 22:43 何杨 阅读(402) | 评论 (2)编辑 收藏

下载地址:
http://www.blogjava.net/Files/heyang/RSAWebServiceSample.zip

posted @ 2011-03-16 00:30 何杨 阅读(234) | 评论 (0)编辑 收藏

     摘要:   第一部分:页面中JavaScript的写法:   function isSoleContractName(contractNameTextBox){                 var&nb...  阅读全文
posted @ 2011-03-14 11:35 何杨 阅读(359) | 评论 (0)编辑 收藏

第一部分:Web.Xml中ContextLoaderListener的相关配置
在工程目录下的\WebContent\WEB-INF\web.xml中,我们可以发现以下配置:

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext-*.xml</param-value>
</context-param>

 

<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

以上第一段XML中,contextConfigLocation参数定义了要载入Spring上下文的配置文件,这里采用了通配符的方式,也可以通过逗号符来分隔多个文件。
以上第二段XML定义了一个监听器,它适用于Servlet2.3及其以上版本,这个监听器会随着WebApp的启动而启动,并加载contextConfigLocation参数中定义好的Spring配置文件。若是在Servlet2.3以下版本中,则需要定义org.springframework.web.context.ContextLoaderServlet来载入配置文件。

第二部分:Action Bean的配置
接下来我们需要将Struts2的Action交给Spring管理,以com.heyang.module.contract.action. CheckSoleContractNameAction类为例,它在Spring配置文件\WebContent\WEB-INF\applicationContext-action.xml中的相应配置为:

<bean id="checkSoleContractNameAction"   class="com.heyang.module.contract.action.CheckSoleContractNameAction" singleton="false">
        
<property name="contractService">
            
<ref bean="contractService"/>
        
</property>
</bean>

由上面的XML知道,如果我们取得名为checkSoleContractNameAction的bean,Spring将通过反射调用一个com.heyang.module.contract.action.CheckSoleContractNameAction类的实例,并将一个名为contractService的bean注入进去,当然CheckSoleContractNameAction需要拥有此属性并具备对应的setter/getter。

第三部分:在Struts配置文件中将url映射到Spring上下文中的bean
这种方式是通过指定<action>的class属性为Spring配置文件中相应bean的id值来做到的,再以CheckSoleContractNameAction为例,它在Struts2配置文件WebContent\WEB-INF\struts-cfg\contract\struts.xml中的相应设置为:
<action name="checkSoleContractName" class="checkSoleContractNameAction" method="execute"/>
这样,当页面中url有对应用上下文/contract/checkSoleContractName.action?...
时,com.heyang.module.contract.action.CheckSoleContractNameAction类的execute方法将会来处理用户的请求。注意,这段url中,应用上下文是WebApp Context,contract是action所在包的名称空间,checkSoleContractName则是action的name。

至此,Struts2和Spring的整合配置讲述完毕。

第四部分:Struts2与Spring的整合原理
在\WebContent\WEB-INF\lib\下存在一个struts2-spring-plugin-2.0.9.jar,这个插件包的作用是通过覆盖(override)Struts2的ObjectFactory来增强核心框架对象的创建。当Struts2需要根据配置文件创建一个Action的时候,它会用Struts2配置文件中的class属性去和Spring配置文件中的id属性进行关联,如果能找到,则由Spring创建;否则由Struts 2框架自身创建。这个功能是通过插件提供的两个拦截器实现的,默认情况下框架使用的自动装配策略是name,也就是说框架会去Spring中寻找与Action属性名字相同的bean,可选的装配策略还有:type、auto、constructor等。

第五部分:Spring与Hibernate的整合
通常来说,每个负责具体请求的Action都会被注入一个或多个Service bean(参见applicationContext-action.xml),而每个Service Bean都会被注入一个DAO bean(参见applicationContext-dao.xml),而每个dao bean都被被注入一个hibernateTemplate来与数据库交互(参见applicationContext-dao.xml),而在applicationContext-db.xml中,说明了hibernateTemplate的由来,它最终会找到一个datasource从而找到数据库。

这样,从前台Struts2的控制器到后台数据库,S2SH整个链条就被串起来了。

posted @ 2011-03-13 23:41 何杨 阅读(602) | 评论 (0)编辑 收藏

PNG图片作为网页图的一个好处是它允许有透明背景,这一点比gif格式做得要好,但也有不如意的地方,就是在FireFox上PNG的透明背景显示得很好,但是在IE中就做不到了,这就需要滤镜技术的帮助。

比如有一张图片作为logo,它放在一个id为logodiv的DIV中,在CSS中是这样定义的:
#logoDiv{
    width
:300px;
    height
:100%;
    background
:transparent url(../img/logo.png) no-repeat -65px 0px;
}

这张图片在FF显示没有问题,在IE6中就需要加上这样一段:
*html #logoDiv{
    width
:300px;
    height
:100%;
    margin-left
:-65px;
    background-color
:transparent;
    background-image
:none;
    filter
:progid:DXImageTransform.Microsoft.AlphaImageLoader(src="web/img/logo.png", sizingMethod="crop");
}
这段代码FireFox是不认识的,会被略过,图片会继续上面#logoDiv的效果,而IE会用下面一段取代上面这一段,所以滤镜透明图片的效果就出现了。这两段代码放在一起,无论客户浏览器是IE6或是FireFox都能适应了。

使用滤镜有两点需要注意的:一是图片地址是网页相对app的地址,不是css相对app的地址,所以上面两处路径会有差异;另外一点是在不同的IE滤镜的写法也有差异,需要根据客户浏览器实际情况调整一下。

具体代码请见,其中有三处使用了滤镜,分别是logo,主菜单左侧和右侧,您可以从下面的代码中去寻找它们
http://www.box.net/shared/tz5k1um68l
http://www.box.net/shared/mbdf2e85yi



posted @ 2011-03-04 13:13 何杨 阅读(906) | 评论 (0)编辑 收藏

说明:下文涉及的内容只限于对前端jsp和后台servlet的代码修改,不涉及Web容器和数据库的相关修改。
我的测试环境是:英文XP操作系统,容器采用Tomcat6,前台是jsp,后台Servlet,Ajax框架采用prototype1.6.0

Web编程中前后端乱码问题发生的根源
从前端jsp到后台的Servlet,中间传输过程中的默认编码方式是ISO-8859-1,这种编码方式是西欧字符集,包括英语,德语,丹麦语,芬兰语等,其它语言如中文日文等是不兼容的,如不经转换或是设置直接在Servlet中用request.getParameter(paramName)这种方式直接拿出来中文部分就会得到乱码,但英语,字母,数字组合成的字符串是不会变成乱码的。

常见的编码解决乱码问题的方式有
  • new String(request.getParameter(paramName).getBytes("ISO-8859-1"),"页面字符集");
  • HttpServletRequest.setCharacterEncoding("页面字符集");
  • URLDecoder.decode(str, "UTF-8");
它们各自用在不同的场合,这里的页面字符集指GBK,GB2312,UTF-8等,它们通常和jsp页面设定的字符集(charset)一致。

如果是将form通过post方式提交,在servlet的doPost函数开头(对于Struts写在execute函数开头)写上request.setCharacterEncoding("jsp网页字符集")就可以直接用request.getParameter(paramName)直接得到文字,不需要经过再转码。这里需要注意的是form的action如果不直接写成post的话,是会以get方式提交,这时request.setCharacterEncoding就会失效。

如果不管是post还是get方式,想做一个通用方案,则可以通过new String(request.getParameter(paramName).getBytes("ISO-8859-1"),"jsp网页编码方式")得到转码后正常的文字,这种方式只要知道网页的字符集,几乎都能还原成正确的文字,适用性很广,在Servlet和Action中很常见。

如果是Ajax提交方式,则在servlet或是action中书写request.setCharacterEncoding("jsp网页字符集")是没有效果的,经过对提交的URL用一次javascript的encodeURI函数编码后,用 new String(request.getParameter(paramName).getBytes("ISO-8859-1"),"jsp网页字符集")可以得到正确的文字。但如果不用encodeURI函数处理提交的url则不会正确的文字。

Ajax提交中文的另一种方式可以用javascript的encodeURI函数对提交的URL进行两次编码,而后台采用URLDecoder.decode(request.getParameter(paramName), "UTF-8")得到正确的文字。

上面两种方式都借助了avascript的encodeURI函数的帮助,它能将字符串进行utf-8编码,其中,第二种方式确定性很高,推荐。

具体方式请参考下面给出的例程,里面含有12个例子,分别对应了多种情况:
http://www.blogjava.net/Files/heyang/DisorderCode2011-01-31.zip



参考文章:
深入浅出 web 编码(转载整理)
http://www.blogjava.net/heyang/archive/2011/01/26/343570.html
posted @ 2011-01-30 18:07 何杨 阅读(1828) | 评论 (0)编辑 收藏

以下代码主体来自互联网,原作者已经不可考,在此向这些有共享精神的作者致敬。

一.日期的合法性校验
以下代码中进行验证的主函数是isValidDateString,它的输入是类似2011-1-27这样的字符串,如果合法就返回真,否则返回假。如果您的日期格式不同,请将验证主函数中的正则表达式修改之,比如说输入是2011/1/27这样的字符串,则pattern=/^ *(\d{4})[/](\d{1,2})[/](\d{1,2})*$/;
// 进行日期合法性验证的主函数
function
 isValidDateString(dateString){
    
var pattern=/^ *(\d{4})-(\d{1,2})-(\d{1,2})*$/;
    
var arr=pattern.exec(dateString);
    
   
var year=arr[1];
    
var month=arr[2];
    
var dday=arr[3];

    
return IsValidDate(year,month,dday);
}


function IsValidYear(psYear)
{
    
var sYear = new String(psYear);


    
if(psYear==null)
    {
        
return false;
    }


    
if(isNaN(psYear)==true)
    {
        
return false;
    }

    
if(sYear == "")
    {
        
return true;
    }

    
if(sYear.match(/[^0-9]/g)!=null)
    {
        
return false;
    }

    
var nYear = parseInt(sYear, 10);

    
if((nYear < 0|| (9999 < nYear))
    {
        
return false;
    }

    
return true;
}


function IsValidMonth(psMonth)
{
    
var sMonth = new String(psMonth);

    
if(psMonth==null)
    {
        
return false;
    }

    
if(isNaN(psMonth)==true)
    {
        
return false;
    }

    
if(sMonth == "")
    {
        
return true;
    }

    
if(sMonth.match(/[^0-9]/g)!=null)
    {
        
return false;
    }

    
var nMonth = parseInt(sMonth,10);

    
if((nMonth < 0|| (12 < nMonth))
    {
        
return false;
    }

    
return true;
}


function IsValidDay(psDay)
{
    
var sDay  = new String(psDay);

    
if(psDay==null)
    {
        
return false;
    }

    
if(isNaN(psDay)==true)
    {
        
return false;
    }

    
if(sDay == "")
    {
        
return true;
    }

    
if(sDay.match(/[^0-9]/g)!=null)
    {
        
return false;
    }

    
var nDay = parseInt(psDay, 10);

    
if((nDay < 0|| (31 < nDay))
    {
        
return false;
    }

    
return true;
}


function IsValidDate(psYear, psMonth, psDay)
{
    
if(psYear==null || psMonth==null || psDay==null)
    {
        
return false;
    }

    
var sYear  = new String(psYear);
    
var sMonth = new String(psMonth);
    
var sDay   = new String(psDay);

    
if(IsValidYear(sYear)==false)
    {
        
return false;
    }

    
if(IsValidMonth(sMonth)==false)
    {
        
return false;
    }

    
if(IsValidDay(sDay)==false)
    {
        
return false;
    }

    
var nYear  = parseInt(sYear,  10);
    
var nMonth = parseInt(sMonth, 10);
    
var nDay   = parseInt(sDay,   10);

    
if(sYear=="" &&  sMonth=="" && sDay=="")
    {
        
return true;
    }

    
if(sYear=="" || sMonth=="" || sDay=="")
    {
        
return false;
    }
   
    
if(nMonth < 1 || 12 < nMonth)
    {
        
return false;
    }
    
if(nDay < 1 || 31 < nDay)
    {
        
return false;
    }

    
if(nMonth == 2)
    {
        
if((nYear % 400 == 0|| (nYear % 4 == 0&& (nYear % 100 != 0))
        {
            
if((nDay < 1|| (nDay > 29))
            {
                
return false;
            }
        }
        
else
        {
            
if((nDay < 1|| (nDay > 28))
            {
                
return false;
            }
        }
    }
    
else if((nMonth == 1)  ||
            (nMonth 
== 3)  ||
            (nMonth 
== 5)  ||
            (nMonth 
== 7)  ||
            (nMonth 
== 8)  ||
            (nMonth 
== 10||
            (nMonth 
== 12))
    {
        
if((nDay < 1|| (31 < nDay))
        {
            
return false;
        }
    }
    
else
    {
        
if((nDay < 1|| (30 < nDay))
        {
            
return false;
        }
    }

    
return true;
}


二.日期的比较
下面函数是进行日期比较如果date1小于等于date2,则返回真,否则返回假。注意这两个参数都应该通过了上面的日期合法性校验,请注意先验证一下。
function isReasonable(startDate,endDate){

    startDate=startDate.replace("-","/");
    endDate=endDate.replace("-","/");

    var dt1=new Date(Date.parse(startDate));
    var dt2=new Date(Date.parse(endDate));
      
    return dt1<=dt2;
}

posted @ 2011-01-27 16:51 何杨 阅读(874) | 评论 (3)编辑 收藏

在Ajax程序中,在URL拼接时带有中文参数是不可避免的事情,如
var url='/YourAppName/CreateTodo.do?name='+name;
其中name是来自inputbox的取值,它可能带有中文。

如果让Ajax直接提交这样的URL,那么后台用request.getParameter("name");这样的方法得到的name就会含有乱码。

解决之道是先对URL进行两次编码,用的是JavaScript的encodeURI函数,具体代码如下:
var url=encodeURI('/YourAppName/CreateTodo.do?name='+name);
url
=encodeURI(url);

在后台的Servlet或是Action中,可以这样得到正确的文字:
Sting name=java.net.URLDecoder.decode(request.getParameter("name"),"utf-8");

就是这样,值得注意的是,中文环境的机器用容器跑WebApp也许不需要这样的处理,但其它环境如日文,英文就非此不可了,因此在编码时尽可能这样处理一下,如果安装后出现问题就会造成慌乱了。我们在编写Web程序时,最好让文件编码,数据库编码,输出编码,网页编码保持一致,这样能省去很多麻烦。

以上操作的具体原理请见:
http://yiminghe.javaeye.com/blog/243812
http://yiminghe.javaeye.com/blog/247837

posted @ 2011-01-26 14:46 何杨 阅读(2052) | 评论 (1)编辑 收藏

已有功能:
进行混合加密的消息传递,用户注册,登录,取RSA公钥,得到用户列表,通过服务器中转消息。

修正点:
1.针对较长文字改变了解析方式。
2.聊天界面又向QQ靠拢了一些。

下载地址:
http://www.blogjava.net/Files/heyang/IMSample2011-01-25-1320.zip

界面截图:



posted @ 2011-01-25 13:18 何杨 阅读(234) | 评论 (2)编辑 收藏

一般说的组合键,是指在按下某个特定的键的时候,有另一些键处于某个特定的状态。例如:按回车enter,且CTRL键处于按下的状态,就认为是按了CTRL+回车这个组合键。

下面是具体的代码,myTextArea是一个文本区域组件(JTextArea)。注意其中粗体部分:
myTextArea.addKeyListener(new KeyListener(){
            @Override
            
public void keyReleased(KeyEvent arg0) {
                 
if ( arg0.getKeyCode() == KeyEvent.VK_ENTER && 
                    ((arg0.getModifiersEx() 
& KeyEvent.CTRL_DOWN_MASK) != 0) && 
                    ((arg0.getModifiersEx() 
& KeyEvent.SHIFT_DOWN_MASK) == 0)   ) {
                         
//   do something......
                 }
            }
            
            @Override
            
public void keyPressed(KeyEvent arg0) {
                
// do nothing
                
            }

            @Override
            
public void keyTyped(KeyEvent arg0) {
                
// do nothing
                
            }
        });
上面粗体部分第一句意味着回车键处于按下状态;
第二句意味着同时Ctrl键处于按下状态;
第三句意味着Shift键没有处于按下状态;
整个条件就是指在ctrl+enter键按下时,执行特定的处理。

Java文本组件中检测组合键就是这样简单。
posted @ 2011-01-25 11:24 何杨 阅读(502) | 评论 (0)编辑 收藏

下载地址:
http://www.box.net/shared/ccymfosmyu

本版改善功能:
1.客户端界面朝QQ靠近了点。
2.去除了发送信息时的一个潜在隐患。

posted @ 2011-01-24 21:39 何杨 阅读(171) | 评论 (1)编辑 收藏

myFrame.setExtendedState(JFrame.NORMAL);
myFrame.toFront();

myFrame是从Swing的JFame继承而来的类。

posted @ 2011-01-24 17:07 何杨 阅读(981) | 评论 (0)编辑 收藏

       // 设定布局
        int gridx, gridy, gridwidth, gridheight, anchor, fill, ipadx, ipady;
        
double weightx, weighty;
        GridBagConstraints c;
        Insets inset;
        GridBagLayout gridbag 
= new GridBagLayout();
        
this.setLayout(gridbag);
        
        
// 0,0
        gridx = 0;
        gridy 
= 0;
        gridwidth 
= 1;
        gridheight 
= 1;
        weightx 
= 1.00;
        weighty 
= 1.00;
        anchor 
= GridBagConstraints.CENTER;
        fill 
= GridBagConstraints.BOTH;
        inset 
= new Insets(up, left, down, right);
        ipadx 
= 0;
        ipady 
= 0;
        c 
= new GridBagConstraints(gridx, gridy, gridwidth, gridheight,
                weightx, weighty, anchor, fill, inset, ipadx, ipady);
        JScrollPane js
=new JScrollPane(msgArea);
        gridbag.setConstraints(js, c);
        
this.add(js);

        以上代码中,Insets构造函数四个参数的顺序依次为上,左,下,右, 逆时针方向。这样比较好记忆。
        Swing中其它类似的四参数形式(如BorderFactory.createEmptyBorder(top, left, down, right))也类同此例。

posted @ 2011-01-24 15:00 何杨 阅读(3226) | 评论 (0)编辑 收藏

将文字在网络中进行传输的时候,如果存在非ASCII码字符,很容易出现乱码问题,要解决也不难,在传输的文字上用URLEncoder进行编码,将它变成全部是ASCII码的形式,这样在网络传输中就不会受到影响;在另一侧,将收到的文字用URLDecoder加码就能还原文字原本的摸样。

IMSample中涉及到文字的混合加密,情况稍复杂一点,但流程还是一样的。


相关涉及编码和解码的工具类:
package com.heyang.common.code;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;


/**
 * UTF8转码器
 * 
@author heyang
 *
 
*/
public class UTF8Coder{
    
private static final String UTF_8 = "utf-8";// 编码形式

    
/**
     * 对文字进行UTF8转码
     * 
@param str
     * 
@return
     
*/
    
public static String encode(String str){
        
try {
            
return URLEncoder.encode(str, UTF_8);
        } 
catch (UnsupportedEncodingException e) {
            
return null;
        }
    }
    
    
/**
     * 将转码后的文字还原
     * 
@param str
     * 
@return
     
*/
    
public static String decode(String str){
        
try {
            
return URLDecoder.decode(str, UTF_8);
        } 
catch (UnsupportedEncodingException e) {
            
return null;
        }
    }
}

变化后的加密器代码:
package com.heyang.common.cipher;

import org.apache.commons.codec.binary.Base64;

import com.heyang.common.code.AESSecurityCoder;
import com.heyang.common.code.Base64SecurityUtil;
import com.heyang.common.code.RSASecurityCoder;
import com.heyang.common.code.UTF8Coder;

/**
 * 对消息进行加密的加密器
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 * 创建时间:2010-12-27 下午07:00:29
 * 修改时间:2010-12-27 下午07:00:29
 
*/
public class IMMsgEncrypter{
    
// 经加密的消息
    private String cipheredMsg;
    
    
/**
     * 构造函数
     * 
@param plainMsg 未加密的消息
     * 
@param otherSideRSAPublicKey 对方RSA公钥
     * 
@param rsaCoder 己方RSA编码器
     * 
@param aesCoder 己方AES编码器
     * 
@throws IMMsgEncryptException
     
*/
    
public IMMsgEncrypter(String plainMsg,String otherSideRSAPublicKey,RSASecurityCoder rsaCoder,AESSecurityCoder aesCoder) throws IMMsgEncryptException{
        
try{
            
// 防止乱码
            plainMsg=UTF8Coder.encode(plainMsg);
            
            
// 对明文进行AES加密
            byte[] aesArr=aesCoder.getEncryptByteArray(plainMsg); // 对明文进行AES加密
            String cipherText=Base64.encodeBase64String(aesArr);// 得到AES加密后的密文
            
            
// 使用RSA对AES密钥进行加密
            String key=aesCoder.getAesKey();// 取得AES的密钥
            String aesKey="";
            
try{
                
byte[] clientRsaKeyArr=null;
                clientRsaKeyArr
=Base64.decodeBase64(otherSideRSAPublicKey);
                
byte[] rsaArr=rsaCoder.getEncryptArray(key, clientRsaKeyArr);
                aesKey
=Base64.encodeBase64String(rsaArr);
            }
            
catch(Exception ex){
                
throw new IMMsgEncryptException("使用对方RSA公钥加密己方AES钥匙时发生异常.");
            }
            
            
// 在发出的密文前附带经服务器RSA公钥加密的AES密钥
            StringBuilder sb=new StringBuilder();
            sb.append(
"<aeskey>"+aesKey+"</aeskey>");
            sb.append(
"<rsakey>"+rsaCoder.getPublicKeyString()+"</rsakey>");
            sb.append(
"<text>"+cipherText+"</text>");
            
            
// 最后对整体进行Base64加密
            cipheredMsg=Base64SecurityUtil.getEncryptString(sb.toString());
        }
        
catch(Exception ex){
            
throw new IMMsgEncryptException("加密消息时发生异常,异常信息为"+ex.getMessage()+".");
        }
    }

    
public String getCipheredMsg() {
        
return cipheredMsg;
    }
}

修改后的解码器代码:
package com.heyang.common.cipher;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.codec.binary.Base64;

import com.heyang.common.code.AESSecurityCoder;
import com.heyang.common.code.Base64SecurityUtil;
import com.heyang.common.code.RSASecurityCoder;
import com.heyang.common.code.UTF8Coder;


/**
 * 消息解密器
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 * 创建时间:2010-12-27 下午07:41:44
 * 修改时间:2010-12-27 下午07:41:44
 
*/
public class IMMsgDecrypter{
    
// 固定的三个节点名
    private static final String TEXT = "text";

    
private static final String RSAKEY = "rsakey";

    
private static final String AESKEY = "aeskey";

    
// 对方的RSA公钥
    private String otherSideRSAPublicKey;
    
    
// 解密后的明文
    private String plainMsg;
    
    
/**
     * 构造函数
     * 
@param cipherMsg 要解密的消息
     * 
@param rsaCoder 己方RSA编码器
     * 
@param aesCoder 己方AES编码器
     * 
@throws IMMsgDecryptException
     
*/
    
public IMMsgDecrypter(String cipherMsg,RSASecurityCoder rsaCoder,AESSecurityCoder aesCoder) throws IMMsgDecryptException{
        
try{
            
// 先用Base64解密密文
            cipherMsg=Base64SecurityUtil.getDecryptString(cipherMsg);
            
            
// 用正则表达式得到密钥文,客户端的RSA公钥和密文
            String regex="<(\\w+)>((.|\\s)+)</\\1>";

            Pattern pattern
=Pattern.compile(regex);
            Matcher matcher
=pattern.matcher(cipherMsg);
                
            String cipheredAesKey
="";// 经服务器RSA公钥加密的客户端AES钥匙密文
            String cipherText="";// 经客户端AES加密的密文
            
            Map
<String,String> map=new HashMap<String,String>();
            
while(matcher.find()){
                map.put(matcher.group(
1), matcher.group(2));
            }
            
            
if(map.size()==3){
                cipheredAesKey
=map.get(AESKEY);
                otherSideRSAPublicKey
=map.get(RSAKEY);
                cipherText
=map.get(TEXT);
            }
            
else{
                
throw new IMMsgDecryptException("解密消息时发生异常,原因是消息格式不正确.消息为:"+cipherMsg);
            }

            
// 得到经过服务器RSA私钥解密后的AES密钥
            String plainAesKey="";
            
try {
                
byte[] cipheredAesKeyArr=Base64.decodeBase64(cipheredAesKey);
                plainAesKey
=rsaCoder.getDecryptString(cipheredAesKeyArr);
            } 
catch (Exception e) {
                
throw new IMMsgDecryptException("无法解密对方AES密钥,异常信息为"+e.getMessage()+",客户端请求为:"+cipherMsg);
            }
            
            
// 使用AES密钥解密出明文
            byte[] cipherTextArr=Base64.decodeBase64(cipherText);
            plainMsg
=aesCoder.getDecryptString(cipherTextArr, plainAesKey);
            
            
//  UTF08还原
            plainMsg=UTF8Coder.decode(plainMsg);
        }
        
catch(Exception ex){
            
throw new IMMsgDecryptException("解密消息发生异常,异常信息为"+ex.getMessage()+".");
        }
    }

    
public String getOtherSideRSAPublicKey() {
        
return otherSideRSAPublicKey;
    }

    
public String getPlainMsg() {
        
return plainMsg;
    }
}

以上只是涉及乱码问题的一个处理方法,各位还要具体情况具体分析。
posted @ 2011-01-21 22:41 何杨 阅读(248) | 评论 (0)编辑 收藏

此版是 http://www.blogjava.net/heyang/archive/2010/12/31/342057.html  的改进版本。

改善功能:
1.XML文件存储。
2.在英文操作系统下乱码的问题。

已有功能:
1.基于TCP的通信功能。
2.基于RSA+AES的对信息的混合加密。
3.通过服务器转发客户端间消息。
4.用户的注册,登录,登出等功能。

注意:
本程序用到了AES加密,请确认http://www.blogjava.net/heyang/archive/2010/12/01/339515.html 一文中提到的两个文件是否已经拷贝到了对应的两处目录。

下载地址:
http://www.box.net/shared/o8z5rcrff5


posted @ 2011-01-21 17:17 何杨 阅读(172) | 评论 (1)编辑 收藏

以前,我们习惯用以下方式在XML中保存中文:
        try {
            OutputFormat format 
= OutputFormat.createPrettyPrint();
            format.setEncoding(
"GBK");    // 指定XML编码        
            XMLWriter writer = new XMLWriter(new FileWriter("c:\\1.xml"
),format);
            
            Document document 
= DocumentHelper.createDocument();
            Element root 
= document.addElement("users");

            
for(String user:userMap.keySet()){
                Element userElm
=root.addElement("user");
                userElm.addElement(
"name").addText(user);
                userElm.addElement(
"pswd").addText(userMap.get(user));
            }
           
            writer.write(document);
            writer.close();
        } 
catch (Exception e) {
            System.out.println(
"无法将注册用户信息存储到文件中,原因为"+e.getMessage());
            e.printStackTrace();
        }

在中文操作系统下,这样的方案是可行的,但是在英文操作系统下中文就会变成问号。最好使用如下的修正方案:
        try {
            OutputStreamWriter osw 
= new OutputStreamWriter(new FileOutputStream("c:\\1.xml"),"UTF-8");   
            OutputFormat format 
= OutputFormat.createPrettyPrint();
            format.setEncoding(
"UTF-8");    // 指定XML编码       
            XMLWriter writer = new
 XMLWriter(osw,format);
            
            Document document 
= DocumentHelper.createDocument();
            Element root 
= document.addElement("users");

            
for(String user:userMap.keySet()){
                Element userElm
=root.addElement("user");
                userElm.addElement(
"name").addText(user);
                userElm.addElement(
"pswd").addText(userMap.get(user));
            }
           
            writer.write(document);
            writer.close();
        } 
catch (Exception e) {
            System.out.println(
"无法将注册用户信息存储到文件中,原因为"+e.getMessage());
            e.printStackTrace();
        }

两端代码的变化区域在粗体部分,请注意区分。
posted @ 2011-01-21 11:35 何杨 阅读(757) | 评论 (0)编辑 收藏

注:下文代码主要来自参考书籍,本人稍稍修改了一下。

泛型栈类:
package com.heyang;

/**
 * 栈数据结构
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 * 创建时间:2011-1-15 上午07:51:09
 * 修改时间:2011-1-15 上午07:51:09
 
*/
public class MyStack<T>{
    
private int size;    // 大小
    private T[] datas;    // 数据
    private int top;    // 栈顶元素下标
    
    @SuppressWarnings(
"unchecked")
    
public MyStack(int size){
        
this.size=size;
        datas
= (T[])new Object[this.size]; 
        top
=-1;
    }
    
    
/**
     * 压栈
     
*/
    
public void push(T t){
        datas[
++top]=t;
    }
    
    
/**
     * 出栈
     * 
     * 说明:
     * 
@return
     * 创建时间:2011-1-15 上午08:01:15
     
*/
    
public T pop(){
        
return datas[top--];
    }
    
    
/**
     * 取得栈顶元素
     * 
     * 说明:
     * 
@return
     * 创建时间:2011-1-15 上午08:02:02
     
*/
    
public T getTopItem(){
        
return datas[top];
    }
    
    
/**
     * 查看栈是否为空
     * 
     * 说明:
     * 
@return
     * 创建时间:2011-1-15 上午08:02:38
     
*/
    
public boolean isEmpty(){
        
return top==-1;
    }
}

括号检查类:
package com.heyang;

/**
 * 表达式中括号检查类
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 * 创建时间:2011-1-15 上午08:05:25
 * 修改时间:2011-1-15 上午08:05:25
 
*/
public class BracketChecker{
    
private String input;        // 输入:待检查的表达式
    private boolean isValid;    // 是否检查通过
    private String checkResult;        // 输出:检查结果
    
    
/**
     * 构造函数
     * 
@param input
     
*/
    
public BracketChecker(String input){
        
this.input=input;
        
this.isValid=false;
        
this.checkResult="";
        
        check();
    }
    
    
/**
     * 执行检查
     * 
     * 说明:
     * 创建时间:2011-1-15 上午08:09:25
     
*/
    
private void check(){
        
int length=input.length();
        MyStack
<Character> stack=new MyStack<Character>(length);
        
        
for(int i=0;i<length;i++){
            
char c=input.charAt(i);
            
            
switch(c){
                
case '{':
                
case '[':
                
case '(':
                    stack.push(c);
                    
break;
                
case '}':
                
case ']':
                
case ')':
                    
if(stack.isEmpty()==false){
                        
char top=stack.pop();
                        
                        
if( (c=='}' && top!='{'|| (c==']' && top!='['|| (c==')' && top!='(') ){
                            isValid
=false;
                            checkResult
="经检查,表达式'"+input+"'中,位于第"+(i+1)+"的字符‘"+c+"’没有对应的匹配项";
                            
return;
                        }
                    }
                    
else{
                        isValid
=false;
                        checkResult
="经检查,表达式'"+input+"'中,位于第"+(i+1)+"的字符‘"+c+"’没有对应的匹配项";
                        
return;
                    }
                    
break;
                
default:
                    
break;
            }
        }
        
        
if(stack.isEmpty()==false){
            isValid
=false;
            checkResult
="经检查,表达式'"+input+"'中右括号缺失,匹配不完整";
            
return;
        }
        
else{
            isValid
=true;
            checkResult
="经检查,表达式'"+input+"'中括号匹配无误.";
            
return;
        }
    }

    
/**
     * 括号是否匹配
     * 
     * 说明:
     * 
@return
     * 创建时间:2011-1-15 上午08:39:38
     
*/
    
public boolean isValid() {
        
return isValid;
    }

    
/**
     * 取得检查结果
     * 
     * 说明:
     * 
@return
     * 创建时间:2011-1-15 上午08:39:27
     
*/
    
public String getCheckResult() {
        
return checkResult;
    }
    
    
public static void main(String[] args){
        String[] arr
={"1+(2/3-4","[1+(2/3-4)]*5","{[1+(2/3-4)]*5+(6+2*3)}*7","{[1+(2/3-4]*5+(6+2*3)}*7"};
        
        
for(String str:arr){
            BracketChecker c
=new BracketChecker(str);
            System.out.println(c.getCheckResult());
        }
    }
}

检查结果:
经检查,表达式'1+(2/3-4'中右括号缺失,匹配不完整
经检查,表达式
'[1+(2/3-4)]*5'中括号匹配无误.
经检查,表达式
'{[1+(2/3-4)]*5+(6+2*3)}*7'中括号匹配无误.
经检查,表达式
'{[1+(2/3-4]*5+(6+2*3)}*7'中,位于第11的字符‘]’没有匹配项


参考书籍:SAMS的《Java数据结构与算法》第四章

posted @ 2011-01-15 08:49 何杨 阅读(730) | 评论 (0)编辑 收藏

注:以下是Swing GUI处理的一个小小技巧,对此无兴趣者请退散。

在Swing中有这样一种状况:即长时间运行的事件回调,当它运行时,其余的GUI是没有响应的。如果这会持续较长的一段时间,它可能会让使用者感到挫折和困惑。下面一段程序就展示了这一现象,其粗体部分的本意是每隔一秒刷新标签中的文字,但是结果是按钮事件响应完毕后,标签上显示最后一段文字:
package com.heyang;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class MyFrame extends JFrame{
    
private static final long serialVersionUID = -5100794608937579830L;
    
    
private JLabel msgLbl;
    
private JButton cmdBtn;
    
    
public MyFrame(){
        setTitle(
"MyFrame");
        
        msgLbl
=new JLabel("提示文字");
        cmdBtn
=new JButton("刷新文本");
        
        
this.setLayout(new BorderLayout());
        
this.add(msgLbl,BorderLayout.NORTH);
        
this.add(cmdBtn,BorderLayout.CENTER);
        
        
// 设置大小,位置
        setSizeAndCentralizeMe(300200);
        
        
// 点击窗口右上角的关闭按钮关闭窗口,直接退出程序
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        
// 按钮事件注册
        cmdBtn.addActionListener(new ActionListener() {
            
public void actionPerformed(ActionEvent e) {
                runCmd();
            }
        });
        
        setVisible(
true);
    }
    
    
private void runCmd(){
        msgLbl.setText(
"温故而知新,可以为师矣。");
        longTimeProcess(
10);
        
        msgLbl.setText(
"由,汝知之乎!知之为知之,不知为不知,是知也。");
        longTimeProcess(
10);
        
        msgLbl.setText(
"见贤思齐焉,见不贤而内自省也");
        longTimeProcess(
10);
        
        msgLbl.setText(
"士不可以不弘毅,任重而道远。");
        longTimeProcess(
10);
        
        msgLbl.setText(
"岁寒,然后知松柏之后凋也。");
        longTimeProcess(
10
);
    }
    
    
/**
     * 模拟一个长时处理,以100毫秒为单位
     * 
     * 说明:
     * 
@param mSeconds
     * 创建时间:2011-1-9 下午12:02:28
     
*/
    
private void longTimeProcess(int mSeconds){
        
try{
            Thread.sleep(mSeconds
*100);
        }
        
catch(Exception e){
            
        }
    }
    
    
private void setSizeAndCentralizeMe(int width, int height) {
        Dimension screenSize 
= Toolkit.getDefaultToolkit().getScreenSize();
        
this.setSize(width, height);
        
this.setLocation(screenSize.width / 2 - width / 2, screenSize.height
                
/ 2 - height / 2);
    }
    
    
public static void main(String[] args){
        
new MyFrame();
    }
}

要达到预期的效果,Swing建议:让长时间运行的任务在独立的线程中运行会好很多,这样能够让GUI有适当响应。修改后的代码如下:
package com.heyang;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class MyFrame extends JFrame{
    
private static final long serialVersionUID = -5100794608937579830L;
    
    
private JLabel msgLbl;
    
private JButton cmdBtn;
    
    
public MyFrame(){
        setTitle(
"MyFrame");
        
        msgLbl
=new JLabel("提示文字");
        cmdBtn
=new JButton("刷新文本");
        
        
this.setLayout(new BorderLayout());
        
this.add(msgLbl,BorderLayout.NORTH);
        
this.add(cmdBtn,BorderLayout.CENTER);
        
        
// 设置大小,位置
        setSizeAndCentralizeMe(300200);
        
        
// 点击窗口右上角的关闭按钮关闭窗口,直接退出程序
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        
// 按钮事件注册
        cmdBtn.addActionListener(new ActionListener() {
            
public void actionPerformed(ActionEvent e) {
                runCmd();
            }
        });
        
        setVisible(
true);
    }
    
    
private void runCmd(){
        new Thread(){
            
public void
 run(){
                msgLbl.setText(
"温故而知新,可以为师矣。");
                longTimeProcess(
10);
                
                msgLbl.setText(
"由,汝知之乎!知之为知之,不知为不知,是知也。");
                longTimeProcess(
10);
                
                msgLbl.setText(
"见贤思齐焉,见不贤而内自省也");
                longTimeProcess(
10);
                
                msgLbl.setText(
"士不可以不弘毅,任重而道远。");
                longTimeProcess(
10);
                
                msgLbl.setText(
"岁寒,然后知松柏之后凋也。");
                longTimeProcess(
10);
            }
        }.start();

    }
    
    
/**
     * 模拟一个长时处理,以100毫秒为单位
     * 
     * 说明:
     * 
@param mSeconds
     * 创建时间:2011-1-9 下午12:02:28
     
*/
    
private void longTimeProcess(int mSeconds){
        
try{
            Thread.sleep(mSeconds
*100);
        }
        
catch(Exception e){
            
        }
    }
    
    
private void setSizeAndCentralizeMe(int width, int height) {
        Dimension screenSize 
= Toolkit.getDefaultToolkit().getScreenSize();
        
this.setSize(width, height);
        
this.setLocation(screenSize.width / 2 - width / 2, screenSize.height
                
/ 2 - height / 2);
    }
    
    
public static void main(String[] args){
        
new MyFrame();
    }
}

以上代码达到了预期效果,其中起关键作用的代码就是以上粗体部分,它将长时处理放到了另一个线程中运行。
这种做法不是唯一解决之道,Sun提供的SwingWorker类可以帮你达到目的,只是要繁琐一些。这样的技巧在耗时检查,与服务器交互和复杂图形处理中都能有所应用。

参考书籍:
O'REILLY 《Java 线程》一书。

最后感谢您看到这里。

何杨,2011年1月9日14:20:37


posted @ 2011-01-09 14:08 何杨 阅读(1011) | 评论 (3)编辑 收藏

注意:
1.NIO主要用于服务端,若用来客户端相对于它带来的额外复杂性有点不值得。
2.用于编码解码字符集请根据您的机器缺省字符集进行调整,如GB2312,GBK,UTF-8,UTF-16等,若出现乱码请更换之。
3.BufferSize请根据您可能发送接收的最大字符串长度进行相应调整。

代码:
package com.heyang.biz.server.test.nio;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;


/**
 * NIO 服务器
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 * 创建时间:2011-1-3 下午12:09:02
 * 修改时间:2011-1-3 下午12:09:02
 
*/
public class NIOServer{
    
// 本地字符集
    private static final String LocalCharsetName = "gb2312";

    
// 本地服务器监听的端口
    private static final int Listenning_Port=8888;
    
    
// 缓冲区大小
    private static final int Buffer_Size=1024;
    
    
// 超时时间,单位毫秒
    private static final int TimeOut=3000;
    
    
public static void main(String[] args) throws Exception{
        
// 创建一个在本地端口进行监听的服务Socket信道.并设置为非阻塞方式
        ServerSocketChannel serverChannel=ServerSocketChannel.open();
        serverChannel.socket().bind(
new InetSocketAddress(Listenning_Port));
        serverChannel.configureBlocking(
false);
        
        
// 创建一个选择器并将serverChannel注册到它上面
        Selector selector=Selector.open();
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        
        
while(true){
            
// 等待某个信道就绪
            if(selector.select(TimeOut)==0){
                System.out.println(
".");
                
continue;
            }
            
            
// 获得就绪信道的键迭代器
            Iterator<SelectionKey> keyIter=selector.selectedKeys().iterator();
            
            
// 使用迭代器进行遍历就绪信道
            while(keyIter.hasNext()){
                SelectionKey key
=keyIter.next();
                
                
// 这种情况是有客户端连接过来,准备一个clientChannel与之通信
                if(key.isAcceptable()){
                    SocketChannel clientChannel
=((ServerSocketChannel)key.channel()).accept();
                    clientChannel.configureBlocking(
false);
                    clientChannel.register(key.selector(), SelectionKey.OP_READ,ByteBuffer.allocate(Buffer_Size));
                }
                
                
// 客户端有写入时
                if(key.isReadable()){
                    
// 获得与客户端通信的信道
                    SocketChannel clientChannel=(SocketChannel)key.channel();
                    
                    
// 得到并重置缓冲区的主要索引值
                    ByteBuffer buffer=(ByteBuffer)key.attachment();
                    buffer.clear();
                    
                    
// 读取信息获得读取的字节数
                    long bytesRead=clientChannel.read(buffer);
                    
                    
if(bytesRead==-1){
                      
// 没有读取到内容的情况
                      clientChannel.close();
                    }
                    
else{
                      
// 将缓冲区准备为数据传出状态
                      buffer.flip();
                      
                      
// 将获得字节字符串(使用Charset进行解码)   
                      String receivedString=Charset.forName(LocalCharsetName).newDecoder().decode(buffer).toString();
                      
                      
// 控制台打印出来
                      System.out.println("接收到信息:"+receivedString);
                      
                      
// 准备发送的文本
                      String sendString="你好,客户端. 已经收到你的信息"+receivedString;
                      
                      
// 将要发送的字符串编码(使用Charset进行编码)后再进行包装
                      buffer=ByteBuffer.wrap(sendString.getBytes(LocalCharsetName));
                      
                      
// 发送回去
                      clientChannel.write(buffer);
                      
                      
// 设置为下一次读取或是写入做准备
                      key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
                    }
                }
                
                keyIter.remove();
            }
        }
        
    }
}

与之配合的客户端代码,没有采用NIO方式。
package com.heyang.biz.server.test.nio;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;



public class TestClient{
    
public static void main(String[] args) throws Exception{
        Socket s
=new Socket("127.0.0.1",8888);
        
        InputStream  inStram
=s.getInputStream();
        OutputStream outStream
=s.getOutputStream();
        
        
// 输出
        PrintWriter out=new PrintWriter(outStream,true);
        
        out.print(
"getPublicKey你好!");
        out.flush();

        s.shutdownOutput();
// 输出结束
        
        
// 输入
        Scanner in=new Scanner(inStram);
        StringBuilder sb
=new StringBuilder();
        
while(in.hasNextLine()){
            String line
=in.nextLine();
            sb.append(line);
        }
        String response
=sb.toString();
        System.out.println(
"response="+response);
    }
}

服务器端的输出:
.
接收到信息:getPublicKey你好!
.

客户端的输出:
response=你好,客户端. 已经收到你的信息getPublicKey你好!
posted @ 2011-01-03 14:36 何杨 阅读(4699) | 评论 (0)编辑 收藏

一.目录互斥方案:这种互斥要求同一目录下不能运行两个应用程序的实例,通常用文件解决之,即程序启动时看看所在目录下有没有一个特定文件的存在,在的话就退出,不在的话就自己创建一个,退出时再删除之。这种情况下,这个临时文件便成了同一目录下程序已经启动实例的标志。为了避免误删除导致此功能失常,可以给文件加上隐藏属性。

二.本机互斥方案:这种互斥要求在一台机器上只能运行一个实例。一种解决办法是在注册表的特定位置进行记录,原理和文件互斥类似;另一个解决办法是利用端口,即程序启动后在某一端口进行监听,这样第二个实例启动时再去监听就不可行了,这种方式很巧妙,无须顾忌程序异常退出问题,只是会无端占用一个端口,有时客观环境不允许这么干。

三.单用户互斥方案:这种互斥要求系统只允许同名用户登录一次,因此服务器端必须存放用户对应的数据,当用户登上时检查这部分数据就可以了,这种方式最棘手的是客户端程序的异常退出导致再也无法登录,但让客户端发心跳包或是服务器端反连客户端来解决。

综上,互斥功能要成功,就要找到互斥对象共同的环境或是上下文。如果找到了,互斥就变成了一个技术问题。

posted @ 2010-12-31 13:47 何杨 阅读(257) | 评论 (0)编辑 收藏

按:以下是一个老旧的IM服务器客户机例子,网络间传递的信息采用混合加密方式以保护客户隐私,熟知这两细节者就不用往下看了,以免浪费宝贵时间。

下载地址
http://www.box.net/shared/jcrbps2hk3

下载包说明:
从上述地址下载完毕后是一个Eclispe工程,载入即可使用,可以执行RunServer运行服务器端,执行RunClient运行客户端。

使用说明:
先启动服务器端,让其开始监听;再由各客户端连到服务器上,注册好用户后各个客户机之间即可通信,此时服务器起一个消息转发器的作用。

截图:


几句啰嗦的话:
1.本程序是为了配合说明混合加密方式在IM程序中的使用,目标不是做一个商用IM软件。
2.其中的混合加密方式的使用可以参考(http://www.blogjava.net/heyang/archive/2010/12/25/341518.html)和(http://www.blogjava.net/heyang/archive/2010/12/26/341556.html)这两篇文章。

posted @ 2010-12-31 13:06 何杨 阅读(1858) | 评论 (6)编辑 收藏

一般来说,“.”在正则表达式中是匹配任意字符,但是,实际上,它是不能匹配换行符的,因为它的真实定义是“ 匹配除换行符号之外的任意字符”,这点要特别注意一下。
要匹配任意字符,可用"(.|\\n)+"或是"(.|\\s)+".

posted @ 2010-12-27 18:04 何杨 阅读(589) | 评论 (0)编辑 收藏

     摘要: 按:前面(http://www.blogjava.net/heyang/archive/2010/12/25/341518.html)已经提到过混合加密方式,今天这里再来赘述一下完成的代码和流程,熟悉者就不用往下看了。完整的IM程序在(http://www.box.net/shared/jcrbps2hk3)可以下载。 整个流程的UML Sequence图(Amaterus UML用得还不熟...  阅读全文
posted @ 2010-12-26 11:41 何杨 阅读(7330) | 评论 (4)编辑 收藏

     摘要: 按:下面的文字涉及早已在工程中广泛采用的混合加密方式,对此熟知者就不用往下看了,以免浪费时间。 我们知道,现代加密方式有两大类:一类是对称加密方式,其优点是加密速度快,缺点是密钥不便于传递,其中典型代表是AES;一类是非对称加密方式,优点是交换钥匙方便,缺点是加密时间长,代表是RSA。在实际应用,我们可以取其所长,弃其所短,这就是混合加密方式,有的场合也成为Hybrid方式。 具体来说...  阅读全文
posted @ 2010-12-25 16:02 何杨 阅读(4294) | 评论 (6)编辑 收藏

注:下例仅为学习使用,高性能的服务器例子请采用NIO方案。

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class ThreadedServer{
    
public static void main(String[] args) throws IOException{
        ServerSocket s
=new ServerSocket(9999);
        
        
while(true){
            Socket incoming
=s.accept();
            InetAddress address
=incoming.getInetAddress();
            System.out.println(
"开始与"+address+"进行通讯.");
            
            
new Thread(new EchoHandler(incoming)).start();
        }
    }
}

class EchoHandler implements Runnable{
    
private Socket incoming;
    
    
public EchoHandler(Socket incoming){
        
this.incoming=incoming;
    }
    
    
    
public void run(){
        
try{
            InputStream  inStram
=incoming.getInputStream();
            OutputStream outStream
=incoming.getOutputStream();
            
            Scanner in
=new Scanner(inStram);
            PrintWriter out
=new PrintWriter(outStream);
            out.println(
"你好!输入Bye退出。");
            
            
while(in.hasNextLine()){
                String line
=in.nextLine();
                System.out.println(
"客户端说:"+line);
                
                
if(line.equalsIgnoreCase("Bye")){
                    
break;
                }
                
else if(line.equalsIgnoreCase("login")){
                    System.out.println(
"客户端想登录");
                }
                
else if(line.equalsIgnoreCase("register")){
                    System.out.println(
"客户端想注册");                
                }
                
else if(line.equalsIgnoreCase("dispacth")){
                    System.out.println(
"客户端想转发信息");
                }
                
else if(line.equalsIgnoreCase("userlist")){
                    System.out.println(
"客户端想得到用户列表");
                }
                
else{
                    out.println(
"收到:"+line);
                }
            }
        }
        
catch(Exception ex){
            ex.printStackTrace();
        }
        
finally{
            
try {
                incoming.close();
            } 
catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

可采用Telnet与上述服务器端通信,Vista上Telnet可如下方式开启:
1、打开控制面板;
2、在左侧选择“经典视图”,然后在右侧选择“程序和功能”;
3、在出现的“程序和功能”窗口左侧中点击“打开或关闭Windows功能”;
4、在弹出的“Windows功能”窗口中勾选上“Telnet客户端”;
5、确定后退出,Windows会自动开始配置激活;
6、在“开始搜索”框中输入“telnet 127.0.0.1 9999



posted @ 2010-12-23 14:19 何杨 阅读(454) | 评论 (0)编辑 收藏

一.嗅探器的应用范围
   嗅探器要求监听设备的物理传输介质与被监听设备的物理传输介质存在直接联系或者数据包能通过路由选择到达对方,及一个逻辑上的三方连接,具体来说有以下两种情况:
   1.监听方与通讯方位于同一物理网络,如局域网。
   2.监听方和通讯方存在路由或者接口关系,如通讯双方的同一网关,连接通讯双方的路由设备等。
   因此,嗅探技术不太可能在公共网络设备上使用,当今最普遍的嗅探行为多发生在大大小小的局域网中。

二.发生在交换式局域网内的窃听
   交换式局域网内的网络连接设备是交换机,它连接的每台计算机是独立的,交换机引入了端口的概念,它会产生一个地址表存放每台与之连接的计算机的MAC地址,除了声明为广播或者组播的报文,交换机在一般情况下是不会让其他报文出现共享式局域网那样的广播形式发送,因此即使网卡设置为混杂模式,它也接收不到发往其他计算机的数据,因为数据的目标地址会在交换机中被识别,然后有针对性的发往表中对应地址的端口。
    在这种环境中,嗅探器为了监听特定计算机的通讯,通常采取ARP欺骗行为,这时嗅探器充当了一个被监听对象与信息交换对象之间的转发者的角色,它会截获双方发给对方的信息后经过处理在发送给目的方,这时嗅探器对双方是透明的。



posted @ 2010-12-16 20:56 何杨 阅读(316) | 评论 (0)编辑 收藏

注:下文涉及一种Web入侵方式的古老方法,即利用Cookie冒充已登录用户。熟知此方法的朋友请退散。

我们在做Web应用时,习惯把用户信息放到Session中,而这一举措,实际上有较大的潜在危险性,如果别人知道了我们的session id,就可能利用它以我们的身份进入Web应用。因为session的数据虽然存在于服务器中,但识别客户端各自的数据还是靠存放在客户端的session Id的,如果有人以某个已登录的用户的session Id进入Web应用,那么他就会被当作那个用户,下文将展示这一过程。

首先,我们让某个用户正常登录一个位于Tomcat上的应用,注意右上角的用户名的显示:



再取得他的session Id。这一步实际上有很多途径取到,比如url中有时带有它,Struts做前端的e
Web应用就时常可见;本地cookie中可以找到它,这个用程序就能知道,用js也行(使用document.cookie);用嗅探器也可以获得它,这个嗅探器可以放在想冒充用户的机器或是网关上。下面使用了TCPMon得到其session id(具体使用方法请参考 http://www.blogjava.net/heyang/archive/2010/12/10/340294.html)。

上面高亮的文字部分就是“关羽”这个用户的session id。

现在,url “http://localhost:8080/ProjectManager/GotoModifyUserPage.do” 和session id“4DC291FC36B2392BE440F70E5B3AA49D” 我们已经得到,接下来就是用它们来进入web应用了。

一般的浏览器没有可供输入 session id的地方,但从原理来看我们知道这并不复杂,因为http是基于文本的,只要有工具能把Url和cookie捏合起来成文本并发送就可以了,WebTool就是这样的一款工具,你可以从http://www.hackline.net/a/soft/tools/2010/0603/4198.html  来获得它。

得到下载文件解开包,执行里面的WebTool 4.2.exe,点击其菜单“设置”-->“自定义cookie浏览”,使其成为勾选状态,然后在地址栏输入http://localhost:8080/ProjectManager/GotoModifyUserPage.do,左下方的cookie处输入4DC291FC36B2392BE440F70E5B3AA49D,然后点击右上方的“Get”按钮,你将看到以下画面:


好了,看看其右上方把,用户名“关羽”已经显示出来了。我们这会不用得知关羽的密码也能以他的身份开始操作了,这就是冒充session id做到的。

好了,感谢您看到这里。可见,常规Web应用还是比较脆弱的,但这种入侵方式也好防范,将协议改成改成https就可以了(请参考 http://www.blogjava.net/heyang/archive/2010/12/13/340500.html)。另希望有人不要把上文的技巧用到不该用的地方,去动本不该属于自己的东西是危险而徒劳的。
posted @ 2010-12-14 17:14 何杨 阅读(2042) | 评论 (0)编辑 收藏

注:以下文字还是老调重弹,对在Tomcat上配置https熟悉的朋友就不要浪费时间了,另喜欢英语的朋友请直接到https://localhost:8443/docs/ssl-howto.html或是http://localhost:8080/docs/ssl-howto.html查看原文档。

给Tomcat配置https只有简单的几个步骤,比较容易完成的:
1.首先,用keytool工具生成证书。
  keytool工具是jdk自带的,您可以从JAVA_HOME/bin下找到它。
  在命令行Command中,您可以输入以下命令来生成认证证书:
  C:\jdk1.6.0_13\bin>keytool -genkey -alias tomcat -keyalg RSA -keystore c:\tomcat.keystore
  注意上方命令两个加粗的文字,前者是我的JAVA_HOME/bin,后者是证书的文件名,您需要根据您的实际情况进行调整。

2.输入必要的数据。
  在命令行窗口输入上面的指令后,控制台还会询问您一些信息如名字,城市,国家等,这些随便写就成了,但有一个地方不能胡来,就是密码。注意它最要和Tomcat的admin用户登录密码保持一致,也就是说问你输入密码的时候你要使用Tomcat的admin的密码(我自己的是123456,如果不记得了请查看您的TOMCAT_HOME/conf/tomcat-users.xml文件)。最后,当控制台问你是否要和Tomcat的admin是一个密码时,回车即可。

3.修改Tomcat配置文件Server.xml
如果以上手续成功,那么c:\tomcat.keystore将会被生成,接下来修改TOMCAT_HOME/conf/server.xml,找到<Connector ...    port="8443".../>这样一段,将它替换成下面的文字:
<Connector protocol="org.apache.coyote.http11.Http11NioProtocol"
           port
="8443" minSpareThreads="5" maxSpareThreads="75"
           enableLookups
="true" disableUploadTimeout="true" 
           acceptCount
="100"  maxThreads="200"
           scheme
="https" secure="true" SSLEnabled="true"
           keystoreFile
="c:/tomcat.keystore" keystorePass="123456"
           clientAuth
="false" sslProtocol="TLS"/>
注意上述文字的粗体部分,请和您自己设定的文件及密码保持一致。

4.重启Tomcat,再以https://localhost:8443来访问Tomcat。
  注意Tomcat也有不听话的时候,有时需要重启一下计算机。
 
好了,就是这些,感谢您看到这里。

posted @ 2010-12-13 13:52 何杨 阅读(614) | 评论 (0)编辑 收藏

以下文字只是记录我做的一个小实验,没有代码和程序,没有兴趣者请退散。

在“用TCPMon验证Web应用的安全性隐患”中谈到,http基本就是明码,如果用嗅探器获得http数据包的话,甚多私密信息都被被截获,下面将记录这一过程。
下文中提到的嗅探器是Wireshark,这是一个优秀的免费软件,您可以从 wireshark官方网站 得到它。
下文中涉及的站点是天涯的用户登录页面(http://passport.tianya.cn/login.jsp),下面实验中要用到已经注册的用户名test_user2010及其密码t123456  .


首先,我们要知道本机的IP地址和点击登录页面的登录按钮后要向他发出http请求的机器的ip地址,前者用ipconfig就能知道,后者的话需要打开网页源码获取响应服务器的网址,再用ping获得其IP地址。请参考下图:
打开网页源码获取响应服务器的网址:


再用ping获得其IP地址:


到这里,我们知道当我们在登录页面输入用户名和密码后,本机192.168.104.173将和221.11.172.202取得联系。

第二步,我们打开Wireshark,让它开始监听网络数据包,当我们点击登录按钮并登录成功后再停止监听。

第三步,我们可以从Wireshark的监听结果中去找想要的数据,为了减小范围,我们可以在filter中输入ip.src==192.168.104.173  && http,它表示IP来源是本机IP,使用的协议是http,下面是找到的结果:


在infor一列中,书写有POST /login http/1.1 (application .....)的一行就是点击登录按钮后发出的http请求,这一行在上图中用蓝色框框起来了。

点击这一行,弹出的界面中已经把我们输入的用户名和密码都暴露出来了,上图中用红色框表示。

好了,到这里实验就做完了,它表示以Http为基础的Web世界并不安全,用户名和密码不足以保护您的私密信息,所以,很多网站也需要加强安全措施,您自己也尽量不要把隐私信息放到网上。

最后感谢您看完此文。

附:2010年12月24日的截图



posted @ 2010-12-11 14:19 何杨 阅读(52808) | 评论 (16)编辑 收藏

很简单,程序如下:
class Test{
    
public static void main(String[] args) throws Exception{
        
// 汉字变成UFT8编码
        System.out.println(URLEncoder.encode("何杨""utf-8"));
        
        
// 将UFT8编码的文字还原成汉字
        System.out.println(URLDecoder.decode("%E4%BD%95%E6%9D%A8""utf-8"));        
    }
}

输出如下:
%E4%BD%95%E6%9D%A8
何杨

下面是一个辅助的工具类:
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;


/**
 * UTF8转码器
 * 
@author heyang
 *
 
*/
public class UTF8Coder{
    
private static final String UTF_8 = "utf-8";// 编码形式

    
/**
     * 对文字进行UTF8转码
     * 
@param str
     * 
@return
     
*/
    
public static String encode(String str){
        
try {
            
return URLEncoder.encode(str, UTF_8);
        } 
catch (UnsupportedEncodingException e) {
            
return null;
        }
    }
    
    
/**
     * 将转码后的文字还原
     * 
@param str
     * 
@return
     
*/
    
public static String decode(String str){
        
try {
            
return URLDecoder.decode(str, UTF_8);
        } 
catch (UnsupportedEncodingException e) {
            
return null;
        }
    }
}


posted @ 2010-12-11 12:06 何杨 阅读(2090) | 评论 (0)编辑 收藏

Web应用的安全性一直有一个先天缺陷,即http基本就是明码传递,这个缺陷可以让后台做的诸多加密工作一朝崩塌,下面以一个实际例子来说明。

我们还是用TCPMon来截获http请求,看从中能否找到有用的信息,下面的Http请求来自很多网站都有的注册和登录页面。TCPMon的具体方法请参照:如何用Apache TCPMon来截获SOAP消息

下面是用户注册页面,我们向其中输入了一点信息:

点击“提交按钮后”,我们在TCPMon中可以截获这样的内容.



下面是登录页面:


点击“登录”按钮后,TCPMon截获的内容如下:


上面两个字符串:
name=%E5%88%98%E5%A4%87&email=1@3445.5&pswd=123456&repswd=123456&brief=rteterte&submitBtn=%E6%8F%90%E4%BA%A4
name=%E5%88%98%E5%A4%87&pswd=123456&submitBtn=%E7%99%BB%E5%BD%95

已经暴露了不少信息,我们再转码一下会全部暴露出来:
System.out.println(URLDecoder.decode("name=%E5%88%98%E5%A4%87&email=1@3445.5&pswd=123456&repswd=123456&brief=rteterte&submitBtn=%E6%8F%90%E4%BA%A4","utf-8"));
        System.out.println(URLDecoder.decode("name=%E5%88%98%E5%A4%87
&pswd=123456&submitBtn=%E7%99%BB%E5%BD%95","utf-8"));

输出如下:
name=刘备&email=1@3445.5&pswd=123456&repswd=123456&brief=rteterte&submitBtn=提交
name=刘备
&pswd=123456&submitBtn=登录

也就是说,我们在表单中输入的内容,已经完全出现在http请求中。只要加一个网络嗅探器(sniffer)来收集网络上传递的数据报的相关信息,再加以少许处理,所有私密信息都将被发现。
posted @ 2010-12-11 11:55 何杨 阅读(1222) | 评论 (0)编辑 收藏

注:以下是关于TCPMon的一些使用常识,如果不需要或是已经熟悉就不用往下看了。

在WebService服务器和客户机之间会传递SOAP消息,有时我们需要得到这些消息以便调试,而Apache的TCPMon可以帮助我们做到这一点。

TCPMon的下载地址在http://ws.apache.org/commons/tcpmon/download.cgi,找到Binary Distribution,
下载后会得到一个tcpmon-1.0-bin.zip的包,解开后进去\tcpmon-1.0-bin\build目录,双击tcpmon.bat就可以执行程序了。

这里有必要对tcpmon说明一下,它实际上是个代理,起一个消息转发的作用,监视的是转发出去的消息。最终,消息还是要送到具体的地址和端口,否则响应就不正确了。也就是说,TCPMon是一个消息的二传手,它的前后都应该配置正确才行。


现在我们手头有一个WebService测试客户端,一个WebService工程运行在Tomcat服务器中,这就是TCPMon的两端,我们需要把它配置进去。

首先,我们需要修改Tomcat的服务端口,你可以打开Tomcat目录下的conf目录下的server.xml文件,将Connector节点的port属性值从8080改成8088(也可以是其他端口),如下所示:
<Connector port="8088" protocol="HTTP/1.1" maxThreads="150" connectionTimeout="20000" redirectPort="8443" />
这样,Tomcat服务器就在8088端口进行监听了。

其次,我们需要让TCPMon在8080端口进行监听,并把收到的消息转发到8088端口去。我们找到刚才打开的TCPMon程序,找到admin选项卡,在listen port #:右边的文本框中写入8080,在Target HostName右边的文本框中输入127.0.0.1,在Tatget port右边的文本框中输入8088。如下图。


然后,再点击add按钮。一个名为Port 8080的选项卡会出现,这个界面将负责显示截获的SOAP消息。

接下来就可以启动客户端程序,客户端会向原来一样,向127.0.0.1所在的8080端口送出SOAP消息,而这个消息会被TCPMon截获,然后转送到127.0.0.1所在的8088端口去,然后Tomcat会收到这个SOAP消息交给负责处理的XFire Servlet,处理完的结果会通过TCPMon送回到客户端。在这个过程中,SOAP消息就被完全截获并显示在Port 8080选项卡中了。如下图:


最后,当你的SOAP消息调试结束后,别忘了吧Tomcat的端口改回到8080。

感谢您看到这里。

posted @ 2010-12-10 19:38 何杨 阅读(5610) | 评论 (1)编辑 收藏

注:下文是关于WebService的一个概念和总结,其中的例子来自http://www.box.net/shared/cyg98xgz78 。 如果您对WebService已经熟悉就不用浪费时间了。

一.什么是Web服务?

Web服务是网络化应用程序的一种,我们可以将Web服务看成一种函数调用,只不过这个函数的实体存在于某个服务器上,而调用在客户端进行。Web服务的思想很简单,即服务器通过网络提供Web服务,其它程序可以将由Web服务器封装的功能无缝的集成到自己的程序中去。Web服务是跨平台跨语言的,它可以由多种语言创建,也可以由多种语言使用。WebService定义了一套标准的调用过程:服务器端使用WSDL来向外界描述它所提供的服务,客户端与服务器端的交互采用SOAP协议。

二.Web服务有什么益处?
处于这个信息化高度发展的世界,每个软件系统都势必要和别的软件系统进行交互,它们可能由不同语言编写运行在不同的服务器上,相互间的调用是一个很大的难题。Web服务就是为解决这些问题而诞生的,它的语言平台无关性可以和任一平台或语言的软件进行交互,这样,Web服务就可以像一座桥梁,可以连通信息化世界中的孤岛。

三.SOAP协议。
在Web服务中,服务器和客户机需要传递接收消息,这就需要对传输的数据格式采取一定的约定措施,这个约定就是SOAP协议,它的全称是简单对象访问协议(Simple Object Access Protocl)。SOAP是基于XML的消息包装器,它既包括客户端送给服务器端希望调用的类和方法的一种消息格式,也包括服务器返回数据的消息格式。有个这个协议,服务器和客户机就能明白对方想干什么。SOAP消息一般基于HTTP来传输,也可以基于其他协议。
下面是一个客户端向服务器发送的SOAP消息例子:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
    
<ns1:getServerPublicKey xmlns:ns1="http://heyang.com">
    
</ns1:getServerPublicKey>
</soap:Body>
</soap:Envelope>
客户机向服务器端发送消息时,</soap:Body>中的XML包含要调用的方法和参数,如上述的getServerPublicKey。

下面是服务器反馈给客户机的SOAP消息例子:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    
<soap:Body>
    
<ns1:getServerPublicKeyResponse xmlns:ns1="hello.XFire">    <ns1:out>MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkSpbrSfBIIu+f4mMr7Ie2JdWCBEmlZ1mcoZ0UTNMGaVwexfRax+HC/uusXvkkdoUGYjMaiMycRsQtSOLsfKjOVY/8zBLs0tAOEVelg6MyiF3DV7PVgGEq0dpXJCz0MWFY34a1YJMbPfvPa+VpZaIFbzICUPRhVdBYPAboXthFyQIDAQAB
    
</ns1:out>
    
</ns1:getServerPublicKeyResponse>
    
</soap:Body>
</soap:Envelope>
当服务器端送回消息时,</soap:Body>中包含调用的结果,它可以是单个值,也可以是含有多个值的复杂数据类型。如上面的<ns1:out>中的节点值。

另:在调试WebService程序,想要查看SOAP消息时,可以使用Apache的TCPMon工具,具体使用方法请看http://www.blogjava.net/heyang/archive/2010/12/10/340294.html.

四.服务器端收到SOAP消息后的动作

以XFire为例,当一个来自客户端的SOPA请求送达WebService服务端时,它会先送到一个Servlet(XFireConfigurableServlet)中(请参看web.xml中的配置),然后开始解析SOAP消息,再根据配置文件services.xml找到接口com.heyang.IService和具体的实现类com.heyang.ServiceImpl中的方法,调用函数产生结果,然后再包装成SOAP消息返回。Axis的做法也是类似的。

五.WSDL
我们现在可以想到Web服务是一个对象,含有一个或多个方法。如何对一个WebService服务器能提供的方法进行说明呢?这里就要用到WSDL(Web Service Description Language),它定义了Web服务提供的可供操作的函数,具体如下:
<?xml version="1.0" encoding="UTF-8" ?>
<wsdl:definitions targetNamespace="hello.XFire" xmlns:soapenc12="http://www.w3.org/2003/05/soap-encoding" xmlns:tns="hello.XFire" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc11="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<wsdl:types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="hello.XFire">
<xsd:element name="getServerPublicKey">
  
<xsd:complexType />
  
</xsd:element>
<xsd:element name="getServerPublicKeyResponse">
<xsd:complexType>
<xsd:sequence>
  
<xsd:element maxOccurs="1" minOccurs="1" name="out" nillable="true" type="xsd:base64Binary" />
  
</xsd:sequence>
  
</xsd:complexType>
  
</xsd:element>
<xsd:element name="getResonse">
<xsd:complexType>
<xsd:sequence>
  
<xsd:element maxOccurs="1" minOccurs="1" name="in0" nillable="true" type="xsd:base64Binary" />
  
<xsd:element maxOccurs="1" minOccurs="1" name="in1" nillable="true" type="xsd:base64Binary" />
  
</xsd:sequence>
  
</xsd:complexType>
  
</xsd:element>
<xsd:element name="getResonseResponse">
<xsd:complexType>
<xsd:sequence>
  
<xsd:element maxOccurs="1" minOccurs="1" name="out" nillable="true" type="xsd:base64Binary" />
  
</xsd:sequence>
  
</xsd:complexType>
  
</xsd:element>
  
</xsd:schema>
  
</wsdl:types>
<wsdl:message name="getServerPublicKeyRequest">
  
<wsdl:part name="parameters" element="tns:getServerPublicKey" />
  
</wsdl:message>
<wsdl:message name="getResonseResponse">
  
<wsdl:part name="parameters" element="tns:getResonseResponse" />
  
</wsdl:message>
<wsdl:message name="getServerPublicKeyResponse">
  
<wsdl:part name="parameters" element="tns:getServerPublicKeyResponse" />
  
</wsdl:message>
<wsdl:message name="getResonseRequest">
  
<wsdl:part name="parameters" element="tns:getResonse" />
  
</wsdl:message>
<wsdl:portType name="helloPortType">
<wsdl:operation name="getServerPublicKey">
  
<wsdl:input name="getServerPublicKeyRequest" message="tns:getServerPublicKeyRequest" />
  
<wsdl:output name="getServerPublicKeyResponse" message="tns:getServerPublicKeyResponse" />
  
</wsdl:operation>
<wsdl:operation name="getResonse">
  
<wsdl:input name="getResonseRequest" message="tns:getResonseRequest" />
  
<wsdl:output name="getResonseResponse" message="tns:getResonseResponse" />
  
</wsdl:operation>
  
</wsdl:portType>
<wsdl:binding name="helloHttpBinding" type="tns:helloPortType">
  
<wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="getServerPublicKey">
  
<wsdlsoap:operation soapAction="" />
<wsdl:input name="getServerPublicKeyRequest">
  
<wsdlsoap:body use="literal" />
  
</wsdl:input>
<wsdl:output name="getServerPublicKeyResponse">
  
<wsdlsoap:body use="literal" />
  
</wsdl:output>
  
</wsdl:operation>
<wsdl:operation name="getResonse">
  
<wsdlsoap:operation soapAction="" />
<wsdl:input name="getResonseRequest">
  
<wsdlsoap:body use="literal" />
  
</wsdl:input>
<wsdl:output name="getResonseResponse">
  
<wsdlsoap:body use="literal" />
  
</wsdl:output>
  
</wsdl:operation>
  
</wsdl:binding>
<wsdl:service name="hello">
<wsdl:port name="helloHttpPort" binding="tns:helloHttpBinding">
  
<wsdlsoap:address location="http://localhost:8080/XfireSample/services/hello" />
  
</wsdl:port>
  
</wsdl:service>
  
</wsdl:definitions>
  以上内容在浏览器中输入http://localhost:8080/XfireSample/services/hello?wsdl 可以看到。

  WSDL本身比较复杂,它主要给程序看的,利用当前大多数的Web服务工具可以生成它,而无需手工编写它。
  WSDL的主要目的在于将自己的Web服务的所有相关内容如提供服务的传输方式,服务方法接口,接口参数,服务路径等,生成相应的完全的文档,发布给使用者。使用者可以通过这个WSDL文档,创建相应的SOAP请求消息,通过HTTP传递给Web服务提供者;Web服务提供者在完成请求服务后,将SOAP返回消息传回给请求者,服务请求者再根据WSDL文档将SOAP返回消息解析成程序能够理解的内容。

六.UDDI
UDDI是Universal Description Discovery and Intergretion的缩写,是一种创建注册服务的规范,以便大家将自己的Web Service进行注册发布供使用者查找。
当服务提供者想将自己的Web Service发布,以便外部能找到其服务时,那么服务提供这可以将自己的Web Service注册到相应的UDDI商用注册网站。
UDDI并非一个必须的Web Service组件,服务方完全可以不进行UDDI的注册。因为WSDL文件中已经给出了Web Service的地址URI,外部可以通过它进行相应的Web Service调用.

七.消息服务与WebService的比较

在概念上,Web Service和消息服务它们都是传输数据到别的组件,都是使应用程序之间可以进行异步通信。
消息处理和Web Service是互补的技术,消息服务明确是一项为企业内部而不是为商业领域内的应用程序提供通信的技术,使用消息处理,企业必须与共用的传输格式达成一致,在定义应用程序之间传递的数据方面,消息具有更多的灵活性,另外,Web Service缺乏一个定义好的机制,用于确保SOAP传输和事务处理,这些是消息服务已经定义好和成熟的部分。
Web Service,是松散耦合的组件,应用程序发送请求给它进行处理和数据服务,结果返回给应用程序继续处理,传输机制是Simple Object Access Protocol(简单对象访问协议,SOAP),Web Service通过SOAP能有效的通过HTTP协议发送XML文档。Web Service具有公开性,具有快速推进的标准和大量出版物与技术文档。Web Service有潜力来连接不同的应用程序组件,把软件定义成服务而不是产品。如果应用程序是新建的,则Web Service更为合理。

八.使用Axis的WebService实现。
以上文章是针对XFire的WS实现,如果要用Axis的实现,可以参考这里 http://www.blogjava.net/heyang/archive/2009/10/10/297729.htmlhttp://www.blogjava.net/heyang/archive/2009/09/29/296897.html。个人感觉XFire的方案更方便快捷,如果没有限制的话建议使用XFire实现Web Service。

好了,感谢您看到这里。
posted @ 2010-12-10 17:27 何杨 阅读(436) | 评论 (0)编辑 收藏

一.框架类
   1.JavaScript框架:ExtJshttp://www.sencha.com/
   2.O/R Mapping框架:Hibernatehttp://www.hibernate.org/
   3.JavaScript框架:Jquery(http://jquery.com/)
   4.JavaScript框架:Prototypehttp://www.prototypejs.org/
   5.业务层Bean管理框架:Springhttp://www.springsource.org/
   6.Web框架Struts1:Strutshttp://struts.apache.org/
   7.Web框架Struts2:Struts 2http://struts.apache.org/2.x/index.html

二.工具包类
   1.用于编码处理(Base64,DES,RSA.MD5等)的Apache Commons Codechttp://commons.apache.org/codec/

三.开发测试工具
   1.网页测试工具:HttpUnithttp://httpunit.sourceforge.net/
   2.Java单元测试工具:JUnithttp://www.junit.org/
   3.网络数据包截获工具:TCPMonhttp://ws.apache.org/commons/tcpmon/download.cgi

四.服务器类


五.数据库类
   1.轻量级纯JavaSQL数据库引擎HSQLDBhttp://hsqldb.org/
   2.重量级数据库Oraclehttp://www.oracle.com/technetwork/database/enterprise-edition/downloads/index.html

六.插件类
   1.用于UML图绘制的Eclipse插件Amateurhttp://sourceforge.jp/projects/amateras/releases/?package_id=4435

七.技术站点社区类
   1.中文综合技术社区CSDN社区http://community.csdn.net/
   2.英文综合技术站点ServerSidehttp://www.theserverside.com/

八.引擎类
   1.Java Web服务实现引擎:XFirehttp://xfire.codehaus.org/
   2.Java Web服务实现引擎:Axis2(http://axis.apache.org/axis2/java/core/download.cgi

九.工具类
   1.网络数据包嗅探器Wiresharkhttp://www.wireshark.org/download.html
   2.Web检测工具WebToolhttp://www.hackline.net/a/soft/tools/2010/0603/4198.html
   3.Office工具POI(http://poi.apache.org/
posted @ 2010-12-09 20:32 何杨 阅读(374) | 评论 (0)编辑 收藏

MD5是消息摘要算法的一种,它和SHA,HMAC是消息摘要算法的主要代表,其前身有MD2,MD3,MD4算法。
消息摘要算法又称为散列算法,其不可破解的核心在于散列函数的单向性,即可以通过散列函数得到结果,却不可能通过结果反推出其原始信息。这是消息摘要算法的安全性根本所在。如果用户输入的密码是123456789,则会得到25f9e794323b453885f5181f1b624d0这样的结果;如果有人拿到25f9e794323b453885f5181f1b624d0这样的结果,他是不可能反推出密码123456789的。
但是,总所周知的是,MD5已经被我国山东大学王小云教授攻破了。他是怎么做到这不可能的事呢?当然不是反推,而是使用的碰撞算法,具体来说就是,拿到25f9e794323b453885f5181f1b624d0这样的结果,用多种精心设计的字符串去试试,总有一个字符串经MD5加密后能得到25f9e794323b453885f5181f1b624d0这样的结果,这个字符串也许是真实密码,也是是别的,但它加密后可以得到和123456789加密后一样的效果。这就意味着,你给自己设定的密码,别人通过其他密码也可能通过验证!
其原因还是在于散列函数,不同的输入通过散列函数可能得到同一结果,虽然这个可能性较小。王教授成果的意义在于,以前号称用全世界所有计算机算一百年不能做到的,用他的办法用一台普通微机在数个小时内就能做到。这个很了不起,诸位如果有意可以去当他的研究生,这样就知道是怎么做的了。
那么,MD5还有存在的价值吗。当然有,因为破解者要破解成功有三个必要条件,一,知道算法;二,知道密钥;三,有大量数据供测试。如果把几种其它算法和MD5混合,破解者就容易困惑,再加上时间限制,破解也不是件容易的事。最后,还有理论上不可能破解的量子密码,如果它能实用化,则能达到真正意义上的不可破解。


posted @ 2010-12-08 18:58 何杨 阅读(407) | 评论 (2)编辑 收藏

密码学的加密算法可分为 单向加密算法,对称加密算法和非对称加密算法三类。
  • 单向加密算法是数据完整性验证的常用算法,MD5SHA是单向加密算法的代表;
  • 对称加密算法是数据存储加密的常用算法,DESAES是对称加密算法的代表;
  • 非对称加密算法是数据传输加密的常用算法,RSA是非对称加密算法的代表。对称加密算法也可以用作数据传输加密,但非对称加密算法在密钥管理方面更有优势,在安全级别上更高,只是时间效率上不如对称加密算法。

JAVA API对密码学的支持
  • MessageDigest类,可以构建MD5,SHA两种加密算法;
  • Mac类可以构建HMAC加密算法;
  • Cipher类可以构建多种加密算法,如DES,AES,RSA,DSA,DH等;
  • Signature类可用于数字签名和签名验证;
  • Certificate类可用于操作证书。

posted @ 2010-12-05 14:24 何杨 阅读(216) | 评论 (0)编辑 收藏

本版新增功能:
1.增加对DB2数据库的支持。
2.过滤器不区分大小写。
3.取消了欢迎窗口。

下载地址:
http://www.box.net/shared/0flunl0zul

Softonic下载页面:
http://sqltoolbox.softonic.cn/

概述

SqlToolBox是一款纯绿色的免费数据库客户端软件,基于Java Swing编制而成,旨在于为开发人员,系统工程师和数据库管理员提供一种通用方便和快捷的数据库操作工具,使他们摆脱需要学习掌握使用多种数据库客户端 的苦恼,并减轻他们日常操作数据库和编写Sql语句的任务量,帮助他们把精力投入到解决更有意义的问题上去。

SqlToolBox现有功能

  1. 能连接到MySql,Oracle,Ms Sql Server和DB2四种数据库。
  2. 连接到数据库后,会提供数据库Schema和表的树视图以便用户进行浏览和查找,另外还提供了一个过滤器帮助用户缩小查找范围。
  3. 用户能自动快速获取单表的创建,查询,更新,删除,建表语句,整表全部数据插入语句,单表对应Pojo类和单表的Hibernate映射文件等常用文字,且可借此构造更复杂的Sql语句。
  4. 能执行Sql语句并显示执行结果,如果是查询语句会以表格形式显示结果,还提供CSV形式数据下载;如果是非查询语句或是错误的查询语句则会以文字形式告知用户。
  5. 在用户输入Sql语句的过程中提供Sql语法高亮功能,以助于Sql语句的识别。
  6. 提供Sql格式化功能以助于Sql语句的识别和整理。
  7. 提供Redo/Undo,Shift整体退格进格,大小写转化,将Sql语句用StringBuilder包容以及将Sql语句中关键字大写表示等常用文字编辑功能。这些都能帮助程序员在程序中书写Sql语句。
  8. 能保存和记忆数据库信息,以便下次打开。

运行SqlToolBox有何前提条件?

将SqlToolBox运行起来的唯一前提是安装JDK6或以上版本。

SqlToolBox需要安装吗?

SqlToolBox是一款纯绿色软件,它对您的系统不做出任何更改,因此不需要安装和卸载。

SqlToolBox安全吗?

由于软件使用Java编写而成,它本身就具有较高的安全性。此外作者保证在SqlToolBox整个系列中都不会加入病毒,木马,插件等坏东西。

如何运行SqlToolBox?

解开下载包,然后双击run.bat即可。

在Unix/Linux下如何运行SqlToolBox?

除了也需要安装JDK外,您还需要参照run.bat写一份脚本,然后执行它。

如何使用SqlToolBox打开一个数据库?

程序运行起来后,您将看到一个输入数据库信息的对话框,请依次填入数据库所在机器的IP地址,数据库的库名称,选择数据库的类型以及输入登录数据库的用户 名和密码等必要信息。此后再点击“连接数据库”按钮,程序将打开数据库。如果您将以上信息填错也不要紧,程序会提示哪里出现了问题。此外您可以在登录前点 击“测试连接”按钮,程序也会告诉您是否能连接到指定的数据库。

打开数据库后程序左边部分如何使用?

成功连接到数据库以后,数据库的Schema和table结构会在画面的左边以树的形式展现出来,如果展现的内容过多,您还可以在上方的“过滤器”输入栏 中输入关键字以缩小展现范围。在这颗树中,表格(table)是以小圆点的方式展现的,左键点击这个圆点,程序将在右侧打开一个Sql语句操作窗口,并执 行“select * from table”语句,最后在下方以表格的形式展现给您;如果您用右键点击这个圆点,程序将弹出一个右键菜单,选择其中的项目您将可以在右边的Sql语句操作 窗口中得到单表的字段信息,创建(insert),查询(select),更新(update),删除语句(delete)及建表语句(create table),单表对应Pojo文件,单表的Hibernate映射文件等文字。

打开数据库后程序右边部分是如何使用的?

用左右键点击表格后,您将在右侧看到一个“Sql语句操作窗口”,它分成三部分:工具栏菜单,输入窗口和输出窗口。输入窗口是用以输入,编辑和整理Sql 语句的;工具栏菜单中的一大排按钮都是为编辑处理输入窗口中的文字而准备的;输出窗口则是展示Sql语句执行后的结果的,如果是查询语句,它会以表格的形 式告知您查询的结果,如果是其它语句,它会以文字的形式告知。通常的操作手法是,先在输入窗口中用鼠标选中您要操作的文本,再在工具栏菜单中点击执行特定 操作的按钮,然后在下方的输出窗口中就能看到具体的结果,当然如果仅是文本编辑操作的话输出窗口是不会有反应的。

如何执行Sql语句?

程序员和数据库管理员总是习惯使用语句来操作数据库,这也是本软件的最重要功能之一。执行Sql语句的过程具体来说是这样做的,首先,在输入窗口输入您向 执行的Sql语句,如“select * from table”之类,当然您更可以通过表格的右键菜单来获得常用的sql语句(在输入或是粘贴文本的过程中,Sql语句中的关键字会以蓝色显示,这是语法高 亮功能所致);其次,你需要选中你想执行的文本,再点击工具栏菜单中的向右三角形按钮,这段文本将得到执行,执行结果将在下方的输出窗口得到展示。如果您 执行的是查询语句,输出窗口将以表格的形式列出查询结果集的字段和内容;如果您执行的是删除,更新,添加,修改表等语句或是执行错误的Sql文本,输出窗 口将以文本形式告知执行结果。另外工具栏菜单中的双向右三角形按钮用于批量执行Sql语句,它以分号“;”来作为每段Sql的分隔标志,然后分别执行每 段。

如何快速调整对执行查询语句后得到的表格列宽度?

如果您想自动调整某列的宽度,可以双击这列的表头,此后这列的宽度会根据这列的最长文字进行调整;您还可以在表格上点击右键,选择“调整列宽为最适合状态”一项,那么所有的列宽都会进行调整。

如何得到执行查询语句后得到的表格的内容?

您还可以在表格上点击右键,选择“下载表格为CSV文件”一项,此后查询语句和得到的结果都会被放入一个CSV文件中。CSV是一中文本文件,但您可以用Excel打开它,也会得到xls文件一样的效果。

在新增或是删除一张表后,在左边的树中为什么没有相应的变化?

新增或是删除一张表后,您需要手动执行一下左上方的更新按钮(最上方的大图标中第一个),此后程序会重新载入数据库的Schema和table,这样您刚才对表格进行增删操作就能体现出来。

如果我需要常打开数据库进行操作或是需要常操作多个数据库,程序能为我提供那些便利?

本软件有记忆功能,如果您正确连接到一个数据库,那么相应的信息如IP地址,数据库名,数据库类型,连接数据库的用户名和密码都会被记忆下来,这样下次打 开时就不用重复输入了。如果您需要常操作多个数据库,您可以通过保存按钮(最上方五个大图标中的第二个)将数据库信息保存成XML文件,这样在登录画面中 就可以通过“打开文件按钮”得到相应的数据库信息。

如果我有想法和建议,如何与作者联系?

首先,您可以点击程序上方的信封按钮,通过邮件heyang78@gmail.com和我联系,我会乐于回复您的邮件并会认真考虑您提出的想法和建议;其次,您还可以通过QQ和我联系,我的Q号是805985315;其三,我的MSN是junglesong_5@gmail.com,通过MSN也能找到我;最后,欢迎您登录我的博客http://heyang.blogjava.net,如果SqlToolBox有所变化,我会在第一时间在博客上公告。

感谢名单

SqlToolBox的成长离不开以下人士的建议,激励和帮助,在此谨向他们表示诚挚的谢意:
  • danielxu(关于jtds-1.2.2.jar的添加)
  • creasure(关于开源的建议)
  • Always BaNg.(关于语法高亮)
  • mircle(关于提升加载数据库对象的性能)
  • willim2000(他也做了一个类型相同的软件)
  • ytfulz(提供连接SqlServer的连接测试以,改变输出表格形式,调整输出表格列宽的建议)
  • 王宏亮(提供将程序和JRE整体打包的建议)
  • 朱俭(关于帮助窗口只打开一个的建议)
  • ☆振兴中华☆(关于选择数据表的建议)


posted @ 2010-12-03 19:25 何杨 阅读(1217) | 评论 (4)编辑 收藏

安装步骤:
1.到http://sourceforge.jp/projects/amateras/releases/?package_id=4435 去下载 AmaterasUML_1.3.2.zip
2.下载完毕后,解开压缩包,将其中三个jar文件拷贝到你的Eclipse目录的plugins目录下。
3.启动或者重启您的Eclipse。

如何使用:
1.点击Eclipse的菜单"File"--"New"--"Others"。


2.找到Amateras UML一项,选择你要绘制的UML图类型。


3.选择一个要存储UML图文件的文件夹。


4.好了,可以开始画了。



我是在JavaEye看人介绍后装的,用了感觉确实不错,Visio可以见回收站去了。

posted @ 2010-12-02 14:29 何杨 阅读(1694) | 评论 (0)编辑 收藏

按:以下文字涉及RSA对WebService传递的数据的加密解密,如果您已经熟知RSA或是有其它更好的方法请不要往下看以免浪费时间.

WebService采用的协议是SOAP,它基于HTTP,而HTTP是明文方式,也就是说,采用WebService传递的数据是明文的。如果是天气预报这种公开的只读信息的WebService无所谓,如果涉及写入或是和私密数据相关,那么明文传递就有很大的潜在危险性,必须加以遏止。

一般来说有两种方法,一是采用https加密的方式,另一种是用非对称加密算法对数据加密,下文提到的RSA就是第二种。

使用RSA对WebService传递的信息加密解密的基本思想是:服务器端提供一个WebService方法byte[] getServerPublicKey(),客户端可以以此得到服务器端的公钥,然后使用服务器端的公钥对要传出去的数据进行RSA加密,并附带以自己的公钥;服务器端得到客户端的请求后,先用自己的私钥解密客户端送来的数据,得到处理结果后用客户端提供的公钥加密,然后传回;客户端得到服务器端的返回数据后,用自己的私钥进行解密,最终得到了服务器端的真实数据。服务器端和客户端各自保存自己的RSA私钥用于解密,提供给对方RSA公钥进行加密,这样中间传递的信息就安全了。

加密解密示意顺序图:


下面是服务器端实现类的代码:
package com.heyang;


public class ServiceImpl implements IService{
    @Override
    
public byte[] getResonse(byte[] params, byte[] clientPublicKey) {
        
try {
            
// 使用自己的私钥解密客户端用服务器端公钥加密的数据
            String decryptString=SecurityUtil.getCoder().getDecryptString(params);
            
            
// 要返回的结果
            String response="你好!"+decryptString;
            
            
// 使用客户端提供的公钥对返回的数据进行加密
            byte[] retval=SecurityUtil.getCoder().getEncryptArray(response, clientPublicKey);
            
            
return retval;
        } 
catch (Exception e) {
            e.printStackTrace();
            
            
return null;
        }
    }

    @Override
    
public byte[] getServerPublicKey() {
        
return SecurityUtil.getCoder().getPublicKey();
    }
}


客户端调用服务器端的代码:
package com.heyang;

import org.codehaus.xfire.XFireFactory;
import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.service.binding.ObjectServiceFactory;

public class Test {
    
public static void main(String[] args) {
        Service srvcModel 
= new ObjectServiceFactory().create(IService.class);
        XFireProxyFactory factory 
= new XFireProxyFactory(XFireFactory
                .newInstance().getXFire());

        String helloWorldURL 
= "http://localhost:8080/XfireSample/services/hello";
        
try {
            IService srvc 
= (IService) factory.create(srvcModel, helloWorldURL);

            
// 得到服务器端的公钥
            byte[] serverPublicKey=srvc.getServerPublicKey();
            System.out.print(
"从服务器端得到的公钥为:");
            
for(byte b:serverPublicKey){
                System.out.print(b);
            }
            System.out.println();
            
            
            RSASecurityCoder coder
=SecurityUtil.getCoder();
            String requestString
="世界";
            
            
// 使用服务器端的公钥对要传出去的数据进行加密
            byte[] params=coder.getEncryptArray(requestString, serverPublicKey);
            
            
// 得到服务器端的返回结果
            byte[] responseArray=srvc.getResonse(params, coder.getPublicKey());
            
            
// 使用自己的私钥进行解密
            String responseString=coder.getDecryptString(responseArray);
            System.out.println(
"从服务器端返回的字符串结果是:"+responseString);
        } 
catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出的结果为:
从服务器端得到的公钥为:48-127-9748136942-12272-122-913111503-127-115048-127-1192-127-1270-575108-121578675121-687-32-1165359-2586-50-127114-24-6769-17-128115114982868-11550-121-111-69-494021-48-22-5844-37-8645-115-125-984651-344761-117-7875-34115-101-119164666123-4211-13-103-62-30-587926842-12338-32-91-24-75-1177128103-12-71108-121-122112-712-1089753-2691-7863-6385-41-10210782-8784120344-69-90474108-3661-47089-1261812510046-123-3910723101
从服务器端返回的字符串结果是:你好!世界

服务器端和客户端使用的RSA加密解密类代码:
package com.heyang;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

/**
 * RSA加密解密类
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 * 创建时间:2010-12-1 下午06:14:38
 * 修改时间:2010-12-1 下午06:14:38
 
*/
public class RSASecurityCoder{
    
// 非对称加密密钥算法
    private static final String Algorithm="RSA";
    
    
// 密钥长度,用来初始化
    private static final int Key_Size=1024;
    
    
// 公钥
    private final byte[] publicKey;
    
    
// 私钥
    private final byte[] privateKey;
    
    
/**
     * 构造函数,在其中生成公钥和私钥
     * 
@throws Exception
     
*/
    
public RSASecurityCoder() throws Exception{
        
// 得到密钥对生成器
        KeyPairGenerator kpg=KeyPairGenerator.getInstance(Algorithm);
        kpg.initialize(Key_Size);
        
        
// 得到密钥对
        KeyPair kp=kpg.generateKeyPair();
        
        
// 得到公钥
        RSAPublicKey keyPublic=(RSAPublicKey)kp.getPublic();
        publicKey
=keyPublic.getEncoded();
        
        
// 得到私钥
        RSAPrivateKey keyPrivate=(RSAPrivateKey)kp.getPrivate();
        privateKey
=keyPrivate.getEncoded();
    }
    
    
/**
     * 用公钥对字符串进行加密
     * 
     * 说明:
     * 
@param originalString
     * 
@param publicKeyArray
     * 
@return
     * 
@throws Exception
     * 创建时间:2010-12-1 下午06:29:51
     
*/
    
public byte[] getEncryptArray(String originalString,byte[] publicKeyArray) throws Exception{
        
// 得到公钥
        X509EncodedKeySpec keySpec=new X509EncodedKeySpec(publicKeyArray);
        KeyFactory kf
=KeyFactory.getInstance(Algorithm);
        PublicKey keyPublic
=kf.generatePublic(keySpec);
        
        
// 加密数据
        Cipher cp=Cipher.getInstance(Algorithm);
        cp.init(Cipher.ENCRYPT_MODE, keyPublic);
        
return cp.doFinal(originalString.getBytes());
    }
    
    
    
/**
     * 使用私钥进行解密
     * 
     * 说明:
     * 
@param encryptedDataArray
     * 
@return
     * 
@throws Exception
     * 创建时间:2010-12-1 下午06:35:28
     
*/
    
public String getDecryptString(byte[] encryptedDataArray) throws Exception{
        
// 得到私钥
        PKCS8EncodedKeySpec keySpec=new PKCS8EncodedKeySpec(privateKey);
        KeyFactory kf
=KeyFactory.getInstance(Algorithm);
        PrivateKey keyPrivate
=kf.generatePrivate(keySpec);
        
        
// 解密数据
        Cipher cp=Cipher.getInstance(Algorithm);
        cp.init(Cipher.DECRYPT_MODE, keyPrivate);
        
byte[] arr=cp.doFinal(encryptedDataArray);
        
        
// 得到解密后的字符串
        return new String(arr);
    }

    
public byte[] getPublicKey() {
        
return publicKey;
    }
    
    
public static void main(String[] arr) throws Exception{
        String str
="你好,世界! Hello,world!";
        System.out.println(
"准备用公钥加密的字符串为:"+str);
        
        
// 用公钥加密
        RSASecurityCoder rsaCoder=new RSASecurityCoder();
        
byte[] publicKey=rsaCoder.getPublicKey();        
        
byte[] encryptArray=rsaCoder.getEncryptArray(str, publicKey);
        
        System.out.print(
"用公钥加密后的结果为:");
        
for(byte b:encryptArray){
            System.out.print(b);
        }
        System.out.println();
        
        
// 用私钥解密
        String str1=rsaCoder.getDecryptString(encryptArray);
        System.out.println(
"用私钥解密后的字符串为:"+str1);
    }
}

用于初始化RSASecurityCoder实例的SecurityUtil类代码:
package com.heyang;

/**
 * 信息安全实用类
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 * 创建时间:2010-12-2 上午10:57:49
 * 修改时间:2010-12-2 上午10:57:49
 
*/
public class SecurityUtil{
    
// 用于加密解密的RSA编码类
    private static RSASecurityCoder coder;
    
    
/**
     * 初始化coder的静态构造子
     
*/
    
static{
        
try {
            coder
=new RSASecurityCoder();
        } 
catch (Exception e) {
            e.printStackTrace();
        }
    }

    
public static RSASecurityCoder getCoder() {
        
return coder;
    }
}


您可以从http://www.box.net/shared/cyg98xgz78 获得上述代码涉及到的两个实例工程。

好了,感谢您看到这里,希望此文字没有耽误您太多宝贵时间。
posted @ 2010-12-02 11:44 何杨 阅读(11015) | 评论 (16)编辑 收藏

按:以下文字涉及RSA解密加密的基本操作,您如果已经知晓就不用浪费时间了。

在加密解密过程中,如果加密解密双方都使用同一密钥,那么泄密的可能性还是存在的,无论你把这个密钥放在代码,文件或是数据库中。最好是密钥分成两部分,公钥提供出去给应答者,让它给返回的结果加密,请求者得到返回结果后,用自己的私钥将其解密,公钥和私钥都由程序生成。这样,客户端和服务器端程序的所有者和编写者都难以知道每个客户端的私钥是什么,从而难以破解数据。RSA就是实现这一想法的途径之一。

举例来说,现在有一客户端视图和WebService服务器端通信,假如服务器端的响应函数是 String getResponse(String params,byte[] publicKeyArray);两边程序都有下面的RSASecurityCoder类,客户端在发送请求前,可以得到此类的一个实例,并得到其公钥,然后调用服务器端的getResponse函数,公钥就是这个函数的第二个参数;服务器端得到请求后,处理得到结果,然后用第二个参数--客户端送来的公钥进行加密,然后送回结果;客户端得到结果后用自己的私钥进行解密就可以了。这样,信息在传输过程的安全性就有了充分的保证了。

下面请看代码:
package com.heyang.util;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

/**
 * RSA加密解密类
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 * 创建时间:2010-12-1 下午06:14:38
 * 修改时间:2010-12-1 下午06:14:38
 
*/
public class RSASecurityCoder{
    
// 非对称加密密钥算法
    private static final String Algorithm="RSA";
    
    
// 密钥长度,用来初始化
    private static final int Key_Size=1024;
    
    
// 公钥
    private final byte[] publicKey;
    
    
// 私钥
    private final byte[] privateKey;
    
    
/**
     * 构造函数,在其中生成公钥和私钥
     * 
@throws Exception
     
*/
    
public RSASecurityCoder() throws Exception{
        
// 得到密钥对生成器
        KeyPairGenerator kpg=KeyPairGenerator.getInstance(Algorithm);
        kpg.initialize(Key_Size);
        
        
// 得到密钥对
        KeyPair kp=kpg.generateKeyPair();
        
        
// 得到公钥
        RSAPublicKey keyPublic=(RSAPublicKey)kp.getPublic();
        publicKey
=keyPublic.getEncoded();
        
        
// 得到私钥
        RSAPrivateKey keyPrivate=(RSAPrivateKey)kp.getPrivate();
        privateKey
=keyPrivate.getEncoded();
    }
    
    
/**
     * 用公钥对字符串进行加密
     * 
     * 说明:
     * 
@param originalString
     * 
@param publicKeyArray
     * 
@return
     * 
@throws Exception
     * 创建时间:2010-12-1 下午06:29:51
     
*/
    
public byte[] getEncryptArray(String originalString,byte[] publicKeyArray) throws Exception{
        
// 得到公钥
        X509EncodedKeySpec keySpec=new X509EncodedKeySpec(publicKeyArray);
        KeyFactory kf
=KeyFactory.getInstance(Algorithm);
        PublicKey keyPublic
=kf.generatePublic(keySpec);
        
        
// 加密数据
        Cipher cp=Cipher.getInstance(Algorithm);
        cp.init(Cipher.ENCRYPT_MODE, keyPublic);
        
return cp.doFinal(originalString.getBytes());
    }
    
    
    
/**
     * 使用私钥进行解密
     * 
     * 说明:
     * 
@param encryptedDataArray
     * 
@return
     * 
@throws Exception
     * 创建时间:2010-12-1 下午06:35:28
     
*/
    
public String getDecryptString(byte[] encryptedDataArray) throws Exception{
        
// 得到私钥
        PKCS8EncodedKeySpec keySpec=new PKCS8EncodedKeySpec(privateKey);
        KeyFactory kf
=KeyFactory.getInstance(Algorithm);
        PrivateKey keyPrivate
=kf.generatePrivate(keySpec);
        
        
// 解密数据
        Cipher cp=Cipher.getInstance(Algorithm);
        cp.init(Cipher.DECRYPT_MODE, keyPrivate);
        
byte[] arr=cp.doFinal(encryptedDataArray);
        
        
// 得到解密后的字符串
        return new String(arr);
    }

    
public byte[] getPublicKey() {
        
return publicKey;
    }
    
    
public static void main(String[] arr) throws Exception{
        String str
="你好,世界! Hello,world!";
        System.out.println(
"准备用公钥加密的字符串为:"+str);
        
        
// 用公钥加密
        RSASecurityCoder rsaCoder=new RSASecurityCoder();
        
byte[] publicKey=rsaCoder.getPublicKey();        
        
byte[] encryptArray=rsaCoder.getEncryptArray(str, publicKey);
        
        System.out.print(
"用公钥加密后的结果为:");
        
for(byte b:encryptArray){
            System.out.print(b);
        }
        System.out.println();
        
        
// 用私钥解密
        String str1=rsaCoder.getDecryptString(encryptArray);
        System.out.println(
"用私钥解密后的字符串为:"+str1);
    }
}

输出:
准备用公钥加密的字符串为:你好,世界! Hello,world!
用公钥加密后的结果为:
62-90-128-107-100-7070-11157-123-9160-6-116-68-1476-45-112-107-53-90107-84-670-9862-35-11116-83-10864312117-96-117-56995-2510321-89-89-828977-8810940100-91-76986562-222574-12815-120118-103-11-121-6030-6490-79-804911111-17-473984-7046-12294-8454-27108-26-11281-43833782-7926-612284-81781132357-3108-12673245-5111912-86-10041-799104-8146-5712374-55
用私钥解密后的字符串为:你好,世界! Hello,world
!


看到这里,如果有人说客户端调用服务器端的getResponse函数时,第一个参数params不是还会暴露一部分信息吗? 不要怕,我们可以让服务器端再准备一个WebService函数 byte[] getServerPublicKey();客户端可以调用这个函数以得到服务器端的公钥,然后把params用这个公钥加密,然后再调用getResponse(String params,byte[] publicKeyArray)函数,服务器端接到请求后,用自己的私钥对第一个参数进行解密就可以了。这样,所有信息都得到了保护。

如果String的表现力不够怎么办,有了XML的帮助,这从来不是问题,您说呢?

好了,感谢您看到这里,希望上面的文字能对您有所帮助;如果您要使用的话,上面的代码需要改写一下,相信您知道该怎么办。

posted @ 2010-12-01 19:19 何杨 阅读(493) | 评论 (0)编辑 收藏

按:以下内容涉及传统的AES加密解密方法,熟悉它的请不要浪费宝贵时间。

如果用Base64进行加密解密是不安全的,因为这种方式的方法和密钥(字符映射表)都是公开的,对此熟悉的人如果看到一串字符后面带一些等号,很容易想到是Base64进行加密。因此,我们必须采取一些更安全的加密解密方式,AES就是其一。

在使用AES进行加密解密之前,需要到Sun的官方网站上下载一个权限文件:jce_policy,目前它的下载网址是:http://www.oracle.com/technetwork/java/javase/downloads/index.html ,找到“Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 6”后点击按钮下载,得到下载文件后解开,然后将其中的local_policy.jar和US_export_policy.jar拷贝到你的JAVA_HOME\jre\lib\security和JRE_HOME\lib\security两个目录下。如果没有这一步骤,进行加密解密的时候会产生java.security.InvalidKeyException异常。

接下来就是代码了:
package com.heyang.util;

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Hex;


/**
 * AES算法加密解密实用工具类
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 * 创建时间:2010-11-29 上午11:19:11
 * 修改时间:2010-11-29 上午11:19:11
 
*/
public class AESSecurityUtil{
    
// 加密方法
    private static final String Algorithm="AES";
    
    
// 进行加密解密的密钥
    private static final String Key="03a53dfc257fe1b0996626a5e2e2210692936bd16cc60f37211cbeef9353e268";
    
    
/**
     * 取得解密后的字符串
     * 
     * 说明:
     * 
@param encryptArr
     * 
@return
     * 创建时间:2010-12-1 下午03:33:31
     
*/
    
public static String getDecryptString(byte[] encryptArr){
        
try{
            Cipher cp
=Cipher.getInstance(Algorithm);
            cp.init(Cipher.DECRYPT_MODE, getKey());
            
byte[] arr=cp.doFinal(encryptArr);
            
            
return new String(arr);
        }
        
catch(Exception ex){
            System.out.println(
"无法进行解密,原因是"+ex.getMessage());
            
return null;
        }
    }
    
    
/**
     * 取得加密后的字节数组
     * 
     * 说明:
     * 
@param originalString
     * 
@return
     * 创建时间:2010-12-1 下午03:33:49
     
*/
    
public static byte[] getEncryptByteArray(String originalString){
        
try{
            Cipher cp
=Cipher.getInstance(Algorithm);
            cp.init(Cipher.ENCRYPT_MODE, getKey());
            
return cp.doFinal(originalString.getBytes());
        }
        
catch(Exception ex){
            System.out.println(
"无法进行加密,原因是"+ex.getMessage());
            
return null;
        }
    }
    
    
/**
     * 取得密钥数组
     * 
     * 说明:
     * 
@return
     * 
@throws Exception
     * 创建时间:2010-12-1 下午03:31:08
     
*/
    
private static byte[] initKey() throws Exception{
        KeyGenerator kg
=KeyGenerator.getInstance(Algorithm);
        kg.init(
256);
        
        SecretKey sk
=kg.generateKey();
        
        
return sk.getEncoded();
    }
    
    
/**
     * 取得字符串形式的密钥
     * 
     * 说明:
     * 
@return
     * 
@throws Exception
     * 创建时间:2010-12-1 下午03:31:36
     
*/
    
public static String initKeyHex() throws Exception{
        
return new String(Hex.encodeHex(initKey()));
    }
    
    
/**
     * 取得密钥
     * 
     * 说明:
     * 
@return
     * 
@throws Exception
     * 创建时间:2010-12-1 下午03:33:17
     
*/
    
private static Key getKey() throws Exception{
        
byte[] arr=Hex.decodeHex(Key.toCharArray());
        
        
return new SecretKeySpec(arr,Algorithm);
    }
    
    
public static void main(String[] args)  throws Exception{
        
//System.out.println(initKeyHex());
        
        String str
="Hello!World 你好!世界。";
        
        
byte[] arr=AESSecurityUtil.getEncryptByteArray(str);
        System.out.print(
"AES加密后的结果为:");
        
for(byte b:arr){
            System.out.print(b);
        }
        System.out.println();
        
        String str1
=AESSecurityUtil.getDecryptString(arr);
        System.out.println(
"AES解密后的字符串为:"+str1);
    }
}
测试输出如下:
AES加密后的结果为:833522115-115-6373-10-940-110-93-87736-561-1083427-99-6-6218-4104108-1031216395-92
AES解密后的字符串为:Hello
!World 你好!世界。

上面代码中值得注意的是,加密后的结果不能直接变成String形式,因为这会导致解密的不可行(解密抛出javax.crypto.IllegalBlockSizeException异常)。如果要使用其他的Key,可以单独执行一下initKeyHex()函数,将输出结果置换掉静态变量Key的值即可。

这样,在AES的帮助下,我们实现了比较安全的加密,破解者知道方法AES,但不知道密钥的话,解密会很困难。但是,话说回来,java程序被反编译很容易,别有用心的人还是可以看到密钥,但我们还是可以用公钥加密私钥解密的方式来对付,这个以后有空再说。

好了,感谢您看到这里。
posted @ 2010-12-01 16:10 何杨 阅读(4052) | 评论 (1)编辑 收藏

按:以下内容很简单,对Base64熟悉者无须往下看。

Base64是一种基于64个字符的编码算法,最早用于解决电子邮件传输的问题,它的编码和解码操作可以充当加密和解密操作,其字符映射表就是其密钥。但是,Base64算法及其密钥都是公开的,因此不能被认为是安全的加密解密方法。

下面是其示例代码:
package com.heyang.util;

import org.apache.commons.codec.binary.Base64;


/**
 * 常规Base64加密解密实用工具类
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 * 创建时间:2010-11-29 上午07:52:01
 * 修改时间:2010-11-29 上午07:52:01
 
*/
public class Base64SecurityUtil{
    
/**
     * 得到Base64加密后的字符串
     * 
     * 说明:
     * 
@param originalString
     * 
@return
     * 创建时间:2010-11-29 上午07:53:30
     
*/
    
public static String getEncryptString(String originalString){
        
byte[] arr = Base64.encodeBase64(originalString.getBytes(), true);
        
return new String(arr);
    }
    
    
/**
     * 得到Base64解密后的字符串
     * 
     * 说明:
     * 
@param encryptString
     * 
@return
     * 创建时间:2010-11-29 上午07:56:02
     
*/
    
public static String getDecryptString(String encryptString){
        
byte[] arr = Base64.decodeBase64(encryptString.getBytes());
        
return new String(arr);
    }
    
    
/**
     * 测试
     * 
     * 说明:
     * 
@param args
     * 创建时间:2010-11-29 上午07:56:39
     
*/
    
public static void main(String[] args){
        String str
="Hello world!你好,世界。";
        
        String str1
=Base64SecurityUtil.getEncryptString(str);
        System.out.println(
"经Base64加密后的密文为"+str1);
        
        String str2
=Base64SecurityUtil.getDecryptString(str1);
        System.out.println(
"经Base64解密后的原文为"+str2);
    }
}
输出:
经Base64加密后的密文为SGVsbG8gd29ybGQhxOO6w6OsysC956Gj

经Base64解密后的原文为Hello world
!你好,世界。


posted @ 2010-11-29 08:10 何杨 阅读(1220) | 评论 (0)编辑 收藏

按:以下还是炒冷饭,如果您对加盐了解就不用往下看了,以免浪费宝贵时间。
如果不了解下文部分细节的话,您可以参考这篇文章:使用MD5对存放在数据库中用户密码进行保护


直接对重要数据进行MD5处理后,反向解密确实难度很大,但还是可以找出破绽的,请看下图:


如果名为李自成的用户可以查看数据库,那么他可以观察到自己的密码和别人的密码加密后的结果都是一样,那么,别人用的和自己就是同一个密码,这样,就可以利用别人的身份登录了。

那么我们以前的加密方法是否对这种行为失效了呢?其实只要稍微混淆一下就能防范住了,这在加密术语中称为“加盐”。具体来说就是在原有材料(用户自定义密码)中加入其它成分(一般是用户自有且不变的因素),以此来增加系统复杂度。当这种盐和用户密码相结合后,再通过摘要处理,就能得到隐蔽性更强的摘要值。下面请见代码:
// 对密码进行加盐后加密,加密后再通过Hibernate往数据库里存
        String changedPswd=DigestUtils.md5Hex(name+pswd);

就是这样简单,上面代码中盐就是用户名,可以的话还可以用用户注册时的邮件,注册时间等非空信息(如果是空信息这个加盐处理会失效)。

下面是数据库中两个用户的记录,他们的实际登录密码都是123456,但光看用户记录是完全看不出来的。这下别有用心的人打开数据库看到的密码都完全不一样,他以前的手段就失效了。


加盐就是这样简单,感谢您看到这里。




posted @ 2010-11-28 09:53 何杨 阅读(11764) | 评论 (6)编辑 收藏

以下文章属于老调重弹,您如果对MD5的使用已经熟悉请不要往下看以免浪费宝贵时间。

登录Web系统时通常都采用用户名和密码的形式,如果这样的数据以明码的方式放在数据库中的话无疑会给别有用心的人以可趁之机,所以采取一定的防范措施是必要的。

现在比较安全的方式是用MD5进行加密,利用Apache commons的DigestUtils工具类我们可以迅速做到这一点。
要得到Apache commons的DigestUtils工具类,你必须加载commons-codec-1.x.jar包,我使用的是commons-codec-1.3.jar。使用的具体类是:org.apache.commons.codec.digest.DigestUtils.

下面,我们的任务是,当用户注册时,将他注册的密码加密后存入数据库,下面请见具体代码:
 1 // 对密码进行加密,加密后再通过Hibernate往数据库里存
 2         String changedPswd=DigestUtils.md5Hex(pswd);
 3         
 4         User user=new User(name,changedPswd,email,brief);
 5         
 6         if(service.hasSameName(name)){
 7             // 同名检测
 8             request.setAttribute("msg""已经有和'"+name+"'同名的用户存在了,请换个名称注册.");
 9             return new ActionForward("/web/page/register.jsp");
10         }
11         
12         if(service.hasSameEmail(email)){
13             // 同Emial检测
14             request.setAttribute("msg""已经有和'"+email+"'相同的用户存在了,请换个Email注册.");
15             return new ActionForward("/web/page/register.jsp");
16         }
17         
18         try{
19             service.create(user);
20             saveUserRegisterInforToLog(user,request);
21             request.setAttribute("msg"""+name+",欢迎您的加盟.Ȼ������¼��ť");
22             return new ActionForward("/web/page/login.jsp");
23         }
24         catch(Exception ex){
25             String str="创建用户时遇到未预计的异常,具体的异常信息为'"+ex.getMessage()+"',请与系统维护人员联系.";
26             request.setAttribute("msg",str );
27             logger.fatal(str);
28             return new ActionForward("/web/page/register.jsp");
29         }

以上第二行代码是进行MD5加密的处理,如果用户输入的密码是123456789,则会得到25f9e794323b453885f5181f1b624d0b这样的字符串。

注册用户后,数据库中您将看到如下的对应记录,看到这样的文字,要去反猜原始密码是非常困难的,当然您有山东大学王小云教授的本事则不费吹灰之力。


下面,我们还要对登录时做一番处理,因为登录时用的是原始密码,我们应该对它进行加密后再和数据库中的对应字段进行比对,代码如下:
            User user=objs.get(0);
            
            
// 得到MD5加密后的密码
            String changedPswd=DigestUtils.md5Hex(password);
                
            
// 再与数据库中用户密码进行比对
            if(user.getPassword().equals(changedPswd)==false){
                
throw new ErrorPswdException("密码不匹配.");
            }
else{
                
return user;


            }

以上代码中,password是用户在页面输入的原始密码,changedPswd是经过MD5加密后的密码,user是按名称查询出来的用户,他的密码部分就是已经经过MD5加密的,我们拿这两个密码进行比对即可。

之所以没有反向还原是因为MD5加密和Base64不一样,前者是不可逆的,后者则可以还原。当然,Base64不是严格意义上的加密手段。

最后的问题,如果数据库中原有数据未经加密怎么办,好在MySql数据库提供了md5函数帮我们做到这一点,使用update projectmanager_user set pswd=md5(pswd) 这样的语句就可以将原来数据库中的密码部分用MD5加密了。

下面的图片演示了这一过程:

原始数据:


使用update projectmanager_user set pswd=md5(pswd)加密后的数据库记录:


到此啰嗦完了,感谢您看到这里。
posted @ 2010-11-27 13:56 何杨 阅读(7820) | 评论 (4)编辑 收藏

下载地址:http://www.box.net/shared/7a74mnbafa

使用Base64对登录密码进行了简单保护。

posted @ 2010-11-27 12:55 何杨 阅读(190) | 评论 (0)编辑 收藏

下载地址:http://www.box.net/shared/ah9sutbaut

修改项:
1.在登录页面增加了表过滤器,可以在载入时缩小范围。
2.修改了展示窗口的表现形式。
3.增加了一项右键菜单"得到表格形式的字段细节”。

posted @ 2010-11-26 22:47 何杨 阅读(141) | 评论 (0)编辑 收藏

现代计算机技术的基础之一就是现代互联技术,简而言之,现代互联技术就是计算机之间进行通讯的手段。

 

要让计算机之间进行通讯,需要物理上和机制上的两方面保障。物理保障指的是网络,它是由主机和路由器组成的互联网络;机制方面的保障指的是IP协议和基于其的TCP和UDP协议,它们可以统称为TCP/IP协议族。

 

IP协议用来保证一条信息从一个主机发送到另一个主机,因此信息中必定包含了目的主机的地址。需要说明的是,IP协议只是一个尽力而为的协议,它会试图分发每一个分组报文,但在网络传输过程中,会发生丢失报文,报文顺序打乱和重复发送报文的情况。

 

信息送到指定主机后,还需要送到具体的应用程序,这就需要用到TCP协议和UDP协议,这两个协议都建立在IP层所提供的服务上,它们使用了端口号 用来区别不同的应用程序。TCP能够检测并恢复IP层传送过程中丢失报文,报文顺序打乱和重复发送报文的错误,它提供了一个可信赖的字节流信道,这样应用 程序就不需要再处理上述的问题。而UDP并不尝试修正IP层传输的错误,他只是扩展了IP层的数据报服务,使它能在应用程序之间进行工作。

posted @ 2010-11-05 09:47 何杨 阅读(120) | 评论 (0)编辑 收藏

下载地址:http://www.box.net/shared/gcqt9r3jz7

内中有一个完整的Eclipse工程,其中sqltoolbox子目录是打包目录,build.xml生成的新jar会生成到其中的lib目录中。

大家把它导入Eclipse即可。

posted @ 2010-08-29 10:53 何杨 阅读(243) | 评论 (2)编辑 收藏

     摘要: SqlToolBox是我制作的一款纯绿色的免费数据库客户端软件,旨在于为开发人员,系统工程师和数据库管理员提供一种通用方便和快捷的数据库操作工具,使他们摆脱需要学习掌握使用多种数据库客户端的苦恼,并减轻他们日常操作数据库和编写Sql语句的任务量,帮助他们把精力投入到更有意义的事情上去。

下载地址:
http://www.box.net/shared/6hqixugmti
  阅读全文
posted @ 2010-08-16 06:54 何杨 阅读(263) | 评论 (1)编辑 收藏

常用JAR包与描述对照表 注:jar包尾后的版本号不代表当前最高版本
JAR包 描述
activation-1.1.jar Sun的JavaBeans Activation Framework(JAF),JavaMail要运行必须依赖于它的支持
antlr-2.7.2.jar Antlr是一个用于此法语法分析的类库,hibernate用它来解析Hql语句
cglib-nodep.jar CGLIB是一个强大的高质量高性能的代码生成库,在运行时可以用它来扩展Java类
commons-beanutils-1.7.0.jar Jarkarta Commons BeanUtils库,用于JavaBean的处理
commons-codec-1.3.jar  Commons项目中用来处理常用的编码方法的工具类包,例如DES、SHA1、MD5、Base64等等。
commons-digester-1.7.0.jar Jarkarta Commons Digester是一个用于解析XML并从中生成对象的库
commons-fileupload.jar Jarkarta Commons FileUpload是一个通过Http接收上传的文件并处理结果文件的库
commons-lang-2.1.jar Jarkarta Commons Lang是增强Java语言的实用工具函数库
commons-logging-1.0.4.jar Jarkarta Commons Logging是一个处于真正日志实现如log4j的抽象层
comons-validator-1.0.2.jar Jarkarta Commons Validator包是一个用于验证的包
freemaker.jar FreeMaker是一个模板引擎,一个基于模板生成文本输出的常用工具
jdom-1.0.jar 一个类似于dom4j的XML解析工具
jstl.jar 支持JSP标准标签库JSTL的核心包
mail.jar Java Mail API所用到的jar包
rome-0.7.jar rome是一个rss提要器,应用程序用它获取并处理RSS提要
spring-aop.jar Spring的AOP包,它是核心的Spring AOP接口,建立在AOP Alliance AOP协同工作接口上
spring-beans.jar Spring框架的Bean包,包含了处理JavaBean的接口和类
spring-context.jar Spring的context包,它建立在bean包基础上,添加了对信息源和观察者设计模式的支持
spring-core.jar Spring的核心类包.提供了异常处理和版本检测的基类,以及不针对框架任何部分的核心帮助类
spring-dao.jar Spring DAO包,异常的分层使得复杂的错误处理独立于所应用的数据访问方式
spring-jdbc.jar Spring JDBC包.这个包中的类令JDBC使用起来更加简单,并减少了常见错误发生的可能性
spring-mock.jar Spring mock对象包
spring-web.jar Spring web包,包括与各种Web相关的类
standard.jar JSTL提供的标准工具集
struts-1.3.8.jar Struts1框架用到的jar包
webwork.jar Webwork是Struts2的前身,一个成功的Web框架.这个jar包括大部分的Webwork功能
posted @ 2010-08-14 11:33 何杨 阅读(900) | 评论 (0)编辑 收藏

时间:2010年6月22-25日
地点:大连世界博览广场
注:我是23日下午到会的,可能错过了第一天的高峰和精彩内容,且我见到的是我愿意观察且能观察到的世界,带有个人性和片面性在所难免,望周知。

整体而言,展会规模较大大,大小厂商和各地区都来得不少,场地气派人气足。接待方面,个人填写个人资料后就能领取参观证进入,接待人员也是礼貌热情,不厌其烦,志愿者也在场内穿梭随时准备帮助人。我感觉展会组织者还是相当得力的,因为此会对国家,公司和个人都大有裨益。

先说我看到和听到的:
一.展示产品方面:   
产品方面以软硬结合为最受欢迎,纯软件产品受关注较少。软硬结合有监控设备,安保设备,物联网设备,平台展示设备和教学辅助设备等,人气很足,只要工作人员展示一下设备就能吸引不少目光,有些地方甚至开始了商务洽谈;而纯软件产品中群体软件等还能吸引一定的人气,迁移软件和工作协调软件则门可罗雀,其它常见的企业应用如ERP,MIS,CMS多见于纸面也乏人问津。
产品展示人员宣传产品时多以表现我们做得很好为主,没有听到仅此一家别无可寻的说法,这是值得引发IT从业者思考的。
    
二.参展厂商方面:
这次厂商参与的不少,有些舍得下本连礼仪人员都请了,但不管公司大小和名气,真正有人气关注的还是有“货”有“料”的展位。有些公司仅仅是为了企业形象而展示,别人去干什么呢?这些花大钱占好地方却门庭冷落的展位厂商可以深思了。另外一点是大而全不如小而精,服务外包型的人气明显不如专业型的。商务做派方面,大公司和小公司最好,中等公司最差。以地域论,南方公司商务做派明显强于北方公司,以深圳展商为例,只要有客户经过,即使完全没有购买欲望的人,也会热情为其介绍产品,真正做到知无不言言无不尽,临走还会硬塞各种宣传资料,决不放过任何潜在机会。而国内厂商的展示人员摆出一副资料随便拿别来烦我的姿态,让人望而却步;有些介绍人员像是新手,连自己公司产品有哪些同行业竞争优势都说不清楚,这些公司在敷衍观众同时也破坏了自己的形象。

三.人员方面
展方中基本上业务人员和技术人员素质都不错,业务人员知无不言言无不尽,虽有一些逐利的商业气味也是常情;技术人员则谦虚有理,不因为自己产品有较高技术难度而趾高气扬,相反大家的共识是没有做不出来,只有做得够不够好,这也是值得开发者和项目管理者思考的。观众这边,以IT从业者为主,还有一些想要购买产品的人员和和寻求合作的老板。

个人拍摄整理的图片请见:软交会拍摄整理的图片

个人的感觉和浅见:

1.监控安保物联网是未来的一大发展方向。这方面有三家大公司(英特尔,东芝和电信)和四五家小公司都推出了自己的产品,交通热点,闹市,学校,仓库,家庭和重要设备区域是这些产品的主要的应用领域,产品从低端到高端,简单到复杂都有。我不同意中国人力资源便宜安保设施前景不广的说法,人有许多的缺点,未来的人力成本也未必便宜,大量的安保设施加少量的人必然是未来的一个大趋势,现在在这个领域及时跟进还来得及,等人家都积累完开始瓜分市场了就迟了。

2.精优于博。信息技术发展到惊天,技术已经不是问题,点子大家基本都已经尝试过了,现在不是能不能做而是能否做好的时代,对企业和个人而言,什么都做应该是过去式了,如果不能提升到精的层次离淡出也不远了。

3.产品市场要因地制宜。有些产品,一眼就知道它在国内无法生存,但其在法律法规相对完善,群众愿意为服务付钱的韩日美却左右逢源;一些产品,可能在外国属于侵犯隐私的,在国内却如鱼得水。应该说产品无所谓好坏优劣,找对路子才是关键,仅以技术难度去定产品好坏则更是愚蠢。

4.“技术含量”四个字的精髓在于化平凡为神奇的能力。看遍产品才真正懂得,技术含量不是指高难艰深和新奇,而是这种化平凡为神奇的能力(请允许我再次重复)。摄像头,硬盘机录像机,话筒,微机,平凡普通,连便利店都买得起用得起的东西,变成了可记录,可监控,可统计,能报警,能取证,能手机操纵的安保系统,这组合的能力就是技术含量。程序员应该把专注于把n平方减少到logN的时间分出部分注意这方面能力的培养,也许下一个一飞冲天的就是你。

5.软件应该多与硬件结合起来。软件是信息系统的核心,但按现在而言软件技术难度构不成真正的障碍,开发人员普遍的共识是软件只要肯花时间都能做出来,硬件对于硬件研究人员也差不多,但进入对方领域双方都感觉棘手。如果一个公司能把这两方面统合好,立即能领先同侪一大截,这就不是那些靠压低人力成本才获取微弱的竞争优势可以比拟的了。这换到一个人身上也是同样的道理。

结语:
纯硬件的时代早已过去,纯软件的时代即将消逝,软硬结合的时代已经到来,这是IT界的大势,从业公司和人员应该顺势而为才能获取最大收益,逆势而为无异于螳臂挡车。我的这个个人断言大家可以留待下次展会来实地验证。
posted @ 2010-06-27 14:06 何杨 阅读(1599) | 评论 (2)编辑 收藏

     摘要: 编程中有时需要将一段文本分解成标记,比如说14+2*3需要变成14,+,2,*,3的样式,再比如说select a from b,需要变成select,a,from,b的形式,要写出这样的代码不难,考虑到通用性,于是我制作了下面这个通用类,用户只需要指定合法字符和分隔字符的正则表达式,程序即能将字符串分解成标记并注明类型,下面是源码: 1.用于表示标记的Token类,含有文本和类型两个属性:...  阅读全文
posted @ 2010-06-27 09:34 何杨 阅读(1403) | 评论 (1)编辑 收藏

     摘要: 一种有趣的扑克牌游戏--算24 众多的扑克牌游戏中,算24是一种不错的锻炼反应力和计算能力的智力游戏,游戏规则大致是这样:从去掉大小王的一副扑克中任意抽取四张,读取上面的数字(其中A算1,2-10就是2-10,J算11,Q算12,K算13),然后进行加减乘除四则运算,早算出24的结果者为赢家,要求是四个数字必须且只能参与计算一次。 举例来说:得到Q,J,2,A四张牌,对应了12,11,2,...  阅读全文
posted @ 2010-06-23 18:21 何杨 阅读(2722) | 评论 (6)编辑 收藏

     摘要: 原题如下:用1、2、2、3、4、5这六个数字,用java写一个程序,打印出所有不同的排列,如:512234、412345等,要求:"4"不能在第三位,"3"与"5"不能相连。 一.全排列解法: Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.co...  阅读全文
posted @ 2010-06-22 02:20 何杨 阅读(2151) | 评论 (2)编辑 收藏

     摘要: 对一个成规模的系统来说,缓存总是不可或缺的一个环节,甚至会成为系统成功的重要因素。 从原理来讲,缓存并不神秘,它本质上只是一个哈希表,内部包含许多提取关键字和缓存内容的键值对,当有读操作(如search)新的查询到来时,系统先到 这个哈希表中看看是否有同样的关键字存在,是则取出对应的值返回,否则进行查询,并把新的查询条件和结果存储进哈希表,以便下次提取;当有写操作(如 add,delet...  阅读全文
posted @ 2010-05-24 15:10 何杨 阅读(632) | 评论 (0)编辑 收藏

在交易系统的客户端中,涉及的业务种类有很多,如分类,商品,询价,协商等大类及其下的CRUD四个小类,每种操作几乎都需要一个界面供用户操作,这些界面及其内部处理如果安排不当会造成维护上的巨大麻烦,而且随着程序的发展,界面表现,用户交互和数据处理都会而变得越来越复杂,如果不在一开始就对它们进行分开处理,最后只能导致不可维护的结果,届时悔之晚矣。只有迈出了这坚实稳固的一步,后面的成功才有可靠的保证。因此我采用了MVC2模式来将每个操作界面的界面表现,用户交互和数据处理三部分分离,目的是为了提高系统的可维护性和可扩展性。下面是对交易系统采用的MVC2模式的简要介绍,以便于负责业务的程序员掌握之。

一.MVC2模式的来源
   这种模式首见于网络程序,起初因为Model无法通知到Web程序的界面而发明.这种模式采用Controller做中介者,一方面取得View的输入,然后交由Model层处理,之后再把返回的数据传递到View。在Web程序(典型例子如Struts1)中各层任务如下:View接受用户输入,并在并传递到Controller;Controller统一进行处理命令,交由Model处理具体的业务;进过处理Model更新后,Controller会选一个View并把Model内容传递(request,session)给它,然后View进行显示.

二.MVC2的优缺点
   MVC2相对MVC1优势很明显,首先Model和View无需继承别的类,其次Model和View无需了解对方的存在,只需准备相应的接口而已,最主要的是,是进行了数据部分,视图部分和控制部分三层的区分,程序的耦合度将大为降低,而可读性和可修改性将随之提高;缺点对于规模较小的程序或是组件,MVC2稍显费事,有些过度设计的嫌疑。

三.在客户端程序中MVC各层担负的职责

视图View:它担任数据的显示并接受用户的输入,其中不包括业务逻辑,但可以包含显示逻辑。

数据中心Model:它保存数据层和控制层所需要的数据并提供操作这些数据的方法。

控制器Ctrl:它是一个中介者,负责实例化视图和数据中心,由此View和Model并不需要知道对方的存在。View的事件在Ctrl中注册,这样当事件发生时Ctrl能调用Model取得相应的数据并显示在View中。Ctrl中包含处理逻辑。

下面的UML图形可以参考:
MVC2静态类图


MVC2顺序图


下面是最简化的MVC三层次代码示例:
控制类
public class Mvc2Ctrl {
    
private Mvc2View view;
    
private Mvc2Model model;
    
public Mvc2Ctrl() {
        view 
= new Mvc2View();
        model 
= new Mvc2Model();
        handleEvents();
    }
    
// 处理事件响应
    private void handleEvents() {
        addCloseLintener();
        addButtonListener();
        addButtonListener2();
    }
    
// 窗体关闭事件相应
    private void addCloseLintener() {
        view.addWindowListener(
new WindowAdapter() {
            
public void windowClosing(WindowEvent e) {
                System.out.println(
"Exit MVC2");
                System.exit(
0);
            }
        });
    }
    
private void addButtonListener() {
        view.getButton().addActionListener(
new ActionListener() {
            
public void actionPerformed(ActionEvent e) {
                view.getLabel().setText(model.getText());
            }
        });
    }
    
    
private void addButtonListener2() {
        view.getButton2().addActionListener(
new ActionListener() {
            
public void actionPerformed(ActionEvent e) {
                view.getLabel2().setText(model.getText2());
            }
        });
    }
}

视图类
public class Mvc2View extends JFrame {
    
private static final long serialVersionUID = 621145935910133202L;
    
private JButton button;
    
private JLabel label;
    
private JButton button2;
    
private JLabel label2;
    
public Mvc2View() {
        locateView(
300200);
        
this.setTitle("MVC2 Program");
        setupComponents();
        
this.setVisible(true);
    }
    
// 定位程序在屏幕正中并设置程序大小
    private void locateView(int width, int height) {
        Dimension screenSize 
= Toolkit.getDefaultToolkit().getScreenSize();
        
this.setSize(width, height);
        
this.setLocation(screenSize.width / 2 - width / 2, screenSize.height
                
/ 2 - height / 2);
    }
    
// 初始化内部组件
    private void setupComponents() {
        button 
= new JButton("点击响应事件1");
        label 
= new JLabel("  等待事件响应1");
        button2 
= new JButton("点击响应事件2");
        label2 
= new JLabel("  等待事件响应2");
        setLayout(
new GridLayout(22));
        add(button);
        add(label);
        add(button2);
        add(label2);
    }
    
public JButton getButton() {
        
return button;
    }
    
public JButton getButton2() {
        
return button2;
    }
    
public JLabel getLabel() {
        
return label;
    }
    
public JLabel getLabel2() {
        
return label2;
    }
}
模块类
public class Mvc2Model{
    
public String getText(){
        
return "  事件1响应完毕";
    }
    
    
public String getText2(){
        
return "  事件2响应完毕";
    }
}

小结:
一.越是大型程序,MVC越有必要;倒是小型程序不一定硬要遵守MVC。
二.以上代码抽象程度还不够,理论上说,应该阻止程序员在界面中写监听代码。
三.三部分应该实现相应的接口,这里是应该继续进化的地方。

posted @ 2010-05-23 13:56 何杨 阅读(292) | 评论 (0)编辑 收藏

在交易系统的C/S体系中,C只负责数据的输入和显示,相当于MVC中的View部分,S负责数据的操作和持久化,两者是通过WebService进行联系的,具体来说联系的方式是这样:C端将指定S端负责处理的Service类名,具体负责处理的函数名和函数的参数打包成一个XML传送到S端,S端解析后通过反射找到具体的函数进行处理,处理的结果会转化成XML形式的字符串传回。这就是设计梗概一中提到的内容。

如果这个过程交给负责具体业务的程序员自行完成的话,那无疑会给系统带来许多混乱和无序,程序员也无法将主要精力集中在业务上;另外,他们也无需了解每个细节是怎么完成的,他们真正需要的是框架提供好的接口,知道怎么调用取得结果就可以了。他们希望最好能像调用普通函数一样调用S中的方法并取得想要的结果,举例来说,如果客户端需要查询姓名以H开头的所有雇员,他们只需调用一个search函数就能得到查询出来的雇员集合,中间发生的组装请求XML,WebService调用,业务处理,从数据库查询数据,将数据转为XML传回和在客户端解析传回的XML再变成领域对象集合等都应该由框架来完成。这并不过分,而是很合理的需求,就像RMI曾经就是这样做的。

那么,客户端与服务器端的交互会有几种形式呢,从业务上来说无外乎下面五种形式:
1.调用S端的一个函数,只想知道这个函数是否正确运行了。典型例子如对象的删除操作。
2.调用S端的一个函数,想得到函数执行后返回的一个对象。典型例子如对象的添加操作,用户需要取回添加好的对象的ID。
3.调用S端的一个函数,想得到返回对象的集合列表。典型例子如对象的查询。
4.调用S端的一个函数,想得到分页后的某一页对象集合。典型例子如分页查询。
5.调用S端的一个函数,只想得到一个字符串。典型例子如改变一种商品的目录,得到某种商品的介绍文字等。
框架需要做的,就是把这五种形式做成通用的函数提供给负责业务的程序员,让他们仅需要这五个函数就能完成与WebService服务器的交互。这五种形式以第二种最为典型,也最为基础,完成了它其它的就可以依样画葫芦,下面请看具体过程:

首先,规定具体函数的形制为
public static BaseDomainObj fetchObject(String url,String serviceName,String mothodName,String[] args,Class<?> cls);
公有静态自不必说,BaseDomainObj是客户端领域对象的基类,fetchObject是函数名,接下来是四个参数,前三个分别是WebService所在URL,服务器上服务类注册在Spring上下文中的beanName,服务类具体的方法名,最后一个是取得对象的类型,在函数体中,会根据类型用反射生成一个实例,再通过实例的FromXML方法给实例的属性赋值,完成后就得到了负责业务的程序员想要的结果。

其次,fetchObject内部需要做的事情有:
1.将serviceName,mothodName,args三项组合成一段XML文本。此项工作由WSRequest类完成。
2.向位于url上的WebService服务器端发起请求,获得返回的文本。此项工作由WSInvoker类来完成。
3.将返回的文本转化出来,这一步是要检测服务器端函数执行是否顺畅,有无抛出异常等。因为服务器端如果发生异常是无法通过WebService传回的,只能变成文本后回传,那么客户端就需要解析一次,有问题就报出来,没问题再往下走。这一步是坚决不能忽视的。
4.通过反射得到对象,此时对象的属性还是原始状态,需要再通过反射注入相应的值,最后,客户端需要的对象就产生了。

具体的过程请参考下面的代码:
/**
 * 调用远程WebService端,将返回的XML转化为一个对象,最终返回.这种调用的典型例子是getById,add等
 * 
@param url WebService所在URL
 * 
@param serviceName 服务名,此名在appCtx.xml中定义
 * 
@param mothodName 方法名
 * 
@param args 方法的参数
 * 
@param cls 要返回的对象类型
 * 
@return
 
*/
public static BaseDomainObj fetchObject(String url,String serviceName,String mothodName,String[] args,Class<?> cls){
    
// 得到客户端请求XML文本
    WSRequest request=new WSRequest(serviceName,mothodName,args);
    String requestXML
=request.toXML();
    logger.info(
"准备向位于'"+url+"'发送的请求XML为'"+requestXML+"'.");
    
    
try{
        
// 调用远端WebService上的方法,得到返回的XML文本
        WSInvoker invoker=new WSInvoker(url);
        String responseXML
=invoker.getResponseXML(requestXML);
        logger.info(
"得到位于'"+url+"'响应XML为'"+responseXML+"'.");
        
        
// 转化响应
        WSResponse response=new WSResponse(responseXML);
        logger.info(response);
        
        
// 如果在调用过程中如通不过检测而被中断的话
        if(response.isBreaked()){
            String errTxt
="远程方法被中断,具体原因是"+response.getRemark();
            logger.error(errTxt);
            
throw new WSBreakException(errTxt+".(WSE05)");
        }
        
        
// 如果在调用过程中出现异常的话
        if(response.hasException()){
            String errTxt
="调用远程方法返回了异常,具体信息是"+response.getRemark();
            logger.error(errTxt);
            
throw new WSException(errTxt+".(WSE04)");
        }
        
        
try{
            
// 通过反射得到对象
            BaseDomainObj obj= (BaseDomainObj)cls.newInstance();
            
            
// 通过反射得到方法
            Method method = cls.getMethod("fromXML"new Class[] {String.class});
            
            
// 通过反射调用对象的方法
            method.invoke(obj, new Object[] {response.getMethodResonseXML()});
            
            
return obj;
        }
        
catch(Exception ex){
            String errTxt
="无法将"+response.getMethodResonseXML()+"转化为"+cls.getName()+"对象.(WSE06)";
            logger.error(errTxt);
            
throw new WSException(errTxt);
        }
    }
    
catch(MalformedURLException e){
        String errTxt
="无法调用'"+url+"'上的服务,因为它是畸形的.(WSE01)";
        logger.error(errTxt);    
        
throw new WSException(errTxt);
    }
    
catch(XFireRuntimeException e){
        String errTxt
="无法调用'"+url+"'上的服务.(WSE02)";
        logger.error(errTxt);    
        
throw new WSException(errTxt);
    }
    
catch(DocumentException e){
        String errTxt
="无法解析从服务器端'"+url+"'返回的XML文本.(WSE03)";
        logger.error(errTxt);    
        
throw new WSException(errTxt);
    }
}


我们再看看通过关键的注入属性值的fromXML函数做了些什么:
public void fromXML(String xml) throws DocumentException{
    Document doc
=DocumentHelper.parseText(xml);        
    
    Element root
=doc.getRootElement();        
    List
<Element> elms=root.elements();
    
    
for(Element elm:elms){
        
try {
            
// 借助于BeanUtils,给对象的属性赋值
            BeanUtils.setProperty(this,elm.getName(),elm.getText());
        } 
catch (IllegalAccessException e) {
            e.printStackTrace();
        } 
catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}


最后,我们可以看看负责业务的程序员需要书写的代码示例:
public Tmp add(String name,String age,String salary,String picture){
    String url
=CommonUtil.WebService_Url;
    String serviceName
="TmpService";
    String methodName
="add";
    String[] args
=new String[]{name,age,salary,picture};
    
    
try{
        
return (Tmp)WSUtil.fetchObject(url, serviceName, methodName, args, Tmp.class);
    }
    
catch(WSBreakException ex){
        DlgUtil.popupWarningDialog(ex.getMessage());
    }
    
catch(WSException ex){
        DlgUtil.popupErrorDialog(ex.getMessage());
    }
    
    
return null;
}


小结:
一.负责业务程序员不需要了解的细节,框架应该将它们隐藏起来。
二.负责业务程序员需要了解的接口,框架应该使它们尽量简单。
三.框架能做到的,就不该再让负责业务的程序员再重复的发明车轮。
posted @ 2010-05-21 00:18 何杨 阅读(195) | 评论 (0)编辑 收藏

下载地址
http://www.box.net/shared/o48fxqem61

SqlToolBox是一款纯绿色的免费数据库客户端软件,基于Java Swing编制而成,旨在于为开发人员,系统工程师和数据库管理员提供一种通用方便和快捷的数据库操作工具,使他们摆脱需要学习掌握使用多种数据库客户端 的苦恼,并减轻他们日常操作数据库和编写Sql语句的任务量,帮助他们把精力投入到解决更有意义的问题上去。

SqlToolBox现有功能

  1. 能连接到MySql,Oracle和Ms Sql Server三种数据库。
  2. 连接到数据库后,会提供数据库Schema和表的树视图以便用户进行浏览和查找,另外还提供了一个过滤器帮助用户缩小查找范围。
  3. 用户能自动快速获取单表的创建,查询,更新,删除,建表语句,整表全部数据插入语句,单表对应Pojo类和单表的Hibernate映射文件等常用文字,且可借此构造更复杂的Sql语句。
  4. 能执行Sql语句并显示执行结果,如果是查询语句会以表格形式显示结果,还提供CSV形式数据下载;如果是非查询语句或是错误的查询语句则会以文字形式告知用户。
  5. 在用户输入Sql语句的过程中提供Sql语法高亮功能,以助于Sql语句的识别。
  6. 提供Sql格式化功能以助于Sql语句的识别和整理。
  7. 提供Redo/Undo,Shift整体退格进格,大小写转化,将Sql语句用StringBuilder包容以及将Sql语句中关键字大写表示等常用文字编辑功能。这些都能帮助程序员在程序中书写Sql语句。
  8. 能保存和记忆数据库信息,以便下次打开。

运行SqlToolBox有何前提条件?

将SqlToolBox运行起来的唯一前提是安装JDK6或以上版本。

SqlToolBox需要安装吗?

SqlToolBox是一款纯绿色软件,它对您的系统不做出任何更改,因此不需要安装和卸载。

SqlToolBox安全吗?

由于软件使用Java编写而成,它本身就具有较高的安全性。此外作者保证在SqlToolBox整个系列中都不会加入病毒,木马,插件等坏东西。

如何运行SqlToolBox?

解开下载包,然后双击run.bat即可。

在Unix/Linux下如何运行SqlToolBox?

除了也需要安装JDK外,您还需要参照run.bat写一份脚本,然后执行它。

如何使用SqlToolBox打开一个数据库?

程序运行起来后,您将看到一个输入数据库信息的对话框,请依次填入数据库所在机器的IP地址,数据库的库名称,选择数据库的类型以及输入登录数据库的用户 名和密码等必要信息。此后再点击“连接数据库”按钮,程序将打开数据库。如果您将以上信息填错也不要紧,程序会提示哪里出现了问题。此外您可以在登录前点 击“测试连接”按钮,程序也会告诉您是否能连接到指定的数据库。

打开数据库后程序左边部分如何使用?

成功连接到数据库以后,数据库的Schema和table结构会在画面的左边以树的形式展现出来,如果展现的内容过多,您还可以在上方的“过滤器”输入栏 中输入关键字以缩小展现范围。在这颗树中,表格(table)是以小圆点的方式展现的,左键点击这个圆点,程序将在右侧打开一个Sql语句操作窗口,并执 行“select * from table”语句,最后在下方以表格的形式展现给您;如果您用右键点击这个圆点,程序将弹出一个右键菜单,选择其中的项目您将可以在右边的Sql语句操作 窗口中得到单表的字段信息,创建(insert),查询(select),更新(update),删除语句(delete)及建表语句(create table),单表对应Pojo文件,单表的Hibernate映射文件等文字。

打开数据库后程序右边部分是如何使用的?

用左右键点击表格后,您将在右侧看到一个“Sql语句操作窗口”,它分成三部分:工具栏菜单,输入窗口和输出窗口。输入窗口是用以输入,编辑和整理Sql 语句的;工具栏菜单中的一大排按钮都是为编辑处理输入窗口中的文字而准备的;输出窗口则是展示Sql语句执行后的结果的,如果是查询语句,它会以表格的形 式告知您查询的结果,如果是其它语句,它会以文字的形式告知。通常的操作手法是,先在输入窗口中用鼠标选中您要操作的文本,再在工具栏菜单中点击执行特定 操作的按钮,然后在下方的输出窗口中就能看到具体的结果,当然如果仅是文本编辑操作的话输出窗口是不会有反应的。

如何执行Sql语句?

程序员和数据库管理员总是习惯使用语句来操作数据库,这也是本软件的最重要功能之一。执行Sql语句的过程具体来说是这样做的,首先,在输入窗口输入您向 执行的Sql语句,如“select * from table”之类,当然您更可以通过表格的右键菜单来获得常用的sql语句(在输入或是粘贴文本的过程中,Sql语句中的关键字会以蓝色显示,这是语法高 亮功能所致);其次,你需要选中你想执行的文本,再点击工具栏菜单中的向右三角形按钮,这段文本将得到执行,执行结果将在下方的输出窗口得到展示。如果您 执行的是查询语句,输出窗口将以表格的形式列出查询结果集的字段和内容;如果您执行的是删除,更新,添加,修改表等语句或是执行错误的Sql文本,输出窗 口将以文本形式告知执行结果。另外工具栏菜单中的双向右三角形按钮用于批量执行Sql语句,它以分号“;”来作为每段Sql的分隔标志,然后分别执行每 段。

如何快速调整对执行查询语句后得到的表格列宽度?

如果您想自动调整某列的宽度,可以双击这列的表头,此后这列的宽度会根据这列的最长文字进行调整;您还可以在表格上点击右键,选择“调整列宽为最适合状态”一项,那么所有的列宽都会进行调整。

如何得到执行查询语句后得到的表格的内容?

您还可以在表格上点击右键,选择“下载表格为CSV文件”一项,此后查询语句和得到的结果都会被放入一个CSV文件中。CSV是一中文本文件,但您可以用Excel打开它,也会得到xls文件一样的效果。

在新增或是删除一张表后,在左边的树中为什么没有相应的变化?

新增或是删除一张表后,您需要手动执行一下左上方的更新按钮(最上方的大图标中第一个),此后程序会重新载入数据库的Schema和table,这样您刚才对表格进行增删操作就能体现出来。

如果我需要常打开数据库进行操作或是需要常操作多个数据库,程序能为我提供那些便利?

本软件有记忆功能,如果您正确连接到一个数据库,那么相应的信息如IP地址,数据库名,数据库类型,连接数据库的用户名和密码都会被记忆下来,这样下次打 开时就不用重复输入了。如果您需要常操作多个数据库,您可以通过保存按钮(最上方五个大图标中的第二个)将数据库信息保存成XML文件,这样在登录画面中 就可以通过“打开文件按钮”得到相应的数据库信息。

程序截图:












posted @ 2010-05-20 00:02 何杨 阅读(384) | 评论 (2)编辑 收藏

此项目是一个采购商和供货商之间的交易软件,双方可以在系统中发布供求信息,应答供求信息,与对方谈判敲定供求细节如品种,数量,交货地点,交货批次等,此外还有产品展示,信用记录等交易系统常用功能。

此系统难点在于大量即时信息的送达和交互信息的多样化,框架中采用了JMS和WebService两种手段来保证这两项的成功,并拟采用IM服务器来取代JMS。在层次上采用了WebService来屏蔽后台数据库,并用XML来传递前后台信息。由于采用了使用Java反射技术的控制中心方案和基于AOP的缓存方案,有效降低了系统的开发难度,使得系统的可扩展性和可维护性得到了较大提高。

项目使用的技术:
前台技术:Swing,XML,WebService,JMS。
后台技术:JMS,WebService,Spring,Hibernate等。

posted @ 2010-05-19 14:50 何杨 阅读(136) | 评论 (0)编辑 收藏

     摘要: 我在前一向做交易系统时的设计梗概之一,欢迎拍砖。  阅读全文
posted @ 2010-05-19 14:22 何杨 阅读(1900) | 评论 (0)编辑 收藏

     摘要: 如果有效利用XML和反射等手段,我们可以做到工具栏菜单项的可配置化。具体来说就是,将菜单项的文字,图片和点击后的响应函数都在XML配置文件中配置好,程序启动时去读取文件生成菜单,点击菜单项后会动态的找到具体需要处理的函数。这样做以后,修改一个按钮对应的功能定位代码,或是增删一个按钮及其功能就很容易了。  阅读全文
posted @ 2010-05-18 22:04 何杨 阅读(2371) | 评论 (7)编辑 收藏

XML文件如下:
<?xml version="1.0" encoding="GBK"?>

<menuItems>
    
<name>根节点</name>
    
<icon></icon>
    
<panelName></panelName>
    
<mothodName></mothodName>
    
<args></args>

    
<menuItem>
        
<name>节点一</name>
        
<icon>folder_fromFile.gif</icon>
        
<panelName>
            com.heyang.view.panel.content.folder.addfromfile.AddCategoryFromFilePanel
        
</panelName>
        
<mothodName></mothodName>
        
<args></args>
    
</menuItem>
    
<menuItem>
        
<name>节点二</name>
        
<icon>folder_attribute.gif</icon>
        
<panelName>
            com.heyang.view.panel.content.folder.attribute.AttributeMngPanel
        
</panelName>
        
<mothodName></mothodName>
        
<args></args>
    
</menuItem>
    
<menuItem>
        
<name>节点三</name>
        
<icon>folder_transfer.gif</icon>
        
<panelName>
            com.heyang.view.panel.content.folder.transfer.FolderTransferPanel
        
</panelName>
        
<mothodName></mothodName>
        
<args></args>
    
</menuItem>
</menuItems>

读取例程:
 /**
     * 按照XML文件建立一棵树
     * 
     * 
@author:何杨
     * @date:2009-12-22
     * @time:上午08:13:09
     
*/
    @SuppressWarnings(
"unchecked")
    
private void buildTree(){
        
// 建立树节点
        DefaultMutableTreeNode root = null;
                
        
try {
            SAXReader reader 
= new SAXReader();
            String xmlFile 
= TreeMenuPanel.class.getResource("/text.xml").getPath()
                    .toString();
            
            File file
=new File(xmlFile);
            
if(file.exists()==false){
                DlgUtil.popupErrorDialog(
"无法找到文件"+xmlFile+".");
                
return;
            }
            
            Document document 
= reader.read(file);
            Element rootElm 
= document.getRootElement();
            
// 遍历XML生成节点树
            root=getNode(rootElm);
        } 
catch (Exception ex) {
            ex.printStackTrace();
        }
        
        
// 将节点树赋予树组件
        DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
        model.setRoot(root);
        model.reload();    
        tree.updateUI();
    }
    
    
/**
     * 递归取得节点
     * 
     * 
@author:何杨
     * @date:2010-1-11
     * @time:上午08:31:12
     * 
@param elm
     * 
@return
     
*/
    @SuppressWarnings(
"unchecked")
    
private DefaultMutableTreeNode getNode(Element elm){        
        String name
=elm.elementText("name");
        String icon
=elm.elementText("icon");
        String panelName
=elm.elementText("panelName");
        String mothodName
=elm.elementText("mothodName");
        String args
=elm.elementText("args");
        
        MenuItem menuItem
=new MenuItem(name,icon,panelName,mothodName,args);
        DefaultMutableTreeNode leaf 
= new DefaultMutableTreeNode();
        leaf.setUserObject(menuItem);
        
        List
<Element> elms = elm.elements("menuItem");
        
for (Element element : elms) {
            leaf.add(getNode(element));
        }    
        
        
return leaf;
    }


posted @ 2010-01-14 21:56 何杨| 编辑 收藏

1.1 创建树组件
1.1.1 最简方式

    JTree tree = new JTree();

    在显示时,树组件会带上JTree默认的节点。

1.1.2 指定树的节点后创建树:   

    DefaultMutableTreeNode root = new DefaultMutableTreeNode("根节点");
    root.add(
new DefaultMutableTreeNode("子节点"));    
    JTree tree 
= new JTree(root);


1.1.3 将树加入到面板中
    以下是将树加上滚动窗格后加入一个面板的示例程序。    

   JPanel panel=new JPanel();
   panel.setLayout(
new GridLayout(1,1));
   panel.add(
new JScrollPane(tree));

   
1.2 树节点相关
1.2.1 取得树的根节点

    DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
    DefaultMutableTreeNode root 
=(DefaultMutableTreeNode)model.getRoot();

1.2.2 更新树的根节点

    DefaultMutableTreeNode newRoot=;
    DefaultTreeModel model 
= (DefaultTreeModel) tree.getModel();
    model.setRoot(newRoot);
    model.reload();  
    tree.updateUI();


1.2.3 从一个节点开始递归遍历其下的所有节点

private String getNodeText(DefaultMutableTreeNode node){
   Category category
=(Category)node.getUserObject();
   StringBuilder sb
=new StringBuilder(category.getText());
  
  
if (node.getChildCount() >= 0) {
            
for (Enumeration<?> e=node.children(); e.hasMoreElements(); ) {
             DefaultMutableTreeNode childNode 
= (DefaultMutableTreeNode)e.nextElement();
                sb.append(getNodeText(childNode));
            }
        }
  
  
return sb.toString();
}


1.2.4 在某节点下创建一个节点

    DefaultMutableTreeNode childNode = new DefaultMutableTreeNode();
    childNode.setUserObject();
    parentNode.add(childNode);

1.2.5 节点改名  

    Category selectedCategory=(Category)clickedNode.getUserObject();
    selectedCategory.setName(
"");
    clickedNode.setUserObject(selectedCategory);

 

1.2.6 删除节点   

    DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
    model.removeNodeFromParent(clickedNode);

    注意被删除的节点必须有父节点,若要删除根节点直接用null去替代原有根节点即可,

1.2.7 遍历用户选择的树节点   

    TreePath[] paths = tree.getSelectionPaths();
   
    
for(TreePath selPath:paths){
        Object[] nodes 
= selPath.getPath();
  
        DefaultMutableTreeNode node 
= (DefaultMutableTreeNode) nodes[nodes.length - 1];  
        
// 对node进行处理
    }

 

1.3 树的事件处理
1.3.1 左键点击事件处理
   

   tree.addMouseListener(new MouseAdapter() {
      
public void mousePressed(MouseEvent e) {
        
int selRow = tree.getRowForLocation(e.getX(), e.getY());// 返回节点所在的行,-1表示鼠标定位不在显示的单元边界内
        TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());// 返回指定节点的树路径
   
        
boolean condition = true;
        condition 
= condition && (selRow != -1);// 如果选中
        
//condition = condition && (e.getButton() == 1);// 左键 e.getButton() == 1  右键  e.getButton() == 3
        condition = condition && (e.getClickCount() == 1);// 单击
       
   
        
// 如果是左键点击
        if (condition == true && (e.getButton() == 1)) {
          Object[] nodes 
= selPath.getPath();
         
          DefaultMutableTreeNode node 
= (DefaultMutableTreeNode) nodes[nodes.length - 1];
          Category selectedCategory
=(Category)node.getUserObject();
   
        }
      }
    });

 

1.3.2 在树节点上点击右键弹出右键菜单 

   tree.addMouseListener(new MouseAdapter() {
      
public void mousePressed(MouseEvent e) {
        
int selRow = tree.getRowForLocation(e.getX(), e.getY());// 返回节点所在的行,-1表示鼠标定位不在显示的单元边界内
        TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());// 返回指定节点的树路径

        
boolean condition = true;
        condition 
= condition && (selRow != -1);// 如果选中
        condition = condition && (e.getClickCount() == 1);// 单击
       
        
// 如果是右键点击
        if(condition == true && (e.getButton() == 3)){
         
          Object[] nodes 
= selPath.getPath();
          DefaultMutableTreeNode rightClickedNode 
= (DefaultMutableTreeNode) nodes[nodes.length - 1];
          
          popupMenu.show(e.getComponent(), e.getX(), e.getY());
        }
      }
    });

 

1.4 树的渲染
1.4.1 树节点渲染器示例
 

  public class CategoryNodeRenderer extends DefaultTreeCellRenderer{
    
private static final long serialVersionUID = 8532405600839140757L;
   
    
private static final ImageIcon categoryLeafIcon = new ImageIcon(CategoryNodeRenderer.class.getResource("/categoryLeaf.gif"));
    
private static final ImageIcon openFolderIcon = new ImageIcon(CategoryNodeRenderer.class.getResource("/openFolder.gif"));
    
private static final ImageIcon closedFolderIcon = new ImageIcon(CategoryNodeRenderer.class.getResource("/closedFolder.gif"));
   
    
public Component getTreeCellRendererComponent(JTree tree,
                                              Object value,
                                              
boolean sel,
                                              
boolean expanded,
                                              
boolean leaf,
                                              
int row,
                                              
boolean hasFocus){
     
      
super.getTreeCellRendererComponent(tree,  
                  value,
                  sel,  
                  expanded,  
                  leaf,  
                  row,  
                  hasFocus);  
     
      
if(leaf){
        setIcon(categoryLeafIcon);
      }
      
else if(expanded){
        setIcon(openFolderIcon);
      }
      
else{
        setIcon(closedFolderIcon);
      }
         
      
return this;   
    }
  }

 

1.4.2 用树节点渲染器渲染一棵树 

  DefaultMutableTreeNode root = null;
  JTree tree 
= new JTree(root);
  tree.setCellRenderer(
new CategoryNodeRenderer());

 

posted @ 2010-01-14 15:13 何杨| 编辑 收藏

当不需要全体字段或是不必要的字段属性映射匹配影响效率时,我们可以使用在HQL语句中直接返回一个Java对象,如下:
select new com.heyang.domain.Folder(id,pid,name) from Category c

需要注意的是:
1.Folder类应该写全路径名,如上面的com.heyang.domain.Folder,否则Hibernate会说Unable to locate class ‘Folder’。

2.Folder类应该具有一个和参数相匹配的构造函数,如果上面的id,pid,name三个字段的类型分别是long,long,vchar,那么Folder类的构造函数应该是Folder(Long op1,Long op2,String op3);的形式。

就是这样,很简单,简单到Hibernate帮助手册都对之语焉不详,写出来注意一下就好了。
posted @ 2010-01-09 09:01 何杨| 编辑 收藏

任务:数据库中有六千余条目录(id,pid,name)数据组成一棵目录树,需要通过WebService服务提供给客户端显示出来(Swing中的JTree)。

实现功能的第一步:在客户端的树显示时通过网络得到顶层目录,再根据用户的点击逐级展开下级目录。此方案优点:实现简单;缺点:点击多次容易使人厌烦,速度不行。

客户端实现改善的第二步:启动一个线程从服务器加载数据逐渐生成一个节点树,再交给界面上的JTree命其更新。此举对操作友好型有改进,速度上也有所提高。

客户端实现改善的第三步:先起线程从服务器端一次性下载完全部数据,而后置入内存,再以此为基础构建树。此举对速度也有明显提高。

客户端实现改善的第四步:将已经加载的节点从内存中删除,使查找时间逐渐减小。此举对速度有一定提高。

服务器端实现改善的第四步:不使用Hibernate的对象映射而单独遴选字段组建成一个包装类,此举对速度有一定提高。

服务器端实现改善的第五步:直接采用优化的存储过程将表中必要行集的数据在数据库段形成大文本,一次性传出,WS服务器端只负责传输,此举对速度有明显提高。

通过以上措施,完成包括六千个节点的树显示速度数量级的提高,综合评价一下,以上逐步中,第三步:在客户端另起线程从内存加载数据形成一棵完整的节点树再通知界面更新 和 第五步:通过存储过程直接取得行集合并结果对提高速度帮助最大。


posted @ 2010-01-08 22:20 何杨| 编辑 收藏

编程中Java应用常需要访问Tomcat,Weblogic等中间件,如果因为远程机器没有开机或是中间件服务未启动而导致服务不可用,则程序会抛出异常。如果事先对这些端口进行检测会更有利与我们诊断错误,下面就是一个诊断远程端口的类:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

import com.alpha.model.TPClientModel;
import com.alpha.util.DlgUtil;

/**
 * 这个类仅本类使用
 * 
@author 何杨
 * @date 2009-11-5
 * @time 下午03:15:20
 
*/
class IpPort{
    String ip;
    
int    port;
}

/**
 * 远程端口探测器,判断远程端口是否打开
 * 
 * 
@author 何杨
 * @date 2009-11-5
 * @time 下午02:48:56
 
*/
public class RemotePortTestor{    
    
public static Logger logger = Logger.getLogger(TPClientModel.class);
    
    
// 测试项目集合
    private List<IpPort> testItems;
    
    
    
/**
     * 构造函数
     * 
     * 
@param fileName
     * 
@param keys
     
*/
    
public RemotePortTestor(String fileName,List<String> keys){
        Properties prop
=new Properties();
        
try {
            prop.load(
new FileInputStream(fileName));
            
            testItems
=new ArrayList<IpPort>();
            
for(String key:keys){
                String value
=prop.getProperty(key);
                testItems.add(getIpPortAddr(value));
            }            
        } 
catch (FileNotFoundException e) {
            logger.error(e);
            e.printStackTrace();
        } 
catch (IOException e) {
            logger.error(e);
            e.printStackTrace();
        }
    }
    
    
/**
     * 检测远端端口,全部通过返回真
     * 
     * 
@return
     * 创建人:何杨
     * 创建日期:2009-11-5
     * 创建时间:下午03:32:34
     
*/
    
public boolean testRemotePorts(){
        
for(IpPort ipPort:testItems){
            
if(testRemotePort(ipPort.ip,ipPort.port)==false){
                
return false;
            }            
        }
        
        
return true;
    }
    
    
/**
     * 从URL中得到IP地址和端口
     * 
     * 
@param url
     * 
@return
     * 创建人:何杨
     * 创建日期:2009-11-5
     * 创建时间:下午03:32:55
     
*/
    
private IpPort getIpPortAddr(String url){
        IpPort ipPort
=new IpPort();
        
        String ip
=getMatchedString("(//)(.*)(:)",url);
        ipPort.ip
=ip;
        
        String port
=getMatchedString("(:)(\\d+)",url);
        ipPort.port
=Integer.parseInt(port);
        
        
return ipPort;
    }
    
    
/**
     * 检测端口是否能连接上
     * 
     * 
@param ip
     * 
@param port
     * 
@return
     * 创建人:何杨
     * 创建日期:2009-11-5
     * 创建时间:下午03:33:20
     
*/
    
public static boolean testRemotePort(String ip,int port){        
        
try {
            Socket s
=new Socket(ip,port);
            System.out.println(s.getLocalAddress()
+"可以访问"+ip+"上的端口"+port+"的服务.");
            s
=null;
            
return true;
        } 
catch (Exception e) {
            System.out.println(
"无法取得"+ip+"上的端口"+port+"的服务.");
            DlgUtil.popupErrorDialog(
"无法取得"+ip+"上的端口"+port+"的服务!\r\n,请确认服务可用后再执行本程序!");
                        
            e.printStackTrace();
            logger.error(e);
            
return false;
        }    
    }
    
    
/**
     * 从target找到regex能代表的文字
     * 
     * 
@param regex
     * 
@param target
     * 
@return
     * 创建人:何杨
     * 创建日期:2009-11-5
     * 创建时间:下午03:33:41
     
*/
    
public static String getMatchedString(String regex,String target){
        Pattern pattern
=Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
        
        Matcher matcher
=pattern.matcher(target);
        
        
while(matcher.find()){
            
return matcher.group(2);
        }
        
        
return null;
    }
    
    
/**
     * 测试入口
     * 
     * 
@param args
     * 创建人:何杨
     * 创建日期:2009-11-5
     * 创建时间:下午03:34:06
     
*/    
    
public static void main(String[] args){
        List
<String> ls=new ArrayList<String>();
        ls.add(
"webservice.url");
        ls.add(
"jmsbroker.url");
        
        String properitesFile
=TPClientModel.class.getResource("/remoteservice.properites").getFile().toString();
        RemotePortTestor rt
=new RemotePortTestor(properitesFile,ls);
        System.out.println(rt.testRemotePorts());
    }
}

remoteservice.properites的内容如下:
webservice.url=http://localhost:8080/SampleWebService/services/service
jmsbroker.url=tcp://192.168.0.110:61616

以上程序会自动从上述URL中找出IP地址和端口,然后用Socket连接过去看是否能联通,主要使用了正则表达式和Socket,比较简单,大家可自行阅读理解。


posted @ 2009-11-05 16:29 何杨| 编辑 收藏


代码如下:
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

/**
 * 此类用于取出本机的IP地址
 * 
 * 
@author 何杨
 * @date 2009-11-5
 * @time 上午10:41:13
 
*/
public class IPAddrFetcher{
    
public String getIPInfo(){
        StringBuilder sb
=new StringBuilder();
        
        
try{
            Enumeration
<NetworkInterface> interfaces=NetworkInterface.getNetworkInterfaces();
            
            
while(interfaces.hasMoreElements()){
                NetworkInterface ni
=interfaces.nextElement();
                
                sb.append(
"Interface "+ni.getName()+":\r\n");
                
                
                Enumeration
<InetAddress> inetAddresses=ni.getInetAddresses();
                
                
while(inetAddresses.hasMoreElements()){
                    InetAddress address
=inetAddresses.nextElement();
                    
                    sb.append(
"Address");
                    
                    
if(address instanceof Inet4Address){
                        sb.append(
"(v4)");
                    }
                    
else{
                        sb.append(
"(v6)");
                    }
                    
                    sb.append(
":address="+address.getHostAddress()+" name="+address.getHostName()+"\r\n");
                }
            }
        }
catch(Exception ex){
            ex.printStackTrace();
        }
                
        
return sb.toString();
    }
    
    
public static void main(String[] args){
        IPAddrFetcher iPAddrFetcher
=new IPAddrFetcher();
        System.out.println(iPAddrFetcher.getIPInfo());
    }
}


posted @ 2009-11-05 16:21 何杨| 编辑 收藏

JMS消息传递是一种异步过程,如果没有接受者JMS Provider应该选择将消息持久化,策略主要有文件持久化和基于数据库的持久化两种,下文是关于将未消费的消息持久化到MySql数据库的。

首先,我们要做的是将MySql数据库的驱动包放置到ActiveMQ的安装目录下的lib里。

其次,我们需要改写activemq.xml文件,它在ActiveMQ的conf目录中。具体修改部分请见下文中粗体部分:

<!--
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    this work for additional information regarding copyright ownership.
    The ASF licenses this file to You under the Apache License, Version 2.0
    (the "License"); you may not use this file except in compliance with
    the License.  You may obtain a copy of the License at
   
    http://www.apache.org/licenses/LICENSE-2.0
   
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->
<beans
  
xmlns="http://www.springframework.org/schema/beans"
  xmlns:amq
="http://activemq.apache.org/schema/core"
  xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation
="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
  http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd"
>

    
<!-- Allows us to use system properties as variables in this configuration file -->
    
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        
<property name="locations">
            
<value>file:${activemq.base}/conf/credentials.properties</value>
        
</property>      
    
</bean>

    
<!-- 
        The <broker> element is used to configure the ActiveMQ broker. 
    
-->
    
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.base}/data">
        
        
<!-- 
            The managementContext is used to configure how ActiveMQ is exposed in 
            JMX. By default, ActiveMQ uses the MBean server that is started by 
            the JVM. For more information, see: 
            
            http://activemq.apache.org/jmx.html 
        
-->
        
<managementContext>
            
<managementContext createConnector="false"/>
        
</managementContext>

        
<!-- 
            Configure message persistence for the broker. The default persistence
            mechanism is the KahaDB store (identified by the kahaDB tag). 
            For more information, see: 
            
            http://activemq.apache.org/persistence.html 
        
-->
        
<persistenceAdapter>
            
<jdbcPersistenceAdapter dataSource="#mysqlDataSource"/>
        
</persistenceAdapter>        
        
<!--
            For better performances use VM cursor and small memory limit.
            For more information, see:
            
            http://activemq.apache.org/message-cursors.html
            
            Also, if your producer is "hanging", it's probably due to producer flow control.
            For more information, see:
            http://activemq.apache.org/producer-flow-control.html
        
-->
              
        
<destinationPolicy>
            
<policyMap>
              
<policyEntries>
                
<policyEntry topic=">" producerFlowControl="true" memoryLimit="1mb">
                  
<pendingSubscriberPolicy>
                    
<vmCursor />
                  
</pendingSubscriberPolicy>
                
</policyEntry>
                
<policyEntry queue=">" producerFlowControl="true" memoryLimit="1mb">
                  
<!-- Use VM cursor for better latency
                       For more information, see:
                       
                       http://activemq.apache.org/message-cursors.html
                       
                  <pendingQueuePolicy>
                    <vmQueueCursor/>
                  </pendingQueuePolicy>
                  
-->
                
</policyEntry>
              
</policyEntries>
            
</policyMap>
        
</destinationPolicy> 
 
         
<!--
            The systemUsage controls the maximum amount of space the broker will 
            use before slowing down producers. For more information, see:
            
            http://activemq.apache.org/producer-flow-control.html
             
        <systemUsage>
            <systemUsage>
                <memoryUsage>
                    <memoryUsage limit="20 mb"/>
                </memoryUsage>
                <storeUsage>
                    <storeUsage limit="1 gb" name="foo"/>
                </storeUsage>
                <tempUsage>
                    <tempUsage limit="100 mb"/>
                </tempUsage>
            </systemUsage>
        </systemUsage>
        
-->
          
        
<!-- 
            The transport connectors expose ActiveMQ over a given protocol to
            clients and other brokers. For more information, see: 
            
            http://activemq.apache.org/configuring-transports.html 
        
-->
        
<transportConnectors>
            
<transportConnector name="openwire" uri="tcp://0.0.0.0:61616"/>
        
</transportConnectors>

    
</broker>

    
<!-- MySql dataSource -->
    
<bean id="mysqlDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        
<property name="url" value="jdbc:mysql://localhost/test?relaxAutoCommit=true"/>
        
<property name="username" value="root"/>
        
<property name="password" value="hy"/>
        
<property name="poolPreparedStatements" value="true"/>
    
</bean>

    
<!-- 
        Uncomment to enable Camel
        Take a look at activemq-camel.xml for more details
         
    <import resource="camel.xml"/>
    
-->

    
<!-- 
        Enable web consoles, REST and Ajax APIs and demos
        Take a look at activemq-jetty.xml for more details 
    
-->
    
<import resource="jetty.xml"/>
    
</beans>


如上,在persistenceAdapter节点中指定mySql数据源,在broker节点外配置了bean:

    <!-- MySql dataSource -->
    
<bean id="mysqlDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        
<property name="url" value="jdbc:mysql://localhost/test?relaxAutoCommit=true"/>
        
<property name="username" value="root"/>
        
<property name="password" value="hy"/>
        
<property name="poolPreparedStatements" value="true"/>
    
</bean>

上面加粗的一句指明了消息存储在mysql的test数据库中,当然你可以指定成任何你想要的数据库,注意在启动ActiveMq之前这个数据库是要存在的,否则报错。另外需要赘述的一点是activemq.xml中不要有中文,看来白狗子对非英语的抵触真是无处不在,我们所有中国人应该奋发图强恢复汉唐明荣光,让异族不得不仰视我们,当然这是后话。

下面就可以启动ActiveMQ了,向队列发送几条消息后,我们可以看看数据库里发生了什么变化,如下:


上图是ActiveMQ为了持久化消息而设立的三张表。


上图是持久化到数据库的未被消费掉的消息。

如果这些待消费消息被接收后,这张表就会空空如也,如下:


你可以使用这个程序(注意包要自己导入一下)来测试一下。

以上就是将ActiveMQ中未消费的消息持久化到MySql数据库的过程,但愿对你有所帮助。
posted @ 2009-10-27 11:23 何杨| 编辑 收藏

     摘要: 如果需要将表数据转化为XML形式数据的话,如果我们使用Spring的JDBC Template,那么常需要做的工作是创建一个RowMapper匿名类,在其中将字段与领域对象的某个属性匹配上,然后得到领域对象链表形式的结果,此后展开这个集合,再将字段转化为XML数据,其中进行了两次名称和值之间的匹配,硬编码较多,比较费时间。如果我们利用Metadata(Metadata是解释数据的数据,如果我们的研...  阅读全文
posted @ 2009-10-27 10:13 何杨| 编辑 收藏

     摘要: 相对于Weblogic这种大家伙来说,在ActiveMQ5.3.0上建立队列和主题还是相对容易的,当然如果路没走对也要费一番周折,本人在此写出小文,希望能对ActiveMQ初学者有所裨益,顺便感谢网络上那些辛勤的有共享精神的ActiveMQ研究者和鄙视一下那些懒惰的有剽窃习惯的转载者。 一.下载安装ActiveMQ。 在http://activemq.apache.org/ 你可...  阅读全文
posted @ 2009-10-27 09:00 何杨| 编辑 收藏

TimesTen是一种内存数据库,与其它内存数据库不同的是它依然使用SQL作为数据库存取的手段,估计是考虑到对Oracle数据库的兼顾和对象进出方式的不成熟。它既可以作为Oracle的前端缓存使用,也可以独立使用。下面是将它作为独立数据库并使用java程序对其进行访问的情况:

一.安装TimesTen数据库
到页面“http://www.oracle.com/technology/global/cn/software/products/timesten/index.html”下载适合你的环境的安装程序,并进行安装。(注意需要注册一个账号)

二.设置TimesTen环境变量
在你机器上的[TimesTen的安装目录]\tt70_32\bin下找到ttenv。双击即可。如果要手工设置可以参见其帮助文档,这里略过。

三.建立一个TimesTen数据源
1.打开“控制面板”->“管理工具”->“数据源”
2.点击“系统DSN”选项卡,点击“添加”按钮。
3.找到“TimesTen Data Manager 7.0”一项,再点击“完成”按钮。
4.在“Data Source  Name”一项中,填入数据源名;给 “Data Store Path”指定一个目录,给“Log  Directory”指定另一个目录;指定“DataBase Character Set”为UTF-8;指定“Type Mode”为“1-TimesTen”,这是不依赖Oracle数据库的方式。具体设置请参考下图:


四.通过ttIsql建表
ttIsql是TimesTen的管理控制台,作用相当于MySql数据库的“MySQL Command Line Client”或Oracle数据库的“Sql Plus”,通过它我们可以连接到数据库并执行Sql语句。
在开始菜单中我们可以找到“ttIsql (Interactive SQL)”,点击即打开管理控制台窗口。
窗口打开后,我们可以输入命令“connect myTstDs”连接到刚才建立的数据源,之后可以输入如下语句建立一张表:
create table employee(
   id 
CHAR(4primary key not null ,
   name 
VARCHAR(200)
)

五.通过程序在employee表中建立一条记录
通过程序访问一数据库的库我们需要找到种数据库的驱动包,访问TimesTen数据库的驱动包是ttjdbc14.jar,你可以在[TimesTenan安装目录]"tt70_32"lib下找到它。

以下是程序代码,它能打开TimesTen数据库,并向刚才创建的employee表中插入一条记录:
package com.heyang;

import java.sql.Connection;
import java.sql.PreparedStatement;

import com.timesten.jdbc.TimesTenDataSource;

/**
 * 程序入口点
 * 
@author 何杨(heyang78@gmail.com)
 *
 * 
@since 2009-10-17 下午07:17:11
 * 
@version 1.00
 
*/
public class Main {
  
public static void main(String[] args) {
    
try {
      Class.forName(
"com.timesten.jdbc.TimesTenDriver");

      String url 
= "jdbc:timesten:direct:dsn=myTstDs";

      TimesTenDataSource ds 
= new TimesTenDataSource();
      ds.setUrl(url);
      Connection conn 
= ds.getConnection();
      conn.setAutoCommit(
false);
      String sql 
= "insert into employee ( id, name ) values ( ?, ?);";

      PreparedStatement pstmt 
= conn.prepareStatement(sql);
      pstmt.setString(
1"002");
      pstmt.setString(
2"heyang@gmail.com");
      pstmt.executeUpdate();
      conn.commit();

      conn.close();

    } 
catch (Exception ex) {
      ex.printStackTrace();
    }
  }
}



posted @ 2009-10-18 07:50 何杨| 编辑 收藏

1.Oracle官方的介绍网页。

2.Oralce TimeStan的安装及体验配置,可惜是Linux上的。

3.Oracle官方TimeStan下载页面

4.一个简单的访问TimesTen数据库的例程

5.tst安装指南。
posted @ 2009-10-16 14:28 何杨| 编辑 收藏

WebService的原始API直接书写在代码中有诸多不便,如果我们把其调用过程归纳成一个类,再用Spring把URI和方法名注入到实例中去,这样就好些了。

归纳出来的WebService调用类:
package com.heyang;

import java.net.MalformedURLException;
import java.rmi.RemoteException;

import javax.xml.rpc.ServiceException;

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;

/**
 * WebService统一调用类
 * 
@author: 何杨(heyang78@gmail.com)
 * @date: 2009-10-10-下午11:47:56
 
*/
public class WebService{
    
private String endpoint;
    
    
private String operationName;
    
    
/**
     * 取得WebService调用的结果
     * 
@param args
     * 
@return
     * 
@throws ServiceException
     * 
@throws MalformedURLException
     * 
@throws RemoteException
     
*/
    
public Object getCallResult(Object[] args)throws ServiceException, MalformedURLException, RemoteException{
        
// 创建 Service实例
        Service service = new Service();
        
        
// 通过Service实例创建Call的实例
        Call call = (Call) service.createCall();
        
        
// 将Web Service的服务路径加入到call实例之中.
        call.setTargetEndpointAddress(new java.net.URL(endpoint));// 为Call设置服务的位置
        
        
// 调用Web Service的方法
        call.setOperationName(operationName);
        
        
// 调用Web Service,传入参数
        return call.invoke(args);
    }

    
public String getEndpoint() {
        
return endpoint;
    }

    
public void setEndpoint(String endpoint) {
        
this.endpoint = endpoint;
    }

    
public String getOperationName() {
        
return operationName;
    }

    
public void setOperationName(String operationName) {
        
this.operationName = operationName;
    }
}

再在上下文中配置三个bean,这样WebService的相关信息就变成可配置方式了:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
    
<bean id="method_isExist" class="com.heyang.WebService" >    
        
<property name="endpoint">
            
<value>http://localhost:8080/UserLoginService/services/login</value>
        
</property>
        
<property name="operationName">
            
<value>isExist</value>
        
</property>
    
</bean>
    
    
<bean id="method_getUserRole" class="com.heyang.WebService" >    
        
<property name="endpoint">
            
<value>http://localhost:8080/UserLoginService/services/login</value>
        
</property>
        
<property name="operationName">
            
<value>getUserRole</value>
        
</property>
    
</bean>
    
    
<bean id="method_getUserTrade" class="com.heyang.WebService" >    
        
<property name="endpoint">
            
<value>http://localhost:8080/UserLoginService/services/login</value>
        
</property>
        
<property name="operationName">
            
<value>getUserTrade</value>
        
</property>
    
</bean>
 
</beans>

调用因此也变得相对简单:
package com.heyang;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 使用Spring的简约式调用WebService
 * 
@author: 何杨(heyang78@gmail.com)
 * @date: 2009-10-10-下午11:40:49
 
*/
public class SpringTest{
    
public static void main(String[] args){
        
try{
            ApplicationContext appContext 
= new ClassPathXmlApplicationContext("bean.xml");
            Object[] params
=new Object[] { "MT001","123" };
            
            WebService ws1
=(WebService)appContext.getBean("method_isExist");
            WebService ws2
=(WebService)appContext.getBean("method_getUserRole");
            WebService ws3
=(WebService)appContext.getBean("method_getUserTrade");
            
            System.out.println(ws1.getCallResult(params));
            System.out.println(ws2.getCallResult(params));
            System.out.println(ws3.getCallResult(params));
        }
        
catch(Exception ex){
            ex.printStackTrace();
        }
    }
}

代码下载(jar请从前面的程序里找,WebService即用上一篇文章中的UserLoginService):
http://www.blogjava.net/Files/heyang/UserLoginServiceTest20091011082831.rar
posted @ 2009-10-11 00:10 何杨 阅读(4261) | 评论 (1)编辑 收藏

参考文章一:
使用Axis开发Web Service程序
它对初学者有所帮助

参考文章二:
在axis中通过wsdd文件发布和卸载webservice
这篇文章披露了一些wsdd文件的细节,有一定参考价值。

下面是一个Axis的Web Service程序实例及测试程序:
http://www.blogjava.net/Files/heyang/userloginWebService20091010232908.rar
注意为了减少体积lib目录中的jar都被删除了,你可以从http://www.blogjava.net/Files/heyang/SerialNumber20090929130453.rar 这个工程的lib目录中找到所需要的所有jar包。

希望能对大家有所帮助。

posted @ 2009-10-10 23:34 何杨| 编辑 收藏

大家自己试一试吧:

ASCII Escaped UNICODE 的转换,不用native2ascii.exe
posted @ 2009-10-03 08:34 何杨| 编辑 收藏

Web Service定义了一套标准的调用过程:
  • 服务器端首先用一套标准的方法向外界描述它所提供的服务的内容,这属于WSDL的范畴。
  • 客户端需要以一种标准的协议来调用此服务,这属于SOAP的范畴。
  • 服务提供者将服务内容放在一个公共的网址上让人查询,这属于UDDI的范畴。
WSDL:服务内容的标准化描述
WSDL的目的是告诉外界自己能提供什么样的服务,有点类似于java的接口。
WSDLd的全称是Web Service Description Language,是一种基于XML的关于Web服务的描述,主要目的在于将自己的Web服务的所有相关内容如提供服务的传输方式,服务方法接口,接口参数,服务路径等,生成相应的完全的文档,发布给使用者。使用者可以通过这个WSDL文档,创建相应的SOAP请求消息,通过HTTP传递给Web服务提供者;Web服务提供者在完成请求服务后,将SOAP返回消息传回给请求者,服务请求者再根据WSDL文档将SOAP返回消息解析成程序能够理解的内容。

SOAP:标准的传输协议
SOAP是标准化的消息协议,是客户端送给服务器希望调用的类和方法的一种消息格式,也包括服务返回的消息格式。之所以有SOAP是因为只有大家都遵守一套消息格式的标准,相互之间才能明白对方想要干什么。
SOAP是Web Service的标准传输协议,是Simple Object Application Propotol的简写,是一种标准化的传输消息的XML格式。
SOAP请求消息将客户端的服务请求消息发给服务器,比如想调用什么接口,以及接口的参数值等。SOAP答复消息是从服务器返回给客户端的消息,如接口实现类调用后的返回值或是调用服务时的错误信息等。定义WSDL是很重要的,一旦WSDL定义好了,再根据WSDL的输入变量和输出变量的结构就可以知道SOAP的请求消息和响应消息的格式了。

UDDI:服务的公共网址
UDDI是Universal Description Discovery and Intergretion的缩写,是一种创建注册服务的规范,以便大家将自己的Web Service进行注册发布供使用者查找。
当服务提供者想将自己的Web Service发布,以便外部能找到其服务时,那么服务提供这可以将自己的Web Service注册到相应的UDDI商用注册网站。
UDDI并非一个必须的Web Service组件,服务方完全可以不进行UDDI的注册。因为WSDL文件中已经给出了Web Service的地址URI,外部可以通过它进行相应的Web Service调用。

以下是一个Web Service示例程序,主要参考了梁爱虎的《SOA 思想,技术与系统集成应用详解》中的例子:

发布Web服务的类接口:
package com.heyang;

/**
 * 生成序列号的接口
 * 
@author: 何杨(heyang78@gmail.com)
 * @date: 2009-9-29-下午12:37:55
 
*/
public interface ISerial{
    
/**
     * 传入类型,返回序列号
     * 
@param type
     * 
@return
     
*/
    
public String getSN(String type);
}

发布web服务的类:
package com.heyang;

import java.text.MessageFormat;

/**
 * ISerial的实现类
 * 
@author: 何杨(heyang78@gmail.com)
 * @date: 2009-9-29-下午12:40:05
 
*/
public class SerialService implements ISerial{
    
private static int number;
    
    
/**
     * 产生SN:CD-000001的序列号
     * MessageFormat的用法可参考http://hi.baidu.com/gacmotor/blog/item/372b4a3a0b010de314cecb0b.html
     
*/
    
public String getSN(String type) {
        number
++;
        Object[] arr
=new Object[]{type,number};
        String result
=MessageFormat.format("SN:{0}-{1,number,000000}",arr);
        
return result;
    }
    
    
public static void main(String[] args){
        SerialService s
=new SerialService();        
        System.out.println(s.getSN(
"CD"));
    }
}

Web.xml:
<?xml version="1.0" encoding="UTF-8"?>

<web-app > 
    
<servlet>
        
<servlet-name>AxisServlet</servlet-name>
        
<servlet-class>
            org.apache.axis.transport.http.AxisServlet
        
</servlet-class>
    
</servlet>

    
<servlet-mapping>
        
<servlet-name>AxisServlet</servlet-name>
        
<url-pattern>/servlet/AxisServlet</url-pattern>
    
</servlet-mapping>

    
<servlet-mapping>
        
<servlet-name>AxisServlet</servlet-name>
        
<url-pattern>*.jws</url-pattern>
    
</servlet-mapping>
    
    
<servlet-mapping>
        
<servlet-name>AxisServlet</servlet-name>
        
<url-pattern>/services/*</url-pattern>
    
</servlet-mapping>
</web-app>

wsdd文件server-config.wsdd
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
    xmlns:java
="http://xml.apache.org/axis/wsdd/providers/java">
    
<handler type="java:org.apache.axis.handlers.http.URLMapper"
        name
="URLMapper" />
    
<service name="fetchSerialNumber" provider="java:RPC">
        
<parameter name="className" value="com.heyang.SerialService" />
        
<parameter name="allowedMethods" value="getSN" />
    
</service>
    
<transport name="http">
        
<requestFlow>
            
<handler type="URLMapper" />
        
</requestFlow>
    
</transport>
</deployment>

测试类:
package com.heyang.client;

import java.net.MalformedURLException;
import java.rmi.RemoteException;

import javax.xml.rpc.ServiceException;

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;

/**
 * WebServiceClientTest
 * 
@author: 何杨(heyang78@gmail.com)
 * @date: 2009-9-29-下午01:03:05
 
*/
public class WebServiceClientTest {
    
public static void main(String[] args) throws ServiceException,
            MalformedURLException, RemoteException {
        
// 标识Web Service的具体路径
        /**
         * SerialNumber:发布到Tomcat上的war的名称,采用工程名
         * services:固定写法,与Web.xml中设定对应
         * fetchSerialNumber:server-config.wsdd中设定的service名
         
*/
        String endpoint 
= "http://localhost:8080/SerialNumber/services/fetchSerialNumber";

        
// 创建 Service实例
        Service service = new Service();
        
        
// 通过Service实例创建Call的实例
        Call call = (Call) service.createCall();
        
        
// 将Web Service的服务路径加入到call实例之中.
        call.setTargetEndpointAddress(new java.net.URL(endpoint));// 为Call设置服务的位置
        
        
// 调用Web Service的方法
        call.setOperationName("getSN");
        
        
// 调用Web Service,传入参数
        String retval = (String) call.invoke(new Object[] { "CD" });
        
        System.out.println(retval);
    }
}

输出示例:
SN:CD-000004


例程下载(使用Axis,注意Tomcat的lib目录中要包括mail.jar和activation.jar):
http://www.blogjava.net/Files/heyang/SerialNumber20090929130453.rar

使用说明:
使用Ant脚本将jar包打好,再部署到Tomcat中,可以用http://localhost:8080/SerialNumber/services来测试一下是否有输出,有则表示部署成功,之后执行WebServiceClientTest。

主要参考资料:
梁爱虎著《SOA 思想,技术与系统集成应用详解》
posted @ 2009-09-29 14:09 何杨| 编辑 收藏

XPath的概念
XPath是一种定位XML文档的各个部分的语言,它还提供处理字符串,数字和布尔值的常用函数。XPath可以定位XML文档的元素和属性等部件。XPath提供的一星儿函数能够定位返回字符串或检测出字符串的长度,XPath还包括字符数据转换成数字类型和布尔类型的函数。
XPath从它的路径符号给出名称,它使用的语法铜URL类似,通常称XPath语句为XPath表达式。
XPath不是一种独立技术,它用于其它的技术如XSLT中,用XPath可以检索XML的元素和属性,可以XPath看做是XML的SQL。

XPath语法
1.定位路径:他是一种选择节点集合的XPath表达式类型,通常使用“/”隔开的定位阶来构造定位路径。如/games/game,上述定位路径有两个定位阶。定位路径有两种类型:相对的和绝对的。相对的定位路径是由“/”分开的一个或多个定位阶的序列。绝对定位路径由“/”和后面的相对定位路径组成。

2.定位阶:他是定位路径的组成部分,由三部分组成:
  1)一个轴:它规定了上下文节点和定位阶所选节点之间的关系。
  2)一个节点测试:它规定了定位阶选择的阶段类型。
  3)零或多个谓词,它们使用了表达式进一步改进节点的选择。
  如XPath表达式"/games/game[@genre='rpg']",该表达式选择了所有genre属性值为rpg的位于games元素下的game元素。

3.节点测试:它通知XPath表达式运算的节点类型,节点测试通常都是源树种元素名称,如/games/game,该表达式有两个节点测试:games和game。

4.轴说明符:它用于明确指出要处理的节点测试的关系,如果要选games元素的所有子元素,则代码如下:child::games.
  下面归纳了部分轴说明符
  轴说明符           说明
  child              节点的所有子节点
  descendant         节点的所有后代节点
  parent             节点的父节点
  following-sibling  节点后面的兄弟节点
  preceding-sibling  节点前面的兄弟节点

5.谓词:它是另一种进一步缩小节点选择范围的方法。XPath使用方括号[]来指定谓词,谓词使用XPath提供的函数提供测试,它可以访问属性(使用@符号)。
如前面出现过的XPath表达式"/games/game[@genre='rpg']",方括号[]中的“@genre='rpg'”就是谓词,该表达式用于测试位于games元素下的game元素的genre属性值是否为rpg。

XPath函数
XPath函数使得用户能够处理字符串,数字和节点集合,下面列出了三个节点集合函数:
number last()           返回最后位置 如count(games/game)返回games元素下的game元素数目
number position()       返回当前位置 如games/game[last()]返回games元素下的最后一个game元素
number count(node-set)  返回结合参数中节点数目 如/games/game[position()=1]将返回games元素下的首个game元素。

下面使用开源包dom4j对XML文档进行XPath操作的例子

将要处理的XML文档如下:
<?xml version="1.0" encoding="GBK"?>

<employees> 
  
<employee lable="tech">
    
<id>0001</id>
    
<name>李白</name>
    
<title>程序员</title>
    
<skill>Java</skill>
    
<age>18</age>
  
</employee>
  
<employee lable="tech">
    
<id>0002</id>
    
<name>杜甫</name>
    
<title>高级程序员</title>
    
<skill>C#</skill>
    
<age>28</age>
  
</employee>
  
<employee lable="tech">
    
<id>0003</id>
    
<name>Andy</name>
    
<title>项目经理</title>
    
<skill>PPT</skill>
    
<age>38</age>
  
</employee>
  
<employee lable="admin">
    
<id>0004</id>
    
<name>Bill</name>
    
<title>部门经理</title>
    
<skill>Java</skill>
    
<age>48</age>
  
</employee>
  
<employee lable="admin">
    
<id>0005</id>
    
<name>Cindy</name>
    
<title>总经理</title>
    
<skill>C#</skill>
    
<age>58</age>
  
</employee>
</employees>

XPath示例程序:
package com.heyang;

import java.util.Iterator;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;

/**
 * dom4j的XPath解析示例
 * 
@author: 何杨(heyang78@gmail.com)
 * @date: 2009-9-27-上午09:59:52
 
*/
public class XPathSample{
    
public static void main(String[] args) throws Exception{
        SAXReader reader 
= new SAXReader();
        Document  doc 
= reader.read(XPathSample.class.getResource("/Employee.xml").getPath());
        
        
// 1.XPath选择器,选择根节点employees下所有属性lable为tech的employee子节点
        System.out.println("1.选择根节点employees下所有属性lable为tech的employee子节点");
        XPath xpathSelector 
= DocumentHelper.createXPath("/employees/employee[@lable='tech']");
        List results 
= xpathSelector.selectNodes(doc);
        
for ( Iterator iter = results.iterator(); iter.hasNext(); ) {
          Element element 
= (Element) iter.next();
          
// 找到employee子节点的name子节点的文字打印
          System.out.println(element.selectSingleNode("./name").getText());
        }
        
        
// 2.打印名称为李白的employee节点的title
        System.out.println("2.打印名称为李白的employee节点的title");
        String title 
= doc.valueOf( "//employee[name='李白']/title" );
        System.out.println(title);

        
// 3.XPath选择器,选择所有属性lable为admin的employee子节点的name子节点
        System.out.println("3.选择所有属性lable为admin的employee子节点的name子节点");
        XPath xpathSelector2 
= DocumentHelper.createXPath("//employee[@lable='admin']/name");
        List results2 
= xpathSelector2.selectNodes(doc);
        
for ( Iterator iter = results2.iterator(); iter.hasNext(); ) {
            Element element 
= (Element) iter.next();
            System.out.println(element.getText());
        }
        
        
// 4.XPath选择器,选择所有年龄节点大于20的employee子节点的name子节点
        System.out.println("4.选择所有年龄节点大于20的employee子节点的name子节点");
        XPath xpathSelector3 
= DocumentHelper.createXPath("//employee[age>20]/name");
        List results3 
= xpathSelector3.selectNodes(doc);
        
for ( Iterator iter = results3.iterator(); iter.hasNext(); ) {
            Element element 
= (Element) iter.next();
            System.out.println(element.getText());
        }
    }
}

控制台输出:
1.选择根节点employees下所有属性lable为tech的employee子节点
李白
杜甫
Andy
2.打印名称为李白的employee节点的title
程序员
3.选择所有属性lable为admin的employee子节点的name子节点
Bill
Cindy
4.选择所有年龄节点大于20的employee子节点的name子节点
杜甫
Andy
Bill
Cindy

XPath相关参照文档(网络上搜索得到,不保证内容的完全正确性):
表达式            描述
节点名            选择所有该名称的节点集
/                 选择根节点
//                选择当前节点下的所有节点
.                 选择当前节点
..                选择父节点
@                 选择属性
示例
表达式            描述
bookstore         选择所有bookstore子节点
/bookstore        选择根节点bookstore
bookstore/book    在bookstore的子节点中选择所有名为book的节点
//book            选择xml文档中所有名为book的节点
bookstore//book   选择节点bookstore下的所有名为book为节点
//@lang           选择所有名为lang的属性

方括号[],用来更进一步定位选择的元素
表达式                            描述
/bookstore/book[1]                 选择根元素bookstore的book子元素中的第一个(注意: IE5以上浏览器中第一个元素是0)
/bookstore/book[last()]            选择根元素bookstore的book子元素中的最后一个
/bookstore/book[last()-1]          选择根元素bookstore的book子元素中的最后第二个
/bookstore/book[position()<3]      选择根元素bookstore的book子元素中的前两个
//title[@lang]                     选择所有拥有属性lang的titile元素
//title[@lang='eng']               选择所有属性值lang为eng的title元素
/bookstore/book[price>35.00]       选择根元素bookstore的book子元素中那些拥有price子元素且值大于35的
/bookstore/book[price>35.00]/title 选择根元素bookstore的book子元素中那些拥有price子元素且值大于35的title子元素

选择位置的节点
通配符               描述
*                    匹配所有元素
@*                   匹配所有属性节点
node()               匹配任何类型的节点
示例
表达式               描述
/bookstore/*         选择根元素bookstore的下的所有子元素
//*                  选择文档中所有元素
//title[@*]          选择所有拥有属性的title元素
使用操作符“|”组合选择符合多个path的表达式

posted @ 2009-09-27 10:56 何杨| 编辑 收藏

在Spring的Bean装配文件中配置组件是合适的,但类似于数据库细节,队列主题细节等应该分离出来,这时我们可以使用Spring的PropertyPlaceholderConfigurer从外部属性文件中装载一些配置信息,使用起来很简单,请参考下例:
http://www.blogjava.net/Files/heyang/SpringProperties20090926133054.rar

注意加入必要的包:commons-logging-1.0.4.jar,log4j-1.2.14.jar,spring.jar

两个配置的内容:
person1.properties
person1.id=001
person1.name
=Andy
person1.password
=123456

person2.properties
person2.id=002
person2.name
=Bill
person2.password
=111111

Bean装配文件的内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
    
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        
<property name="locations">
            
<list>
                
<value>person1.properties</value>
                
<value>person2.properties</value>                
            
</list>
        
</property>
    
</bean>
    
<bean id="person1" class="com.heyang.Person" >    
        
<property name="id">
            
<value>${person1.id}</value>
        
</property>
        
<property name="name">
            
<value>${person1.name}</value>
        
</property>
        
<property name="password">
            
<value>${person1.password}</value>
        
</property>
    
</bean>
    
    
<bean id="person2" class="com.heyang.Person" >    
        
<property name="id">
            
<value>${person2.id}</value>
        
</property>
        
<property name="name">
            
<value>${person2.name}</value>
        
</property>
        
<property name="password">
            
<value>${person2.password}</value>
        
</property>
    
</bean>
 
</beans>

Person类:
public class Person{
    
private String name;
    
private String id;
    
private String password;
    
    
public String toString(){
        
return "Person id="+id+" name="+name+" password="+password;
    }
    
    
public String getId() {
        
return id;
    }
    
public void setId(String id) {
        
this.id = id;
    }
    
public String getName() {
        
return name;
    }
    
public void setName(String name) {
        
this.name = name;
    }
    
public String getPassword() {
        
return password;
    }
    
public void setPassword(String password) {
        
this.password = password;
    }
    
    
public static void main(String[] args){
        ApplicationContext appContext 
= new ClassPathXmlApplicationContext("bean.xml");
        
        Person person1
=(Person)appContext.getBean("person1");
        System.out.println(person1);
        
        Person person2
=(Person)appContext.getBean("person2");
        System.out.println(person2);
    }
}

控制台输出:
Person id=001 name=Andy password=123456
Person id
=002 name=Bill password=111111

posted @ 2009-09-26 13:34 何杨| 编辑 收藏

命名服务概述
命名服务(Naming Service)是可以将复杂数据对象或其引用关联到已知名称的机制.然后可以发布这些名称,客户可以使用这些名称查询与它们相关联的数据对象.名称与对象之间的关联称为绑定.命名服务通常与其它服务(如文件系统,目录和数据库等)集成以提供这种绑定.大家可以从现代图书馆的卡片目录系统来理解命名服务.

JNDI介绍(Java Naming and Directory Inteface,Java命名与目录接口)
JNDI是Java命名与目录接口(Java Naming and Directory Inteface)的缩写,有时也简称Java名录服务,J2EE组件通过调用JNDI提供的查找(lookup)方法以定位对象。JNDI是专门为Java设计的,一个Java应用程序可以用JNDI检索Java对象.JNDI还可以执行标准目录操作,如关联属性和对象,并用对象的属性搜索它们.
JNDI名字是对象的友好名字,这些名字通过J2EE服务器提供的命名目录服务绑定到各自的对象上。由于J2EE组件是通过JNDI编程接口访问服务的,所以通常情况下把对象的友好名字称之为JNDI名字。比如,mydatabase数据库的JNDI名字为jdbc/mydatabase,一旦J2EE服务器启动,系统自动从配置文件读取相关信息,并将jdbc/mydatabase的JNDI数据库名字添加到名字空间。
Sun公司对JNDI的定义为”一种对Java平台的标准扩展,它为Java技术编写的应用程序提供了对企业中多种命名和目录服务的统一接口.作为Java Enterprise API集的一部分,JNDI使与异构企业命名和目录服务的无缝连接提供了可能”.

连接工厂(Connection Factory)
连接工厂(Connection Factory)是用于产生链接对象,使得J2EE组件可以访问资源的一种对象。比如,用于数据库的连接工厂是javax.sql.Database对象,它产生java.sql.Connection对象。

JNDI和Weblogic Server
Weblogic提供了在JNDI规范中规定的实现.这使Java客户可以用标准JNDI调用连接到Weblogic Server.客户可以在Weblogic命名空间中访问Weblogic命名服务并使对象可用,还可以检索它们.
如果希望访问已经加载到Weblogic Server的JNDI树中的对象的Java客户一般要执行以下任务:
1.与服务器建立一个上下文
2.对JNDI树进行查询或者更新

取得上下文例程
这是在命名空间中访问绑定对象的第一步.应用程序将获得引导上下文称为InitialContext.它是从InitialContext工厂获得的.这个工厂使用几个属性标识上下文需要指向的Weblogic Server.
Hashtable ht=new Hashtable();
ht.put(Context.INITIAL_CONTEXT_FACTORY, 
"weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL, 
"t3://127.0.0.1:7001");

Context ctx
=null;   

try {
    ctx
=new InitialContext(ht);
catch (NamingException e) {
    e.printStackTrace();
    System.out.println(
"不能得到上下文");
}

创建一个绑定例程
要在WeblogicJNDI树中创建一个新的绑定,可使用Context.bind方法.这个方法以新绑定的名称以及绑定到这个名称号的对象为参数.注意这个对象必须是可序列化的,也就是说它必须实现java.io.Serializablejie接口(实现这个接口无需实现任何方法,它只是告诉JVM这个对象可以序列化).
Hashtable ht=new Hashtable();
ht.put(Context.INITIAL_CONTEXT_FACTORY, 
"weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL, 
"t3://127.0.0.1:7001");
Context ctx
=null;   
try {
  ctx
=new InitialContext(ht);  
  String text
="菩提本非树,明镜亦非台,本来无一物,何处染尘埃.";   
  ctx.bind(
"TEST", text);
catch (NamingException e) {
  e.printStackTrace();
  System.out.println(
"不能得到上下文");
}

下面是在Weblogic中查看刚才创建的绑定内容图示
一.点击环境,服务器,点击“查看JNDI树链接”


二.可以看到已经绑定到JNDI树中的对象

删除现有的绑定例程
使用Context.unbind方法可以从JNDI树中删除绑定,不能再从树中访问这些对象了.
Hashtable ht=new Hashtable();
ht.put(Context.INITIAL_CONTEXT_FACTORY, 
"weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL, 
"t3://127.0.0.1:7001");

Context ctx
=null;   
try {
  ctx
=new InitialContext(ht);  
  ctx.unbind(
"TEST");
catch (NamingException e) {
  e.printStackTrace();
  System.out.println(
"不能得到上下文");
}

总结
JNDI为应用程序提供了标准统一的方式,连接和使用企业中存在的多个对象目录的能力.WeblogiocServer提供了JNDI的实现,客户机可以和它无缝连接.同一客户机还可以用JNDI API连接到另一命名服务上.Weblogic Server大量利用JNDI树完成其常规功能.如果应用程序使用EJB,那么这个EJB就发布在JNDI树中,类似的其它对象如DataSource对象,事务对象都发布在JNDI树上.

参考例程
WeblogicJNDI(注意:weblogic.jar请自行加入lib目录)

posted @ 2009-09-25 09:16 何杨| 编辑 收藏



消息服务

消息服务是以可靠的,异步的,松耦合的,语言无关的,平台无关的以及通常是可配置的方式在分布式应用程序之间传递消息的软件。消息服务通过封装在发送者和接受者之间传递的消息,并提供位于分布式消息客户之间的软件层完成这一任务。消息服务还提供了让消息客户使用的接口,它隔离了底层消息服务实现。这样的基础结构还可以看成是事件通知类型的服务,其中消息是事件,在消息客户间发送这些消息是一种事件通知机制。

理解消息传递

消息传递是一种在软件组件或者应用之间进行通信的方法。一个消息传递系统是一个点对点的设施:一个消息传递客户端可以发送消息到任何其它客户端,或者接收来自它们的消息。每个客户端连接到一个消息传递代理,消息传递代理提供了创建,发送,接受和阅读消息的工具。
消息传递支持松耦合的分布式通信。组件发送消息到某个目的地,接收方可以从目的地获取消息。但是,发送方和接收方在通信时并不需要同时可用。实际上,发送 方不需要了解任何有关接收方的内容,而接收方也不需要了解任何有关发送方的内容。发送方和接收方只需知道要使用什么样的消息格式以及什么目的地。
消息传递和电子邮件不同,它是一种在人们之间或软件和人们之间建立通信的方法,而消息传递则用于软件应用或软件组件之间的通信。

使用消息服务中间件的消息服务实现
一些中间件软件(Weblogic,Sonic MQ等)实现了异步接收由消息生产者生成的消息,并将它们路由给消息消费者的消息服务功能。消息客户通过消息客户接口,以透明的方式利用中央消息服务的服务。
通过致力于使用中间件中的中央管理的持久和冗余的机制,消息中间件提高了消息服务的可靠性和可用性。消息中间件允许消息客户与消息服务中间件服务器之间的连接,还减轻了客户管理到多个消息服务端点位置的连接的需要。
(补图)

Message-Oriented Middleware,MOM
面向消息的中间件和消息服务几乎是同义词,MOM就是消息服务的一种实现,尽管采取的是特定类型的MOM系统的标准方式。MOM API定义了分布式应用程如何使用底层MOM消息信道或者队列彼此通信。
消息在应用程序之间通过MOM传递,不会使消息的发送者阻塞,也就是说,发送者可以发送一个消息并让MOM保证它到达预定的接受者,而不用等待接受者的响应。

Java Message Service(JMS)
从J2EE1.3版本开始,JMS API开始成为该平台的一部分,应用开发者可以通过JavaEE组件来使用消息传递。
当JMS API在1998年引入时,它最重要的用途是允许Java应用访问现有的面向消息中间件系统,如来自IBM的MQSeries,后来JMS产品可以为企业应用提供一个完整的消息传递功能。
Java Message Service(JMS)是一个定义了消息客户如何用标准方式与底层消息服务提供者通信的Java API。
JMS还提供了一个接口,底层消息服务提供者实现了这个接口,向客户提供JMS服务。
JMS提供了点到点和发布-订阅模型。在JMS规范中,这种消息模型也称为消息域。点到点消息是通过实现消息队列完成的,生产者在队列中写入消费者接收的消息;发布-订阅模型是通过实现主题节点的层次结构完成的,其中生产者发布消息,消费者可以订阅这些消息。
JMS提供了核心抽象消息API,点到点消息队列模型API和发布-订阅模型API都扩展这个API。

什么是JMS API
Java消息服务API允许应用创建发送,接收和阅读消息。它的特点有:
1.异步:JMS供应者在接受到消息时可以将它们传递到某个客户端,客户端不必为了接收这些消息而主动发出请求。
2.可靠:JMS API可以确保某个消息传递而且只传递一次。对于那些能够忍受消息丢失或接受到重复消息的应用,也可以使用较低级别的可靠性。

何时使用JMS API
在以下情况下,企业应用供应者更可能选择消息传递API而不是某种紧耦合API:
1.供应者希望组件不依赖有关其他组件接口的信息,这样可以很容易替换组件。
2.供应者希望应用在不管所有组件是否已经就绪并且同时运行的情况下都能够运行。
3.应用业务模型允许组件发送信息到其它组件并且在不必接收到立即响应的情况下继续工作。

基本的JMS API概念
编写基本的JMS客户端应用必须了解以下概念:
JMS API 体系结构
消息传递域
消息使用

JMS API体系结构
JMS应用由以下部分所组成:
1.JMS供应者(JMS Provider):它是一个实现了JMS接口并提供管理和控制功能的消息传递系统。
2.JMS客户端(JMS Client):是以Java编程语言编写,负责生成和是哟个消息的程序或组件。任何JavaEE应用组件都可以作为JMS客户端。
3.消息(Message):是在JMS客户端之间进行信息沟通的对象。
4.管理对象(Administrered Object)是预先配置好的JMS对象,它是由管理员针对客户端的使用而创建的。JMS管理对象的两种类型有目的地(Destination)和连接工厂(ConnectionFactory)。


两种消息传递域(模式)

点对点消息传递域:这种消息传递是建立在消息队列,发送方和接收方的概念上的。每个消息都被寻址到某个特定的队列,并且负责接收的客户端从保存消息的队列中提取这些消息。在消息被使用或过期之前,队列会移植保存所有发送给它们的消息。它的特点有:
1.每个消息只有一个使用者(消费者),即一条消息只会被一个使用者(消费者)使用。
2.消息的发送方和接收方并没有时间同步的依赖性。当发送方发送消息时,不管接受方是否在运行,后者都可以接收到所发送的消息。
3.接收方在成功处理完消息后会发出确认。
4.这种模式适合多个发送者对一个消费者的情况。

发布/订阅消息传递域:这种消息传递方式中客户端按照某个主题来处理消息,发送者和订阅者通常是匿名的,而且可以动态的发布或订阅内容层次。系统负责将来自某个主题的多个发布者的消息分发到该主题的多个订阅者。主题只要负责将消息分发到当前订阅者,便同时负责保存这些消息。它的特点有:
1.每个消息可以有多个使用者。
2.发布者和订阅者具有时间同步依赖性。订阅了某个主题的客户端只有在客户端创建了订阅之后才能使用所发布的消息,而且订阅者必须继续保持活动状态才能使用消息。
3.这种模式适合一个发送者对多个消费者的情况。

图:两种JMS类层次结构



消息使用

消息传递产品本质上是异步的:在消息的生成和使用之间并没有基本的时间同步依赖性,JMS规定消息可以按照以下方式之一来使用:
同步:订阅者或接收方通过调用receive方法明确获取来自目的地的消息。Receive方法在消息到来之前可以进入阻塞状态,或者在消息未在指定时间范围内到达的情况下进入超时状态。
异步:客户端可以向使用者注册一个消息监听器(message listener)。消息监听器类似于事件监听器,当消息到达目的地时,JMS供应者通过调用监听器的onMessage方法来传递消息。

JMS API的重要接口
ConnectionFactory :连接工厂,用于创建到特定JMS服务提供者(如Weblogic,IBM MQ或是Sonic MQ)的消息服务的连接。可以用JNDI查询到一个JMS服务提供者管理的初始ConnectionFactory对象的句柄。它提供了返回特定Connection对象实例的方法,可以使用ConnectionFactory.createConnection()得到Connection对象的句柄。
Connection :它封装了一个从JMS 客户端到JMS服务提供者(JMS Provider)实例的连接 。
Destination :消息的目的地
Session:JMS会话,它与Connection相关联,便是创建消息的上下文。会话可以用于定义一个事务,在该事务的边界中可以存在一组在十五中发送和接收的消息,因此,所有这些消息可包含在一个原子事务中。Session接口封装了一个上下文,JMS消息是在这个上下文中创建和接收的。它还扩展了java.lang.Runnable接口,表明每一个会话运行在单个线程的上下文中,可以用Connection.createSession()方法创建Session对象的句柄,传递给方法的Boolean参数表明会话是否是事务性的。附加在会话上的监听器也可用于得到更多异步回调行为。MessageListener实现了一个onmessage()方法,对于所有由这个Session对象收到的消息,它取Message作为参数,Session对象的setMessageListener和getMessageListenner分别设置和取得MessageListener。
MessageProducer: 由Session 对象创建的用来发送消息的对象
MessageConsumer: 由Session 对象创建的用来接收消息的对象

开发JMS客户端的几个步骤:
广义上说,一个JMS应用是几个JMS 客户端交换消息,开发JMS客户端应用由以下几步构成:
1) 用JNDI 得到ConnectionFactory对象;
2) 用JNDI 得到目标队列或主题对象,即Destination对象;
3) 用ConnectionFactory创建Connection 对象;
4) 用Connection对象创建一个或多个JMS Session;
5) 用Session 和Destination 创建MessageProducer和MessageConsumer;
6) 通知Connection 开始传递消息。】

JMS消息模型
JMS 消息由以下几部分组成:消息头,属性,消息体。
1.消息头(header):JMS消息头包含了许多字段,它们是消息发送后由JMS提供者或消息发送者产生,用来表示消息、设置优先权和失效时间等等,并且为消息确定路由。
2.属性(property):由消息发送者产生,用来添加删除消息头以外的附加信息。
3.消息体(body):由消息发送者产生,JMS中定义了5种消息体:ByteMessage、MapMessage、ObjectMessage、StreamMessage和TextMessage。

JMS的五种专用消息类型
JMS API中定义了五种类型的消息,它们扩展了Message接口并对应于五种类型的消息正文数据。它们是:
1.TextMessage:正文为基础java.lang.String对象的消息,如xml文件内容。
2.MapMessage:正文为底层键值对集合的消息,键是String对象,值类型可以是Java任何基本类型。
3.BytesMessage:正文为字节集合。
4.StreamMessage:正文为Java中的输入输出流。
5.ObjectMessage:正文为Java中的可序列化对象(实现Serializable接口的对象)。

当前比较流行的JMS商业软件和开源产品:
目前许多厂商采用并实现了JMS API,现在,JMS产品能够为企业提供一套完整的消息传递功能,下面是一些比较流行的JMS商业软件和开源产品。
1.IBM MQSeries
IBM MQ系列产品提供的服务使得应用程序可以使用消息队列进行相互交流,通过一系列基于Java的API,提供了MQSeries在Java中应用开发的方法。它支持点到点和发布/订阅两种消息模式,在基本消息服务的基础上增加了结构化消息类,通过工作单元提供数据整合等内容。

2.WebLogic
WebLogic是BEA公司实现的基于工业标准的J2EE应用服务器,支持大多数企业级JavaAPI,它完全兼容JMS规范,支持点到点和发布/订阅消息模式,它具有以下一些特点:
1) 通过使用管理控制台设置JMS配置信息;
2) 支持消息的多点广播;
3) 支持持久消息存储的文件和数据库;
4) 支持XML消息,动态创建持久队列和主题。

3.SonicMQ
SonicMQ是Progress公司实现的JMS产品。除了提供基本的消息驱动服务之外,SonicMQ也提供了很多额外的企业级应用开发工具包,它具有以下一些基本特征:
1) 提供JMS规范的完全实现,支持点到点消息模式和发布/订阅消息模式;
2) 支持层次安全管理;
3) 确保消息在Internet上的持久发送;
4) 动态路由构架(DRA)使企业能够通过单个消息服务器动态的交换消息;
5) 支持消息服务器的集群。

4.Active MQ
Active MQ是一个基于Apcache 2.0 licenced发布,开放源码的JMS产品。其特点为:
1) 提供点到点消息模式和发布/订阅消息模式;
2) 支持JBoss、Geronimo等开源应用服务器,支持Spring框架的消息驱动;
3) 新增了一个P2P传输层,可以用于创建可靠的P2P JMS网络连接;
4) 拥有消息持久化、事务、集群支持等JMS基础设施服务。

5.OpenJMS
OpenJMS是一个开源的JMS规范的实现,它包含以下几个特征:
1) 它支持点到点模型和发布/订阅模型;
2) 支持同步与异步消息发送;
3) 可视化管理界面,支持Applet;
4) 能够与Jakarta Tomcat这样的Servlet容器结合;
5) 支持RMI、TCP、HTTP与SSL协议。

Weblogic9.2中JMS的相关配置
http://www.blogjava.net/heyang/archive/2009/09/24/296244.html

参考程序
http://www.blogjava.net/Files/heyang/WeblogicStandardJMS_Queue20090924101108.rar
http://www.blogjava.net/Files/heyang/WeblogicStandardJMS_Topic20090924101059.rar
http://www.blogjava.net/Files/heyang/SpringJMS_Queue20090924103214.rar
http://www.blogjava.net/Files/heyang/SpringJMS_Topic20090924103204.rar
posted @ 2009-09-24 11:04 何杨| 编辑 收藏

     摘要: 使用Spring的MDP,我们可以与JMS服务提供者通信,向队列或是主题发送或消费JMS消息,下面是两个示例程序,分别是与队列和主题通信,两个程序大同小异,主要是配置上有些许区别,其中Weblogic中的JMS相关配置部分请见“Weblogic9.2中JMS的相关配置”。 为了减少体积,这两个程序去除了库,这些库是commons-logging-1.0.4.jar,d...  阅读全文
posted @ 2009-09-24 10:45 何杨| 编辑 收藏

一.创建JMS服务器
JMS服务器是Weblogic之下的一个JMS消息处理器,我们需要首先配置好一个JMS服务器.在后面的队列或是主题的配置中,需要用到它.

一.JMS服务器的配置
1.1 首先,点击"域结构"中的"服务"->"消息传递"->"JMS服务器",准备开始建立JMS服务器.当然,在创建之前,需要点击"更改中心"中的"锁定并编辑按钮".


1.2 输入JMS服务器的名称,暂时还不需要配置持久性存储.


1.3 选择要部署此 JMS 服务器的服务器实例或可迁移目标.


1.4 JMS服务器创建成功了,点击"更改中心"中的"激活更改"按钮,激活刚才进行的修改.


1.5 激活完毕后的画面.


二.创建JMS模块.

JMS模块是JMS连接工厂ConnectionFactory,队列Queue和主题Topic的载体,因此我们在建立它们之前需要建立一个JMS模块.

2.1 点击域结构下的"服务"->"消息传递"->"JMS模块"链接,在点击"更改中心"中的"锁定并编辑"按钮,之后点击右侧的"新建"按钮,准备开始建立一个JMS模块.


2.2 输入JMS模块的名称.


2.3 选择要部署此 JMS 系统模块的服务器或群集


2.4 创建完成.


2.5 激活所进行的修改.至此,JMS模块创建完成.


三.创建JMS队列(Queue)
JMS模型有两种,一种是队列Queue,它的最主要特征是一条JMS消息只会被一个JMS消息消费者接收;另一种是主题Topic,它的最主要特征是一条JMS消息会被订阅了此主题的所有订阅者接收.我们先来看看队列的配置.

3.1 点击刚才创建好的JMS模块"MyJMSModule"链接,准备在它底下建立一个队列.


3.2 点下"锁定并编辑"按钮,点击右边的"新建"按钮,准备新建一种资源.


3.3 这个界面中列出了多种资源类型,我们现在要建立的队列,当然点击"队列"单选框了.


3.4 输入队列的JNDI名,这个很重要,队列的发送者和消费者要找到队列就要靠它.而名称可以随便写,采取默认也行.写完后点击"下一步"按钮.


3.5 点击此画面中的"新建子部署"按钮,准备新建一个子部署.


3.6 点击确定按钮,子部署名可以采用默认值.


3.7 为队列指定子部署和JMS服务器,这两个就是我们刚才和一开头配置的。之后点击“完成”按钮。


3.8 至此,JMS队列创建成功,在"更改中心"中,点击"激活更改"按钮,激活所进行的更改.


四.建立JMS主题.

4.1 JMS主题和JMS队列,JMS连接工厂都是JMS模块下的一种资源,同样,建立一个JMS主题前,仍然是点击JMS模块链接,然后也选择新建一种资源,进入如下页面后,点击"主题"单选框.


4.2 输入JMS主题的JNDI名,这很重要,主题的发布者和订阅者找到它就靠这个名,而名称则可以随意.之后点击"下一步"按钮.


4.3 进入此页面,为主题选择子部署和JMS服务器,之前,我们在建立JMS队列的时候也进行同样的配置。

4.4 JMS主题创建成功,激活所进行的修改。



五.建立连接工厂ConnectionFactory.
我们单有队列或是主题是不够的,还需要建立一个连接工厂,连接工厂用于创建到特定JMS服务提供者的消息服务的连接,它常与队列或是主题配合使用.

5.1 连接工厂也是JMS模块下的一种资源,我们同样是和前面一样,点击JMS模块链接,再选择新建按钮,进去下面的页面后,选择"连接工厂"单选框.


5.2 输入连接工厂的JNDI名,而名称则可以随意.


5.3 进入此页面后,点击完成按钮,至此连接工厂配置完成.之后选择激活所进行的更改即可.


最后,提供两个程序给大家测试一下刚才配置的正确性.
http://www.blogjava.net/Files/heyang/WeblogicStandardJMS_Topic20090924101059.rar
http://www.blogjava.net/Files/heyang/WeblogicStandardJMS_Queue20090924101108.rar

注意为了减少体积,weblogic.jar已经删除,大家请自行添加进去,另这两个程序中的队列或主题和连接工厂和上面配置的可能有大小写的不同,请大家注意修改.
posted @ 2009-09-24 10:16 何杨| 编辑 收藏

使用Ajax从后台取得反馈信息后总要在前台显示给客户看,显示方式从简单到复杂一般有三种:1.使用alert显示文字,这种方式简便易用,但容易中断用户操作,效果也太死板;2.改变页面某一区域的文字或是图片,这种使用起来也比较方便,实现也不复杂;3.使用新窗口显示,这种效果最好,但实现复杂些。本例中采用第二种方式。

Ajax提示信息出现的位置在于次级菜单栏的下方,边栏和内容栏的上方,由两部分组成:图标和文字。


消息栏的HTML代码如下:
<div id="msgDiv">
    
<span id="iconSpan">
        
<img src="web/img/icon/ok.gif" width="24px" height="24px"/>
    
</span>
    
<span id="msgSpan">
        fdsfdsfsdfsdfsdfsdfsdfsdfsdfsd
    
</span>
</div>

定义它们的CSS如下:
#msgDiv{
    display
:none;
}
#iconSpan
{
    vertical-align
:middle;
}
#msgSpan
{
    height
:100%;
    font-size
:16px;         
    color
:#404040;     
}

在没有Ajax消息前,它们整体是不表现的,通过display:none进行限制;有消息发生后,再使用JavaScript改变msgDiv,iconSpan,msgSpan的状态和内容即可,基本原理很简单,但我们不希望把代码弄乱,因此需要用类整合一下。

其中iconSpan中将显示的图标共有四种:加载图标,用于在从服务器取回响应前;完成图标,用于从服务器取得正确信息后;警告图标,用于从服务器取得错误信息后;错误图标,用于无法取得来自服务器的响应时。这样,用户在仔细查看文字前,就能大致了解发生的情况,为了使用上的方便,我特地把Ajax消息显示器组合成了一个Msger类。如下所示:
/*************************
*
*   Class:Msger
*   2009-9-9
*************************
*/
//-- Contructor
function Msger(){
    
this.msgDiv=$("msgDiv");
    
this.iconSpan=$("iconSpan");
    
this.msgSpan=$("msgSpan");
    // 这里是四种图标
    
this.icons=new Array;
    
this.icons[0]="<img src='web/img/icon/error.gif' width='24px' height='24px'/>";
    
this.icons[1]="<img src='web/img/icon/loading.gif' width='24px' height='24px'/>";
    
this.icons[2]="<img src='web/img/icon/ok.gif' width='24px' height='24px'/>";
    
this.icons[3]="<img src='web/img/icon/warning.gif' width='24px' height='24px'/>";
    
    
this.timer=new Object;
}
// 显示错误信息,出现后不消失
Msger.prototype.showErrorMsg
=function(msg){
    
this.msgDiv.style.display="block";
    
this.iconSpan.innerHTML=this.icons[0];
    
this.msgSpan.innerHTML=msg;
    
this.msgSpan.style.color="#ff0000";
}
// 显示载入信息,出现后不消失,因为很快会被其他信息替代
Msger.prototype.showLoadingMsg
=function(msg){
    
this.msgDiv.style.display="block";
    
this.iconSpan.innerHTML=this.icons[1];
    
this.msgSpan.innerHTML=msg;
    
this.msgSpan.style.color="#404040";
}
// 显示正确消息,使用后渐渐消失
Msger.prototype.showOkMsg
=function(msg){
    
this.msgDiv.style.display="block";
    
this.iconSpan.innerHTML=this.icons[2];
    
this.msgSpan.innerHTML=msg;
    
this.msgSpan.style.color="#404040";
        
    
this.timer=setTimeout("msger.fadeout()",2000);
}
// 显示警告消息,出现一段时间后消失
Msger.prototype.showWarningMsg
=function(msg){
    
this.msgDiv.style.display="block";
    
this.iconSpan.innerHTML=this.icons[3];
    
this.msgSpan.innerHTML=msg;
    
    
this.msgSpan.style.color="#f5692e";
    
    
this.timer=setTimeout("msger.hide()",5000);
}
// 隐藏
Msger.prototype.hide
=function(){
    
this.msgDiv.style.display="none";
    clearTimeout(
this.timer);
}
// 渐渐消失
Msger.prototype.fadeout
=function(){
    
var colorRGB=this.msgSpan.style.color;
    
var color=parseInt(colorRGB.slice(1,3),16)+3;
    
    
if(color<256){
        
var v1=(Math.floor(color/16)).toString(16);
        
var v2=(Math.floor(color%16)).toString(16);
        
var colorStr="#"+v1+""+v2+v1+""+v2+v1+""+v2;
        
this.msgSpan.style.color=colorStr;
        
        
this.timer=setTimeout("msger.fadeout()",120);
    }
    
else{
        
this.hide();
    }        
}

上面这些函数都好理解,fadeout函数还需要赘述一下,让文字渐渐消失是通过修改文字的颜色实现的,使它不断向纯白色靠拢就行,另外使用setTimeout调用自身的写法“msger.fadeout()”要值得注意。以上函数大家务必要理解。

使用上就比以前简化了,以下是用户列表页面的例子:
<script language="javascript">
<!--
//-- 消息显示器
var msger;

/*****************************************************
* 窗口载入时调用的启动函数
****************************************************
*/
window.onload
=function(){
    .
    
    
// 初始化消息显示器
    msger=new Msger;
    
    .
}


/*****************************************************
* 选择成员加入Session
****************************************************
*/
function selectMember(id){
    msger.showLoadingMsg(
"将选择的用户id'"+id+"'加入项目备选用户名单中");
    
    
new Ajax.Request(prjName+'SelectUsersIntoSession.do?id='+id,
           {     
               method:'get',     
               onSuccess: 
function(ajaxObj){                            
                    
var status=ajaxObj.responseXML.getElementsByTagName("status")[0].firstChild.data;
                    
// alert(ajaxObj.responseText);
                    
                    
if(status=="ok"){    
                        
var text=ajaxObj.responseXML.getElementsByTagName("text")[0].firstChild.data;
                        msger.showOkMsg(text);
                    }
                    
else{
                        
// 返回错误信息
                        var text=ajaxObj.responseXML.getElementsByTagName("text")[0].firstChild.data;
                        msger.showWarningMsg(text);
                    }
               },     
               onFailure: 
function(){ 
                   msger.showErrorMsg(
"无法取得服务器的响应");
               }   
            }
          );  
}
//-->
</script>

其中,类实例msger与前面的“this.timer=setTimeout("msger.fadeout()",120);”中的msger是呼应的,需要注意。

好了,就到这里,全体代码请到“

ProjectManager框架下载(更新时间2009年9月10日14:59:48)下载。




--全文完--



posted @ 2009-09-10 14:46 何杨| 编辑 收藏

在ProjectManager中,由于用户需要进行的操作较多,于是采用了主菜单和次级菜单的形式来扩大菜单容量。但新问题是用户不容易记住当前所处的位置,对于新手尤其是这样,因此,在主菜单和次级菜单上把当前位置标出是对用户有所帮助的,具体形式如下图所示:

具体怎么做到这一点呢?使用JS分别把主菜单和次级菜单的当前项更换一个类别就可以,首先我们看看两个菜单css定义:
#menubar{
    width
: 950px;
    height
: 30px;
    margin-left
:auto;
    margin-right
:auto;
}
#menubar ul
{
    margin
:0px;
    padding
:0px;
    list-style-type
:none;
}
#menubar li
{
    float
:left;
    display
:block;    
    height
:30px;
    line-height
:30px;
}
#menubar li.leftBlank
{
    width
:235px;
    text-align
:left; 
    font-size
:20px;         
    color
:#000000;      
}
#menubar li.rightBlank
{
    width
:235px;
    text-align
:right;   
  
}
#menubar li a
{
    width
:96px;
    
    
    font-size
:16px;         
    color
:#404040;
    text-decoration
:none;
    text-align
:center;        
    background
:#ffffff url(../img/manubar.gif) 0px 0px;
}

#menubar li a.current
{
    width
:96px;
    color
:#ffffff;
    font-weight
:bold;
    background
:#ffffff url(../img/manubar.gif) 0px -49px;
    border
:0px;
}


#submenubar
{
    width
: 950px;
    height
: 31px;
    margin-left
:auto;
    margin-right
:auto;
    background
:#000000 url(../img/submanubar.gif) 0px -1px repeat-x;
    border-left
:1px #ff7101 solid;
    border-right
:1px #ff7101 solid;
}

#submenubar ul
{
    margin
:0px;
    padding
:0px;
    list-style-type
:none;
}
#submenubar li
{
    float
:left;
    height
:31px;
    line-height
:31px;
}
#submenubar li a
{    
    padding-left
:20px;
    font-size
:12px;         
    color
:#ffffff;
    text-decoration
:none;
    text-align
:center;        
}

#submenubar li a.current
{       
    color
:#c20002;
    font-weight
:bold;          
}


#submenubar li a:hover
{
    text-decoration
:underline;
}

上面加粗的部分,就是我们要用JS赋给当前菜单项的,这就比较简单了,找出来修改className即可,代码如下:
/*****************************************************
* 设置顶级菜单中当前页所处的位置
****************************************************
*/
function setCurrentMenu(menuNumber){
    
// 设置主菜单
    var manubar=$("menubar");
    
var menu=manubar.childNodes[2].childNodes[menuNumber].firstChild;
    menu.className
="current";
}

/*****************************************************
* 设置次级菜单中当前页所处的位置
****************************************************
*/
function setCurrentSubMenu(menuNumber){
    
// 设置次级菜单
    var manubar=$("submenubar");
    
var menu=manubar.childNodes[2].childNodes[menuNumber].firstChild;
    menu.className
="current";
}

其后,在页面的窗体载入事件中调用这两个函数即可,指定menuNumber即可指定当前菜单项。userMenuIntroBody.jsp中示例调用如下:
<script language="javascript">
<!--

/*****************************************************
* 窗口载入时调用的启动函数
****************************************************
*/
window.onload
=function(){
    
// 设置当前页在主菜单和次级菜单中的位置
    setCurrentMenu(1);
    setCurrentSubMenu(
5);
    
    
// 隐藏边栏,加宽内容栏,使得内容如同全屏一样
    makeConceptFullScreen();
}
//-->
</script>
这样,就做到了是第一个主菜单,第五个次级菜单变成当前项,分别用黄色条纹图片背景和红色加粗字体标识出来。

有两点需要赘述一下,一是主菜单的第一项是第二个li节点,第一个是左空白,而次级菜单的第一项是第一个li节点;二是原始的菜单项都是没有指定current类别的,都是在具体页面中用JS指定。具体大家多看看代码。

--全文完--

posted @ 2009-09-10 10:57 何杨| 编辑 收藏

在Web项目中两栏固定宽度居中的方式较多,三栏比较少见,一栏在某些场合还是有用的,比如说有整版的表格列表。因此我们的程序有必要能在两种方式中切换。

以前我们使用的切换方式是两个页面模版,这种方式稍嫌麻烦一些,因为多了一个文件需要维护。现在使用JS也能达到同样的效果。让我们先看看siderbar和concept两个div的css定义:
#sidebar{
    margin-left
:auto;
    margin-right
:auto;    
    width
:191px;
    height
:480px;
    float
:left;
    background-color
:#fafafa ;
    border-top
:1px #e4e4e4 solid;
    border-bottom
:1px #e4e4e4 solid;
    border-left
:1px #e4e4e4 solid;    
    padding
:2px;
}
#concept
{
    margin-left
:auto;
    margin-right
:auto;
    padding
:10px;
    width
:759px;
    height
:480px;
    float
:left;
    border
:1px #e4e4e4 solid;
}
这两者之所以能并列的原因是一是向左浮动,二是二者的宽度加起来正好等于页面的总宽度950.如果我们需要变换成一栏方式,把siderbar隐藏,使concept的宽度变成950,这样不就可以了吗?这使用JavaScript很容易办到,代码如下:
    var sidebar=$("sidebar");
    sidebar.style.display
="none";
    
var concept=$("concept");
    concept.style.width
=950;

再把它包装成一个函数,在需要单栏的页面中的窗口加载事件中调用这个函数,就能把两栏变成一栏:
//--  Common.js中
function makeConceptFullScreen(){
    
var sidebar=$("sidebar");
    sidebar.style.display
="none";
    
var concept=$("concept");
    concept.style.width
=950;
}

..

//--  userMenuIntroBody.jsp中
window.onload=function(){
    
    
    
// 隐藏边栏,加宽内容栏,使得内容如同全屏一样
    makeConceptFullScreen();
}

--全文完--

posted @ 2009-09-10 10:30 何杨| 编辑 收藏

效果:


代码下载:
http://www.blogjava.net/Files/heyang/bluetable20090909095154.rar

posted @ 2009-09-09 09:52 何杨| 编辑 收藏

在本例中,我们将学习如何在Weblgic9.2中配置一个JDBC数据源并提供给一个Web应用程序使用,此程序你可以 从"http://www.blogjava.net/Files/heyang/TestWeblogicJNDI.rar"处下载然后部署到Weblogic上。

本例使用的数据库 为MySql,请确认其中有名为test的database,并建立一张employee表并填充数据,建表语句及充值语句如下:
create table employee(
   id 
char(4not null primary key,
   name 
varchar(200)
)

insert into employee ( id, name ) values ( '01''张三' );
insert into employee ( id, name ) values ( '02''张四' );
insert into employee ( id, name ) values ( '03''张五' );
insert into employee ( id, name ) values ( '04''张六' );
insert into employee ( id, name ) values ( '05''张七' );


一.首先,将应用程序访问数据库需要用到的数据库驱动包拷贝到自建域所在目录下的lib目录.


二.打开Weblogic管理控制台,在左侧的"域结构"栏中找到"服务">>"JDBC">>"数据源".然后按下上方的"锁定并编辑"按钮,再点击右边的"新建"按钮.


四.进入此页面后,输入JNDI名称,指定数据库类型为MySql,及指定数据库驱动程序。再点击下一步。


五.这个页面目前还不需要修改,直接点击"下一步"按钮.


六.进入此页面后,输入数据库参数.如下所示:指定数据库名为test(MySql5安装后就有),指定主机名为127.0.0.1也就是本机(数据库安装所在机器),端口3306,以及数据库名和密码.


七.到这个页面后可以测试一下能否连通数据库,如果反馈是"链接测试成功"则点击"完成"按钮.


八.完成后,将会进入到以下页面,点击刚配置的数据源名链接.


九.打开目标选项卡,选择服务器AdminServer,再点击"保存".这一步是将数据源绑定到服务器。


十.最后,激活所进行的更改。



十一.将TestWeblogicJNDI发布到Weblogic上后,在浏览器中查看,数据库中的内容就显示出来了.



十二.以下是TestWeblogicJNDI程序访问数据库所用的Scriptlet代码:
<%
    Context ctx 
= new InitialContext();
    DataSource ds 
= (DataSource) ctx.lookup(“MySqlDS”);//JNDI名
    Connection conn 
= ds.getConnection();
    Statement stmt 
= conn.createStatement();
    ResultSet rs 
= stmt.executeQuery("select * from employee");
    
while (rs.next()) {
     out.println(
"id:" + rs.getString("id")+"---");
     out.println(
"name:" + rs.getString("name")+"<br />");    
    }
    rs.close();
    stmt.close();
    conn.close();
    ctx.close();
%>

--全文完--
posted @ 2009-08-30 15:01 何杨| 编辑 收藏

     摘要: 选项卡可在有限的空间内显示多项内容,本文使用无序列表和Div实现了一种选项卡,这种方式的重点在于li子节点的类别,宽度,背景和下边框的设置,具体方式请参照代码。  阅读全文
posted @ 2009-08-28 20:58 何杨| 编辑 收藏

     摘要: 这是一个用fieldset,legend,div等写就的表单,和以往用表格的做法有些区别,包含了常用Web控件,外观上还可以。  阅读全文
posted @ 2009-08-27 11:55 何杨| 编辑 收藏

发布在Weblgic的Web应用应该是war包,如果你手头没有的话可以到“http://www.blogjava.net/Files/heyang/JSTLSample.rar”下载一个,这是用ant打成的一个很简单的Web应用,没有用到数据库。

一.打开Weblogic的管理控制台,点击左上方的“锁定并编辑”按钮。“锁定并编辑”按钮用来修改Weblogic的当前状态,按下后是Weblogic处于配置状态,可以进行发布,修改任务。


二.点击左侧边栏“域结构”中的“部署”链接,准备在域“hydomain”上部署一个Web应用。


三.选择右边的"upload your files"链接,准备把JSTLSample.war上传到服务器上.


四.点击"部署归档文件"右侧的"浏览"按钮,在本地找到JSTLSample.war,然后点击"下一步"按钮.


五.到这里,Weblgic告知已经上传成功,在下面的单选框中选中你刚才上传的war文件,再点击下一步按钮准备开始部署它.


六.在这个页面中,选择"将此部署安装为应用程序"单选框,再点击"下一步"按钮.


七.到这里,部署完成了,你还可以修改一下应用的名称和安全模型,如果没有什么需要变更的话点击"完成"按钮.


八.在weblogic的管理控制台中进行有效修改操作后,原来的"锁定并编辑"按钮会变成"激活更改"按钮,此后如果你确定刚才的变更操作无误应该点击"激活更改"按钮,否则点击"撤销所有更改"按钮用以取消之前的变更行为.这步操作以后很常用.


九.看到以下界面的绿色文字"已激活所欲哦更改.不需要重新启动."后,说明更改已经有效激活了.注意此时"激活更改"按钮又变成了"锁定并编辑"按钮.


十.点击"域结构"下的"部署"链接,在部署列表中找到"JSTLSample.war",选中其左边的复选框。注意现在的安装按钮是不可用的,如果要启用的话,还需要点击“锁定并编辑”按钮。


十一.选中后上方的"启动"按钮和"停止"按钮被激活,它们分别用来启动一个应用程序和停止一个已启动的应用程序.


十二.点击"启动"按钮右侧的下拉按钮,点击"为所有请求提供服务"链接.


十三.进入此界面,点击"是"按钮,确认刚才的操作.


十四.weblogic反馈说"已经将启动请求发送到了选定的部署",这说明应用已经被启动了,接下来我们可以在Web浏览器中看看效果.


十五.打开一个浏览器,在地址栏中输入"http://localhost:7001/JSTLSample",然后,部署好的Web应用界面就出现了。


-全文完-
posted @ 2009-08-27 10:21 何杨| 编辑 收藏