七郎's JavaBlog

草木竹石皆可為劒。至人之用人若鏡,不將不迎,應而不藏,故能勝物而不傷。
posts - 60, comments - 14, trackbacks - 0, articles - 0

我的环境是Oracle9i2+hibernate3
使用原配的Oracle jdbc thin 驱动不能直接对clob对象进行直接操作。
google了无数文章,仿造别人的办法,先写入一个空的clob对象,再读出,再写入真正的clob对象。不行,在BLOB blob =(BLOB) myObject.getClob 这里的类型强制转化就会出现问题。

使用hibernate官方论坛里面的重写一个数据类型的方式,则是出现String长度的错误。还试了很多种办法,均失败。

据说,Oracle 9i 里的jdbc oci驱动可以解决上面的问题,但我已经没有兴趣再去折腾了。

最后到Oracle网站上面注册了一个账户,下载了最新的Oracle 10g的jdbc驱动。
一切就正常了。其实就是Oracle原来的驱动的问题。

使用新的驱动,这个问题就不再是问题了。

Hibernate+Oracle+CLOB的读写其实只要这样做:

1.在Oracle里设置某字段为clob类型。
2.在Hibernate的配置文件里使用网上下载的Oracle 10g最新的jdbc驱动。
3.实体类里把clob字段对应的属性类型设置为String。
4.hibernate的映射文件*.hbm.xml里把该字段对应的类型该为text。

然后就可以在程序里把它当成String随便用了。 

posted @ 2007-04-16 15:36 七郎归来 阅读(651) | 评论 (2)编辑 收藏

我们有时候遇到的日期格式可能是2004-1-12 ,系统自动将月份中的0去掉了,但是有时候我们需要完整的日期格式 ,如:2004-01-12 那么怎么办呢?下面的几个函数可以轻松搞定。
'将一个一位的数字前面加零

function FillZero(str)
ttt=str
if len(str)=1 then
ttt="0" & str
end if
FillZero=ttt
end function

'转化日期,将 一位补上零 2003-1-2 --> 2003-01-02

function ConvertDate(tDate)
ttt=tDate
if isdate(tDate) then
ttt=year(tDate) & "-" & FillZero(month(tDate)) & "-" & FillZero(day(tDate))
end if
ConvertDate=ttt
end function

'输入一个日期时间串,转换成年四位,其他两位的新的日期时间串

function ConvertDateTime(tDateTime)
ttt=tDateTime
if isdate(tDateTime) then
ttt=year(tDateTime) & "-" & FillZero(month(tDateTime)) & "-" & FillZero(day(tDateTime)) & " " & FillZero(cstr(hour(tDateTime))) & ":" & FillZero(cstr(minute(tDateTime))) & ":" & FillZero(cstr(second(tDateTime)))
end if
ConvertDateTime=ttt
end function


posted @ 2007-04-16 15:36 七郎归来 阅读(150) | 评论 (0)编辑 收藏

如果你曾经用过Perl或任何其他内建正则表达式支持的语言,你一定知道用正则表达式处理文本和匹配模式是多么简单。如果你不熟悉这个术语,那么“正则表达式”(Regular Expression)就是一个字符构成的串,它定义了一个用来搜索匹配字符串的模式。
许多语言,包括Perl、PHP、Python、JavaScript和JScript,都支持用正则表达式处理文本,一些文本编辑器用正则表达式实现高级“搜索-替换”功能。那么Java又怎样呢?本文写作时,一个包含了用正则表达式进行文本处理的Java规范需求(Specification Request)已经得到认可,你可以期待在JDK的下一版本中看到它。
然而,如果现在就需要使用正则表达式,又该怎么办呢?你可以从Apache.org下载源代码开放的Jakarta-ORO库。本文接下来的内容先简要地介绍正则表达式的入门知识,然后以Jakarta-ORO API为例介绍如何使用正则表达式。
一、正则表达式基础知识
我们先从简单的开始。假设你要搜索一个包含字符“cat”的字符串,搜索用的正则表达式就是“cat”。如果搜索对大小写不敏感,单词“catalog”、“Catherine”、“sophisticated”都可以匹配。也就是说:
1.1 句点符号
假设你在玩英文拼字游戏,想要找出三个字母的单词,而且这些单词必须以“t”字母开头,以“n”字母结束。另外,假设有一本英文字典,你可以用正则表达式搜索它的全部内容。要构造出这个正则表达式,你可以使用一个通配符——句点符号“.”。这样,完整的表达式就是“t.n”,它匹配“tan”、 “ten”、“tin”和“ton”,还匹配“t#n”、“tpn”甚至“t n”,还有其他许多无意义的组合。这是因为句点符号匹配所有字符,包括空格、Tab字符甚至换行符:
1.2 方括号符号
为了解决句点符号匹配范围过于广泛这一问题,你可以在方括号(“[]”)里面指定看来有意义的字符。此时,只有方括号里面指定的字符才参与匹配。也就是说,正则表达式“t[aeio]n”只匹配“tan”、“Ten”、“tin”和“ton”。但“Toon”不匹配,因为在方括号之内你只能匹配单个字符:
1.3 “或”符号
如果除了上面匹配的所有单词之外,你还想要匹配“toon”,那么,你可以使用“|”操作符。“|”操作符的基本意义就是“或”运算。要匹配 “toon”,使用“t(a|e|i|o|oo)n”正则表达式。这里不能使用方扩号,因为方括号只允许匹配单个字符;这里必须使用圆括号“()”。圆括号还可以用来分组,具体请参见后面介绍。
1.4 表示匹配次数的符号
表一显示了表示匹配次数的符号,这些符号用来确定紧靠该符号左边的符号出现的次数:

假设我们要在文本文件中搜索美国的社会安全号码。这个号码的格式是999-99-9999。用来匹配它的正则表达式如图一所示。在正则表达式中,连字符(“-”)有着特殊的意义,它表示一个范围,比如从0到9。因此,匹配社会安全号码中的连字符号时,它的前面要加上一个转义字符“\”。

图一:匹配所有123-12-1234形式的社会安全号码

假设进行搜索的时候,你希望连字符号可以出现,也可以不出现——即,999-99-9999和999999999都属于正确的格式。这时,你可以在连字符号后面加上“?”数量限定符号,如图二所示:

图二:匹配所有123-12-1234和123121234形式的社会安全号码

下面我们再来看另外一个例子。美国汽车牌照的一种格式是四个数字加上二个字母。它的正则表达式前面是数字部分“[0-9]{4}”,再加上字母部分“[A-Z]{2}”。图三显示了完整的正则表达式。

图三:匹配典型的美国汽车牌照号码,如8836KV

1.5 “否”符号
“^”符号称为“否”符号。如果用在方括号内,“^”表示不想要匹配的字符。例如,图四的正则表达式匹配所有单词,但以“X”字母开头的单词除外。

图四:匹配所有单词,但“X”开头的除外

1.6 圆括号和空白符号
假设要从格式为“June 26, 1951”的生日日期中提取出月份部分,用来匹配该日期的正则表达式可以如图五所示:

图五:匹配所有Moth DD,YYYY格式的日期

新出现的“\s”符号是空白符号,匹配所有的空白字符,包括Tab字符。如果字符串正确匹配,接下来如何提取出月份部分呢?只需在月份周围加上一个圆括号创建一个组,然后用ORO API(本文后面详细讨论)提取出它的值。修改后的正则表达式如图六所示:

图六:匹配所有Month DD,YYYY格式的日期,定义月份值为第一个组

1.7 其它符号
为简便起见,你可以使用一些为常见正则表达式创建的快捷符号。如表二所示:
表二:常用符号

例如,在前面社会安全号码的例子中,所有出现“[0-9]”的地方我们都可以使用“\d”。修改后的正则表达式如图七所示:

图七:匹配所有123-12-1234格式的社会安全号码

二、Jakarta-ORO库
有许多源代码开放的正则表达式库可供Java程序员使用,而且它们中的许多支持Perl 5兼容的正则表达式语法。我在这里选用的是Jakarta-ORO正则表达式库,它是最全面的正则表达式API之一,而且它与Perl 5正则表达式完全兼容。另外,它也是优化得最好的API之一。
Jakarta-ORO库以前叫做OROMatcher,Daniel Savarese大方地把它赠送给了Jakarta Project。你可以按照本文最后参考资源的说明下载它。
我首先将简要介绍使用Jakarta-ORO库时你必须创建和访问的对象,然后介绍如何使用Jakarta-ORO API。
▲ PatternCompiler对象
首先,创建一个Perl5Compiler类的实例,并把它赋值给PatternCompiler接口对象。Perl5Compiler是PatternCompiler接口的一个实现,允许你把正则表达式编译成用来匹配的Pattern对象。
▲ Pattern对象
要把正则表达式编译成Pattern对象,调用compiler对象的compile()方法,并在调用参数中指定正则表达式。例如,你可以按照下面这种方式编译正则表达式“t[aeio]n”:
默认情况下,编译器创建一个大小写敏感的模式(pattern)。因此,上面代码编译得到的模式只匹配“tin”、“tan”、 “ten”和“ton”,但不匹配“Tin”和“taN”。要创建一个大小写不敏感的模式,你应该在调用编译器的时候指定一个额外的参数:
创建好Pattern对象之后,你就可以通过PatternMatcher类用该Pattern对象进行模式匹配。
▲ PatternMatcher对象
PatternMatcher对象根据Pattern对象和字符串进行匹配检查。你要实例化一个Perl5Matcher类并把结果赋值给 PatternMatcher接口。Perl5Matcher类是PatternMatcher接口的一个实现,它根据Perl 5正则表达式语法进行模式匹配:
使用PatternMatcher对象,你可以用多个方法进行匹配操作,这些方法的第一个参数都是需要根据正则表达式进行匹配的字符串:
· boolean matches(String input, Pattern pattern):当输入字符串和正则表达式要精确匹配时使用。换句话说,正则表达式必须完整地描述输入字符串。
· boolean matchesPrefix(String input, Pattern pattern):当正则表达式匹配输入字符串起始部分时使用。
· boolean contains(String input, Pattern pattern):当正则表达式要匹配输入字符串的一部分时使用(即,它必须是一个子串)。
另外,在上面三个方法调用中,你还可以用PatternMatcherInput对象作为参数替代String对象;这时,你可以从字符串中最后一次匹配的位置开始继续进行匹配。当字符串可能有多个子串匹配给定的正则表达式时,用PatternMatcherInput对象作为参数就很有用了。用 PatternMatcherInput对象作为参数替代String时,上述三个方法的语法如下:
· boolean matches(PatternMatcherInput input, Pattern pattern)
· boolean matchesPrefix(PatternMatcherInput input, Pattern pattern)
· boolean contains(PatternMatcherInput input, Pattern pattern)
三、应用实例
下面我们来看看Jakarta-ORO库的一些应用实例。
3.1 日志文件处理
任务:分析一个Web服务器日志文件,确定每一个用户花在网站上的时间。在典型的BEA WebLogic日志文件中,日志记录的格式如下:
分析这个日志记录,可以发现,要从这个日志文件提取的内容有两项:IP地址和页面访问时间。你可以用分组符号(圆括号)从日志记录提取出IP地址和时间标记。
首先我们来看看IP地址。IP地址有4个字节构成,每一个字节的值在0到255之间,各个字节通过一个句点分隔。因此,IP地址中的每一个字节有至少一个、最多三个数字。图八显示了为IP地址编写的正则表达式:

图八:匹配IP地址

IP地址中的句点字符必须进行转义处理(前面加上“\”),因为IP地址中的句点具有它本来的含义,而不是采用正则表达式语法中的特殊含义。句点在正则表达式中的特殊含义本文前面已经介绍。
日志记录的时间部分由一对方括号包围。你可以按照如下思路提取出方括号里面的所有内容:首先搜索起始方括号字符(“[”),提取出所有不超过结束方括号字符(“]”)的内容,向前寻找直至找到结束方括号字符。图九显示了这部分的正则表达式。

图九:匹配至少一个字符,直至找到“]”

现在,把上述两个正则表达式加上分组符号(圆括号)后合并成单个表达式,这样就可以从日志记录提取出IP地址和时间。注意,为了匹配“- -”(但不提取它),正则表达式中间加入了“\s-\s-\s”。完整的正则表达式如图十所示。

图十:匹配IP地址和时间标记

现在正则表达式已经编写完毕,接下来可以编写使用正则表达式库的Java代码了。
为使用Jakarta-ORO库,首先创建正则表达式字符串和待分析的日志记录字符串:
这里使用的正则表达式与图十的正则表达式差不多完全相同,但有一点例外:在Java中,你必须对每一个向前的斜杠(“\”)进行转义处理。图十不是 Java的表示形式,所以我们要在每个“\”前面加上一个“\”以免出现编译错误。遗憾的是,转义处理过程很容易出现错误,所以应该小心谨慎。你可以首先输入未经转义处理的正则表达式,然后从左到右依次把每一个“\”替换成“\\”。如果要复检,你可以试着把它输出到屏幕上。
初始化字符串之后,实例化PatternCompiler对象,用PatternCompiler编译正则表达式创建一个Pattern对象:
现在,创建PatternMatcher对象,调用PatternMatcher接口的contain()方法检查匹配情况:
接下来,利用PatternMatcher接口返回的MatchResult对象,输出匹配的组。由于logEntry字符串包含匹配的内容,你可以看到类如下面的输出:
3.2 HTML处理实例一
下面一个任务是分析HTML页面内FONT标记的所有属性。HTML页面内典型的FONT标记如下所示:
程序将按照如下形式,输出每一个FONT标记的属性:
在这种情况下,我建议你使用两个正则表达式。第一个如图十一所示,它从字体标记提取出“"face="Arial, Serif" size="+2" color="red"”。

图十一:匹配FONT标记的所有属性

第二个正则表达式如图十二所示,它把各个属性分割成名字-值对。

图十二:匹配单个属性,并把它分割成名字-值对

分割结果为:
现在我们来看看完成这个任务的Java代码。首先创建两个正则表达式字符串,用Perl5Compiler把它们编译成Pattern对象。编译正则表达式的时候,指定Perl5Compiler.CASE_INSENSITIVE_MASK选项,使得匹配操作不区分大小写。
接下来,创建一个执行匹配操作的Perl5Matcher对象。
假设有一个String类型的变量html,它代表了HTML文件中的一行内容。如果html字符串包含FONT标记,匹配器将返回true。此时,你可以用匹配器对象返回的MatchResult对象获得第一个组,它包含了FONT的所有属性:
接下来创建一个PatternMatcherInput对象。这个对象允许你从最后一次匹配的位置开始继续进行匹配操作,因此,它很适合于提取FONT标记内属性的名字-值对。创建PatternMatcherInput对象,以参数形式传入待匹配的字符串。然后,用匹配器实例提取出每一个FONT的属性。这通过指定PatternMatcherInput对象(而不是字符串对象)为参数,反复地调用PatternMatcher对象的contains ()方法完成。PatternMatcherInput对象之中的每一次迭代将把它内部的指针向前移动,下一次检测将从前一次匹配位置的后面开始。
本例的输出结果如下:
3.3 HTML处理实例二
下面我们来看看另一个处理HTML的例子。这一次,我们假定Web服务器从widgets.acme.com移到了newserver.acme.com。现在你要修改一些页面中的链接:
执行这个搜索的正则表达式如图十三所示:

图十三:匹配修改前的链接

如果能够匹配这个正则表达式,你可以用下面的内容替换图十三的链接:
注意#字符的后面加上了$1。Perl正则表达式语法用$1、$2等表示已经匹配且提取出来的组。图十三的表达式把所有作为一个组匹配和提取出来的内容附加到链接的后面。
现在,返回Java。就象前面我们所做的那样,你必须创建测试字符串,创建把正则表达式编译到Pattern对象所必需的对象,以及创建一个PatternMatcher对象:
接下来,用com.oroinc.text.regex包Util类的substitute()静态方法进行替换,输出结果字符串:
Util.substitute()方法的语法如下:
这个调用的前两个参数是以前创建的PatternMatcher和Pattern对象。第三个参数是一个Substiution对象,它决定了替换操作如何进行。本例使用的是Perl5Substitution对象,它能够进行Perl5风格的替换。第四个参数是想要进行替换操作的字符串,最后一个参数允许指定是否替换模式的所有匹配子串(Util.SUBSTITUTE_ALL),或只替换指定的次数。

posted @ 2007-04-16 15:36 七郎归来 阅读(134) | 评论 (0)编辑 收藏

<script language="javascript">
 var http_request = false;
 function send_request(url) {//初始化、指定处理函数、发送请求的函数
  http_request = false;
  //开始初始化XMLHttpRequest对象
  if(window.XMLHttpRequest) { //Mozilla 浏览器
   http_request = new XMLHttpRequest();
   if (http_request.overrideMimeType) {//设置MiME类别
    http_request.overrideMimeType('text/xml');
   }
  }
  else if (window.ActiveXObject) { // IE浏览器
   try {
    http_request = new ActiveXObject("Msxml2.XMLHTTP");
   } catch (e) {
    try {
     http_request = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (e) {}
   }
  }
  if (!http_request) { // 异常,创建对象实例失败
   window.alert("不能创建XMLHttpRequest对象实例.");
   return false;
  }
  //http_request.onreadystatechange = processRequest;
  // 确定发送请求的方式和URL以及是否同步执行下段代码
  http_request.open("post","
http://localhost/test/SaveServlet", true);//请求方式,路径,是否同异步
  http_request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  http_request.send("printNum=aa&docID=bb");//需要传的参数

 }
 // 处理返回信息的函数
    /*function processRequest() {
        if (http_request.readyState == 4) { // 判断对象状态
            if (http_request.status == 200) { // 信息已经成功返回,开始处理信息
                alert(http_request.responseText);
            } else { //页面不正常
                alert("您所请求的页面有异常。");
            }
        }
    }*/
 function userCheck() { //应用中调用此方法就会执行上面的异步方法 
   send_request('aaa');  
 }
</script> 


posted @ 2007-04-16 15:35 七郎归来 阅读(116) | 评论 (0)编辑 收藏

AJAX涉及到的7项技术中,个人认为Javascript、XMLHttpRequest、DOM、XML比较有用。

A、XMLHttpRequest对象
  XMLHttpRequest是XMLHTTP组件的对象,通过这个对象,AJAX可以像桌面应用程序一样只同服务器进行数据层面的交换,而不用每次都刷新界面,也不用每次将数据处理的工作都交给服务器来做;这样既减轻了服务器负担又加快了响应速度、缩短了用户等待的时间。

  IE5.0开始,开发人员可以在Web页面内部使用XMLHTTP ActiveX组件扩展自身的功能,不用从当前的Web页面导航就可以直接传输数据到服务器或者从服务器接收数据。,Mozilla1.0以及NetScape7则是创建继承XML的代理类XMLHttpRequest;对于大多数情况,XMLHttpRequest对象和XMLHTTP组件很相似,方法和属性类似,只是部分属性不同。

XMLHttpRequest对象初始化:<script language=”javascript”>var http_request = false;//IE浏览器http_request = new ActiveXObject("Msxml2.XMLHTTP");http_request = new ActiveXObject("Microsoft.XMLHTTP");//Mozilla浏览器http_request = new XMLHttpRequest();</script>

  XMLHttpRequest对象的方法:

方法 描述
abort()

停止当前请求

getAllResponseHeaders()

作为字符串返回完整的headers

getResponseHeader("headerLabel")

作为字符串返回单个的header标签

open("method","URL"[,asyncFlag[,"userName"[, "password"]]]) 设置未决的请求的目标 URL,方法,和其他参数
send(content) 发送请求
setRequestHeader("label", "value") 设置header并和请求一起发送

  XMLHttpRequest对象的属性:

属性 描述
onreadystatechange 状态改变的事件触发器
readyState 对象状态(integer):

 


0 = 未初始化
1 = 读取中
2 = 已读取
3 = 交互中
4 = 完成
responseText 服务器进程返回数据的文本版本
responseXML 服务器进程返回数据的兼容DOM的XML文档对象
status 服务器返回的状态码, 如:404 = "文件未找到" 、200 ="成功"
statusText 服务器返回的状态文本信息

B
、Javascript
   Javascript一直被定位为客户端的脚本语言,应用最多的地方是表单数据的校验。现在,可以通过Javascript操作XMLHttpRequest,来跟数据库打交道。


C
、DOM
   DOM(Document Object Model)是提供给HTML和XML使用的一组API,提供了文件的表述结构,并可以利用它改变其中的内容和可见物。脚本语言通过DOM才可以跟页面进行交互。Web开发人员可操作及建立文件的属性、方法以及事件都以对象来展现。比如,document就代表页面对象本身。

D、XML
  通过XML(Extensible Markup Language),可以规范的定义结构化数据,是网上传输的数据和文档符合统一的标准。用XML表述的数据和文档,可以很容易的让所有程序共享。


7.2、AJAX开发框架
  这里,我们通过一步步的解析,来形成一个发送和接收XMLHttpRequest请求的程序框架。AJAX实质上也是遵循Request/Server模式,所以这个框架基本的流程也是:对象初始化à发送请求à服务器接收à服务器返回à客户端接收à修改客户端页面内容。只不过这个过程是异步的。

A、初始化对象并发出XMLHttpRequest请求
  为了让Javascript可以向服务器发送HTTP请求,必须使用XMLHttpRequest对象。使用之前,要先将XMLHttpRequest对象实例化。之前说过,各个浏览器对这个实例化过程实现不同。IE以ActiveX控件的形式提供,而Mozilla等浏览器则直接以XMLHttpRequest类的形式提供。为了让编写的程序能够跨浏览器运行,要这样写:
if (window.XMLHttpRequest) { // Mozilla, Safari, ...       http_request = new XMLHttpRequest();  }   else if (window.ActiveXObject) { // IE       http_request = new ActiveXObject("Microsoft.XMLHTTP");}

  有些版本的Mozilla浏览器处理服务器返回的未包含XML mime-type头部信息的内容时会出错。因此,要确保返回的内容包含text/xml信息。

http_request = new XMLHttpRequest();http_request.overrideMimeType('text/xml');
B、指定响应处理函数
  接下来要指定当服务器返回信息时客户端的处理方式。只要将相应的处理函数名称赋给XMLHttpRequest对象的onreadystatechange属性就可以了。比如:

 

http_request.onreadystatechange = processRequest;

  需要指出的时,这个函数名称不加括号,不指定参数。也可以用Javascript即时定义函数的方式定义响应函数。比如:

http_request.onreadystatechange = function() { };

C、发出HTTP请求

  指定响应处理函数之后,就可以向服务器发出HTTP请求了。这一步调用XMLHttpRequest对象的open和send方法。

http_request.open('GET', 'http://www.example.org/some.file', true);http_request.send(null);

  open的第一个参数是HTTP请求的方法,为Get、Post或者Head。

  open的第二个参数是目标URL。基于安全考虑,这个URL只能是同网域的,否则会提示“没有权限”的错误。这个URL可以是任何的URL,包括需要服务器解释执行的页面,不仅仅是静态页面。目标URL处理请求XMLHttpRequest请求则跟处理普通的HTTP请求一样,比如JSP可以用request.getParameter(“”)或者request.getAttribute(“”)来取得URL参数值。

  open的第三个参数只是指定在等待服务器返回信息的时间内是否继续执行下面的代码。如果为True,则不会继续执行,直到服务器返回信息。默认为True。

  按照顺序,open调用完毕之后要调用send方法。send的参数如果是以Post方式发出的话,可以是任何想传给服务器的内容。不过,跟form一样,如果要传文件或者Post内容给服务器,必须先调用setRequestHeader方法,修改MIME类别。如下:

http_request.setRequestHeader(“Content-Type”,”application/x-www-form-urlencoded”);

  这时资料则以查询字符串的形式列出,作为sned的参数,例如:

name=value&anothername=othervalue&so=on
D、处理服务器返回的信息
  在第二步我们已经指定了响应处理函数,这一步,来看看这个响应处理函数都应该做什么。

  首先,它要检查XMLHttpRequest对象的readyState值,判断请求目前的状态。参照前文的属性表可以知道,readyState值为4的时候,代表服务器已经传回所有的信息,可以开始处理信息并更新页面内容了。如下:

if (http_request.readyState == 4) {    // 信息已经返回,可以开始处理} else {    // 信息还没有返回,等待}

  服务器返回信息后,还需要判断返回的HTTP状态码,确定返回的页面没有错误。所有的状态码都可以在W3C的官方网站上查到。其中,200代表页面正常。

if (http_request.status == 200) {    // 页面正常,可以开始处理信息} else {    // 页面有问题}

  XMLHttpRequest对成功返回的信息有两种处理方式:
   responseText:将传回的信息当字符串使用;
   responseXML:将传回的信息当XML文档使用,可以用DOM处理。

E、一个初步的开发框架
  总结上面的步骤,我们整理出一个初步的可用的开发框架,供以后调用;这里,将服务器返回的信息用window.alert以字符串的形式显示出来:
<script language="javascript">	var http_request = false;	function send_request(url) {//初始化、指定处理函数、发送请求的函数		http_request = false;		//开始初始化XMLHttpRequest对象		if(window.XMLHttpRequest) { //Mozilla 浏览器			http_request = new XMLHttpRequest();			if (http_request.overrideMimeType) {//设置MiME类别				http_request.overrideMimeType("text/xml");			}		}		else if (window.ActiveXObject) { // IE浏览器			try {				http_request = new ActiveXObject("Msxml2.XMLHTTP");			} catch (e) {				try {					http_request = new ActiveXObject("Microsoft.XMLHTTP");				} catch (e) {}			}		}		if (!http_request) { // 异常,创建对象实例失败			window.alert("不能创建XMLHttpRequest对象实例.");			return false;		}		http_request.onreadystatechange = processRequest;		// 确定发送请求的方式和URL以及是否同步执行下段代码		http_request.open("GET", url, true);		http_request.send(null);	}	// 处理返回信息的函数    function processRequest() {        if (http_request.readyState == 4) { // 判断对象状态            if (http_request.status == 200) { // 信息已经成功返回,开始处理信息                alert(http_request.responseText);            } else { //页面不正常                alert("您所请求的页面有异常。");            }        }    }</script>
7.3、简单的示例
  接下来,我们利用上面的开发框架来做两个简单的应用。

A、数据校验
  在用户注册的表单中,经常碰到要检验待注册的用户名是否唯一。传统的做法是采用window.open的弹出窗口,或者window. showModalDialog的对话框。不过,这两个都需要打开窗口。采用AJAX后,采用异步方式直接将参数提交到服务器,用window.alert将服务器返回的校验信息显示出来。代码如下:

  在<body></body>之间增加一段form表单代码:

<form name="form1" action="" method="post">
用户名:<input type="text" name="username" value="">&nbsp;
<input type="button" name="check" value="唯一性检查" onClick="userCheck()">
<input type="submit" name="submit" value="提交">
</form>

  在开发框架的基础上再增加一个调用函数:

function userCheck() {	var f = document.form1;	var username = f.username.value;	if(username=="") {		window.alert("用户名不能为空。");		f.username.focus();		return false;	}	else {		send_request('sample1_2.jsp?username='+username);	}}

  看看sample1_2.jsp做了什么:

<%@ page contentType="text/html; charset=gb2312" errorPage="" %><%String username = request.getParameter("username");if("educhina".equals(username)) out.print("用户名已经被注册,请更换一个用户名。");else out.print("用户名尚未被使用,您可以继续。");%>

  运行一下,嗯,没有弹出窗口,没有页面刷新,跟预想的效果一样。如果需要的话,可以在sample1_2.jsp中实现更复杂的功能。最后,只要将反馈信息打印出来就可以了。


B、级联菜单
  我们在第五部分提到利用AJAX改进级联菜单的设计。接下来,我们就演示一下如何“按需取数据”。

  首先,在<body></body>中间增加如下HTML代码:

<table width="200" border="0" cellspacing="0" cellpadding="0">    <tr>        <td height="20">			<a href="javascript:void(0)" onClick="showRoles('pos_1')">经理室</a>		</td>    </tr>    <tr style="display:none">        <td height="20" id="pos_1"> </td>    </tr>    <tr>        <td height="20">			<a href="javascript:void(0)" onClick="showRoles('pos_2')">开发部</a>		</td>    </tr>    <tr style="display:none ">        <td id="pos_2" height="20"> </td>    </tr></table>

  在框架的基础上增加一个响应函数showRoles(obj):

//显示部门下的岗位function showRoles(obj) {	document.getElementById(obj).parentNode.style.display = "";	document.getElementById(obj).innerHTML = "正在读取数据..."	currentPos = obj;	send_request("sample2_2.jsp?playPos="+obj);}

  修改框架的processRequest函数:

// 处理返回信息的函数function processRequest() {  if (http_request.readyState == 4) { // 判断对象状态    if (http_request.status == 200) { // 信息已经成功返回,开始处理信息	document.getElementById(currentPos).innerHTML = http_request.responseText;    } else { //页面不正常      alert("您所请求的页面有异常。");    }  }}

  最后就是smaple2_2.jsp了:

<%@ page contentType="text/html; charset=gb2312" errorPage="" %>
<%
String playPos = request.getParameter("playPos");if("pos_1".equals(playPos)) out.print("&nbsp;&nbsp;总经理<br>&nbsp;&nbsp;副总经理");else if("pos_2".equals(playPos)) out.println("&nbsp;&nbsp;总工程师<br>&nbsp;&nbsp;软件工程师");
%>

  运行一下看看效果:

7.4、文档对象模型(DOM)
  文档对象模型(DOM)是表示文档(比如HTML和XML)和访问、操作构成文档的各种元素的应用程序接口(API)。一般的,支持Javascript的所有浏览器都支持DOM。本文所涉及的DOM,是指W3C定义的标准的文档对象模型,它以树形结构表示HTML和XML文档,定义了遍历这个树和检查、修改树的节点的方法和属性。

7.4.1、DOM眼中的HTML文档:树
  在DOM眼中,HTML跟XML一样是一种树形结构的文档,<html>是根(root)节点,<head>、<title>、<body>是<html>的子(children)节点,互相之间是兄弟(sibling)节点;<body>下面才是子节点<table>、<span>、<p>等等。如下图:

  

  这个是不是跟XML的结构有点相似呢。不同的是,HTML文档的树形主要包含表示元素、标记的节点和表示文本串的节点。

7.4.2、HTML文档的节点
  DOM下,HTML文档各个节点被视为各种类型的Node对象。每个Node对象都有自己的属性和方法,利用这些属性和方法可以遍历整个文档树。由于HTML文档的复杂性,DOM定义了nodeType来表示节点的类型。这里列出Node常用的几种节点类型:
接口 nodeType常量 nodeType值 备注
Element Node.ELEMENT_NODE 1 元素节点
Text Node.TEXT_NODE 3 文本节点
Document Node.DOCUMENT_NODE 9 document
Comment Node.COMMENT_NODE 8 注释的文本
DocumentFragment Node.DOCUMENT_FRAGMENT_NODE 11 document片断
Attr Node.ATTRIBUTE_NODE 2 节点属性

  DOM树的根节点是个Document对象,该对象的documentElement属性引用表示文档根元素的Element对象(对于HTML文档,这个就是<html>标记)。Javascript操作HTML文档的时候,document即指向整个文档,<body>、<table>等节点类型即为Element。Comment类型的节点则是指文档的注释。具体节点类型的含义,请参考《Javascript权威指南》,在此不赘述。

  Document定义的方法大多数是生产型方法,主要用于创建可以插入文档中的各种类型的节点。常用的Document方法有:

方法 描述
createAttribute() 用指定的名字创建新的Attr节点。
createComment() 用指定的字符串创建新的Comment节点。
createElement() 用指定的标记名创建新的Element节点。
createTextNode() 用指定的文本创建新的TextNode节点。
getElementById() 返回文档中具有指定id属性的Element节点。
getElementsByTagName() 返回文档中具有指定标记名的所有Element节点。

  对于Element节点,可以通过调用getAttribute()、setAttribute()、removeAttribute()方法来查询、设置或者删除一个Element节点的性质,比如<table>标记的border属性。下面列出Element常用的属性:

属性 描述
tagName 元素的标记名称,比如<p>元素为P。HTML文档返回的tabName均为大写。

  Element常用的方法:

方法 描述
getAttribute() 以字符串形式返回指定属性的值。
getAttributeNode() 以Attr节点的形式返回指定属性的值。
getElementsByTabName() 返回一个Node数组,包含具有指定标记名的所有Element节点的子孙节点,其顺序为在文档中出现的顺序。
hasAttribute() 如果该元素具有指定名字的属性,则返回true。
removeAttribute() 从元素中删除指定的属性。
removeAttributeNode() 从元素的属性列表中删除指定的Attr节点。
setAttribute() 把指定的属性设置为指定的字符串值,如果该属性不存在则添加一个新属性。
setAttributeNode() 把指定的Attr节点添加到该元素的属性列表中。

  Attr对象代表文档元素的属性,有name、value等属性,可以通过Node接口的attributes属性或者调用Element接口的getAttributeNode()方法来获取。不过,在大多数情况下,使用Element元素属性的最简单方法是getAttribute()和setAttribute()两个方法,而不是Attr对象。

7.4.3、使用DOM操作HTML文档
  Node对象定义了一系列属性和方法,来方便遍历整个文档。用parentNode属性和childNodes[]数组可以在文档树中上下移动;通过遍历childNodes[]数组或者使用firstChild和nextSibling属性进行循环操作,也可以使用lastChild和previousSibling进行逆向循环操作,也可以枚举指定节点的子节点。而调用appendChild()、insertBefore()、removeChild()、replaceChild()方法可以改变一个节点的子节点从而改变文档树。

  需要指出的是,childNodes[]的值实际上是一个NodeList对象。因此,可以通过遍历childNodes[]数组的每个元素,来枚举一个给定节点的所有子节点;通过递归,可以枚举树中的所有节点。下表列出了Node对象的一些常用属性和方法:

  Node对象常用属性:

属性 描述
attributes 如果该节点是一个Element,则以NamedNodeMap形式返回该元素的属性。
childNodes 以Node[]的形式存放当前节点的子节点。如果没有子节点,则返回空数组。
firstChild 以Node的形式返回当前节点的第一个子节点。如果没有子节点,则为null。
lastChild 以Node的形式返回当前节点的最后一个子节点。如果没有子节点,则为null。
nextSibling 以Node的形式返回当前节点的兄弟下一个节点。如果没有这样的节点,则返回null。
nodeName 节点的名字,Element节点则代表Element的标记名称。
nodeType 代表节点的类型。
parentNode 以Node的形式返回当前节点的父节点。如果没有父节点,则为null。
previousSibling 以Node的形式返回紧挨当前节点、位于它之前的兄弟节点。如果没有这样的节点,则返回null。

  Node对象常用方法:

方法 描述
appendChild() 通过把一个节点增加到当前节点的childNodes[]组,给文档树增加节点。
cloneNode() 复制当前节点,或者复制当前节点以及它的所有子孙节点。
hasChildNodes() 如果当前节点拥有子节点,则将返回true。
insertBefore() 给文档树插入一个节点,位置在当前节点的指定子节点之前。如果该节点已经存在,则删除之再插入到它的位置。
removeChild() 从文档树中删除并返回指定的子节点。
replaceChild() 从文档树中删除并返回指定的子节点,用另一个节点替换它。

  接下来,让我们使用上述的DOM应用编程接口,来试着操作HTML文档。

  A、遍历文档的节点

  DOM把一个HTML文档视为树,因此,遍历整个树是应该是家常便饭。跟之前说过的一样,这里我们提供两个遍历树的例子。通过它,我们能够学会如何使用childNodes[]和firstChile、lastChild、nextSibling、previousSibling遍历整棵树。

  例子1-- sample3_1.htm:
  这个例子使用了childNodes[]和递归方式来遍历整个文档,统计文档中出现的Element元素总数,并把Element标记名全部打印出来。需要特别注意的是,在使用DOM时,必须等文档被装载完毕再执行遍历等行为操作文档。sample3_1.htm具体代码如下:

<html><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312"><title>无标题文档</title><script language="javascript">var elementName = ""; //全局变量,保存Element标记名,使用完毕要清空function countTotalElement(node) { //参数node是一个Node对象	var total = 0;	if(node.nodeType == 1) { //检查node是否为Element对象		total++;			//如果是,计数器加1		elementName = elementName + node.tagName + "\r\n"; //保存标记名	}	var childrens = node.childNodes;		//获取node的全部子节点	for(var i=0;i<childrens.length;i++) {		total += countTotalElement(childrens[i]); //在每个子节点上进行递归操作	}	return total;}</script></head><body><a href="javascript:void(0)" onClick="alert('标记总数:' + countTotalElement(document) + '\r\n

全部标记如下:\r\n' + elementName);elementName='';">开始统计</a></body></html>

  例子2 – sample3_2.htm:
  接下来使用firstChile、lastChild、nextSibling、previousSibling遍历整个文档树。修改一下countTotalElement函数,其他跟sample3_1.htm一样:

function countTotalElement(node) { //参数node是一个Node对象	var total = 0;	if(node.nodeType == 1) { //检查node是否为Element对象		total++;			//如果是,计数器加1		elementName = elementName + node.tagName + "\r\n"; //保存标记名	}	var childrens = node.childNodes;		//获取node的全部子节点	for(var m=node.firstChild; m!=null;m=m.nextSibling) {		total += countTotalElement(m); //在每个子节点上进行递归操作	}	return total;}

  B、搜索文档中特定的元素
  在使用DOM的过程中,有时候需要定位到文档中的某个特定节点,或者具有特定类型的节点列表。这种情况下,可以调用Document对象的getElementsByTagName()和getElementById()方法来实现。

  document.getElementsByTagName()返回文档中具有指定标记名的全部Element节点数组(也是NodeList类型)。Element出现在数组中的顺序就是他们在文档中出现的顺序。传递给getElementsByTagName()的参数忽略大小写。比如,想定位到第一个<table>标记,可以这样写:document.getElementsByTagName(“table”)[0]。例外的,可以使用document.body定位到<body>标记,因为它是唯一的。

  getElementsByTagName()返回的数组取决于文档。一旦文档改变,返回结果也立即改变。相比,getElementById()则比较灵活,可以随时定位到目标,只是要实现给目标元素一个唯一的id属性值。这个我们在《AJAX开发简略》的“级联菜单”例子中已经使用过了。

  Element对象也支持getElementsByTagName()和getElementById()。不同的是,搜索领域只针对调用者的子节点。

  C、修改文档内容
  遍历整棵文档树、搜索特定的节点,我们最终目的之一是要修改文档内容。接下来的三个例子将使用Node的几个常用方法,来演示如何修改文档内容。

  例子3 -- sample4_1.htm:
  这个例子包含三个文本节点和一个按钮。点击按钮后,三个文本节点和按钮的顺序将被颠倒。程序使用了Node的appendChild()和removeChild()方法。

<html><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312"><title>无标题文档</title><script language="javascript">	function reverseNode(node) { // 颠倒节点node的顺序		var kids = node.childNodes; //获取子节点列表		var kidsNum = kids.length; //统计子节点总数		for(var i=kidsNum-1;i>=0;i--) { //逆向遍历子节点列表			var c = node.removeChild(kids[i]); //删除指定子节点,保存在c中			node.appendChild(c); //将c放在新位置上		}	}</script></head><body><p>第一行</p><p>第二行</p><p>第三行</p><p><input type="button" name="reverseGo" value="颠倒" onClick="reverseNode(document.body)"></p></body></html>

  例子4-- sample4_2.htm:
  例子1通过直接操作body的子节点来修改文档。在HTML文档中,布局和定位常常通过表格<table>来实现。因此,例子4将演示操作表格内容,将表格的四个单元行顺序颠倒。如果没有使用<tbody>标签,则<table>把全部的<tr>当做是属于一个子节点<tbody>,所以我们采用数组缓存的方式,把行数据颠倒一下。这个例子同时也演示了如何使用DOM创建表格单元行。

<html><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312"><title>无标题文档</title><script language="javascript">function reverseTable() {	var node = document.getElementsByTagName("table")[0]; //第一个表格	var child = node.getElementsByTagName("tr"); //取得表格内的所有行	var newChild = new Array(); //定义缓存数组,保存行内容	for(var i=0;i<child.length;i++) {		newChild[i] = child[i].firstChild.innerHTML; 	}	node.removeChild(node.childNodes[0]); //删除全部单元行	var header = node.createTHead(); //新建表格行头	for(var i=0;i<newChild.length;i++) {		var headerrow = header.insertRow(i); //插入一个单元行		var cell = headerrow.insertCell(0); //在单元行中插入一个单元格		//在单元格中创建TextNode节点		cell.appendChild(document.createTextNode(newChild[newChild.length-i-1]));	}}</script></head><body><table width="200" border="1" cellpadding="4" cellspacing="0">    <tr>        <td height="25">第一行</td>    </tr>    <tr>        <td height="25">第二行</td>    </tr>    <tr>        <td height="25">第三行</td>    </tr>    <tr>        <td height="25">第四行</td>    </tr></table><br><input type="button" name="reverse" value="开始颠倒" onClick="reverseTable()"></body></html>

  例子5 -- sample4_3.htm:
  正如我们在Node节点介绍部分所指出的那样,appendChild()、replaceChild()、removeChild()、insertBefore()方法会立即改变文档的结构。下面的例子包含两个表格,我们试着把表格二的内容替换表格一的内容。

<html><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312"><title>无标题文档</title><script language="javascript">function replaceContent() {	var table1 = document.getElementsByTagName("table")[0];	var table2 = document.getElementsByTagName("table")[1];	var kid1 = table1.firstChild.firstChild.firstChild; //定位到<td>节点	var kid2 = table2.firstChild.firstChild.firstChild; //定位到<td>节点	var repKid = kid2.firstChild; //定位到表格二<td>内含的TextNode节点	try {		//用表格二的单元格内容替换表格一的单元格内容,表格二变成没有单元格内容		kid1.replaceChild(repKid,kid1.firstChild); 		//下面注释如果开放,将出现object error,因为表格二已经被改变		//kid2.replaceChild(kid1.firstChild,kid2.firstChild);	}catch(e){		alert(e);	}}</script></head><body><table width="200" border="1" cellspacing="0" cellpadding="0"><tbody>    <tr>        <td>表格一</td>    </tr></tbody></table><br><table width="200" border="1" cellspacing="0" cellpadding="0"><tbody>    <tr>        <td>表格二</td>    </tr></tbody></table><br><input type="button" name="replaceNode" value="替换" onClick="replaceContent()"></body></html>

  注意,当执行kid1.replaceChild(repKid,kid1.firstChild);的时候,table2的子节点已经被转移到table1了,table2已经没有子节点,不能再调用table2的子节点。看看代码的注释,试着运行一下,应该就知道文档是怎么改变的了。

  D、往文档添加新内容
  在学会遍历、搜索、修改文档之后,我们现在试着网文档添加新的内容。其实没有什么新意,只是利用我们上述提到的Node的属性和方法而已,还是操作<table>标记的内容。有新意的是,我们要实现一个留言簿。是的,留言簿,你可以往里面留言,只是不能刷新噢。

  例子6 – sample5_1.htm:

<html><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312"><title>无标题文档</title><script language="javascript">function insertStr() {	var f = document.form1;	var value = f.str.value;	if(value!="") {		// 从最终的TextNode节点开始,慢慢形成<tbody>结构		var text = document.createTextNode(value); //新建一个TextNode节点		var td = document.createElement("td"); //新建一个td类型的Element节点		var tr = document.createElement("tr"); //新建一个tr类型的Element节点		var tbody = document.createElement("tbody"); //新建一个tbody类型的Element节点		td.appendChild(text); //将节点text加入td中		tr.appendChild(td); //将节点td加入tr中		tbody.appendChild(tr); //将节点tr加入tbody中		var parNode = document.getElementById("table1"); //定位到table上		parNode.insertBefore(tbody,parNode.firstChild); //将节点tbody插入到节点顶部		//parNode.appendChild(tbody); //将节点tbody加入节点尾部	}}</script></head><body><form name="form1" method="post" action="">    <input name="str" type="text" id="str" value="">    <input name="insert" type="button" id="insert" value="留言" onClick="insertStr()"></form><table width="400" border="1" cellspacing="0" cellpadding="0" id="table1"><tbody>    <tr>        <td height="25">网友留言列表:</td>    </tr></tbody></table></body></html>

  我们之前说过,<table>的子节点是<tbody>,<tbody>的子节点才是<tr>,<tr>是<td>的父节点,最后<td>内部的TextNode节点。所以,往<table>增加单元格行要逐级形成,就像往树里面添加一个枝桠一样,要有叶子有径。看看,这个留言簿是不是很简单啊。这个例子同时也演示了往<table>表格标记里面增加内容的另一种方法。


  E、使用DOM操作XML文档
  在数据表示方面,XML文档更加结构化。DOM在支持HTML的基础上提供了一系列的API,支持针对XML的访问和操作。利用这些API,我们可以从XML中提取信息,动态的创建这些信息的HTML呈现文档。处理XML文档,通常遵循“加载XML文档à提取信息à加工信息à创建HTML文档”的过程。下面的例子演示了如何加载并处理XML文档。

  这个例子包含两个JS函数。loadXML()负责加载XML文档,其中既包含加载XML文档的2级DOM代码,又有实现同样操作的Microsoft专有API代码。需要提醒注意的是,文档加载过程不是瞬间完成的,所以对loadXML()的调用将在加载文档完成之前返回。因此,需要传递给loadXML()一个引用,以便文档加载完成后调用。

  例子中的另外一个函数makeTable(),则在XML文档加载完毕之后,使用最后前介绍过的DOM应用编程接口读取XML文档信息,并利用这些信息形成一个新的table表格。

  例子7 -- sample6_1.htm:

<html><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312"><title>无标题文档</title><script language="javascript">function loadXML(handler) {	var url = "employees.xml";	if(document.implementation&&document.implementation.createDocument) {		var xmldoc = document.implementation.createDocument("", "", null);		xmldoc.onload =  handler(xmldoc, url);		xmldoc.load(url);	}	else if(window.ActiveXObject) {		var xmldoc = new ActiveXObject("Microsoft.XMLDOM");		xmldoc.onreadystatechange = function() {			if(xmldoc.readyState == 4) handler(xmldoc, url);		}		xmldoc.load(url);	}}function makeTable(xmldoc, url) {	var table = document.createElement("table");	table.setAttribute("border","1");	table.setAttribute("width","600");	table.setAttribute("class","tab-content");	document.body.appendChild(table);	var caption = "Employee Data from " + url;	table.createCaption().appendChild(document.createTextNode(caption));	var header = table.createTHead();	var headerrow = header.insertRow(0);	headerrow.insertCell(0).appendChild(document.createTextNode("姓名"));	headerrow.insertCell(1).appendChild(document.createTextNode("职业"));	headerrow.insertCell(2).appendChild(document.createTextNode("工资"));	var employees = xmldoc.getElementsByTagName("employee");	for(var i=0;i<employees.length;i++) {		var e = employees[i];		var name = e.getAttribute("name");		var job = e.getElementsByTagName("job")[0].firstChild.data;		var salary = e.getElementsByTagName("salary")[0].firstChild.data;		var row = table.insertRow(i+1);		row.insertCell(0).appendChild(document.createTextNode(name));		row.insertCell(1).appendChild(document.createTextNode(job));		row.insertCell(2).appendChild(document.createTextNode(salary));	}}</script><link href="css/style.css" rel="stylesheet" type="text/css"></head><body onLoad="loadXML(makeTable)"></body></html>
供读取调用的XML文档 – employees.xml:
<?xml version="1.0" encoding="gb2312"?><employees> <employee name="J.Doe"> <job>Programmer</job> <salary>32768</salary> </employee> <employee name="A.Baker"> <job>Sales</job> <salary>70000</salary> </employee> <employee name="Big Cheese"> <job>CEO</job> <salary>100000</salary> </employee></employees>
7.5、处理XML文档
  脱离XML文档的AJAX是不完整的。在本部分未完成之前,有读者说AJAX改名叫AJAH(H应该代表HTML吧)比较合适。应该承认,XML文档在数据的结构化表示以及接口对接上有先天的优势,但也不是所有的数据都应该用XML表示。有些时候单纯的文本表示可能会更合适。下面先举个AJAX处理返回XML文档的例子再讨论什么时候使用XML。

7.5.1、处理返回的XML
  
例子8 -- sample7_1.htm:
  在这个例子中,我们采用之前确定的AJAX开发框架,稍微修改一下body内容和processRequest的相应方式,将先前的employees.xml的内容读取出来并显示。

  body的内容如下:

<input type="button" name="read" value="读取XML" onClick="send_request('employees.xml')">processRequest()方法修改如下:	// 处理返回信息的函数    function processRequest() {        if (http_request.readyState == 4) { // 判断对象状态            if (http_request.status == 200) { // 信息已经成功返回,开始处理信息		var returnObj = http_request.responseXML;		var xmlobj = http_request.responseXML;		var employees = xmlobj.getElementsByTagName("employee");		var feedbackStr = "";		for(var i=0;i<employees.length;i++) { // 循环读取employees.xml的内容		var employee = employees[i];		feedbackStr += "员工:" + employee.getAttribute("name");		feedbackStr += " 职位:" + employee.getElementsByTagName("job")[0].firstChild.data;		feedbackStr += " 工资:" + employee.getElementsByTagName("salary")[0].firstChild.data;		feedbackStr +=  "\r\n";				}				alert(feedbackStr);            } else { //页面不正常                alert("您所请求的页面有异常。");            }        }}

  运行一下,看来效果还不错:

7.5.2、选择合适的XML生成方式

  现在的web应用程序往往采用了MVC三层剥离的设计方式。XML作为一种数据保存、呈现、交互的文档,其数据往往是动态生成的,通常由JavaBean转换过来。由JavaBean转换成XML文档的方式有好几种,选择合适的转换方式往往能达到事半功倍的效果。下面介绍两种常用的方式,以便需要的时候根据情况取舍。

  A、类自行序列化成XML
  类自行序列化成XML即每个类都实现自己的toXML()方法,选择合适的API、适当的XML结构、尽量便捷的生成逻辑快速生成相应的XML文档。显然,这种方式必须要求每个类编写专门的XML生成代码,每个类只能调用自己的toXML()方法。应用诸如JDOM等一些现成的API,可以减少不少开发投入。例子9是一个利用JDOM的API形成的toXML()方法。

  例子9 -- toXml() 的 JDOM 实现 -- Employ类的toXml()方法:

public Element toXml() {  	Element employee = new Element(“employee”);	Employee.setAttribute(“name”,name);	Element jobE = new Element(“job”).addContent(job);	employee.setContent(jobE);	Element salaryE = new Element(“salary”).addContent(salary);	employee.setContent(salaryE);	return employee;}

  JDOM提供了现成的API,使得序列化成XML的工作更加简单,我们只需要把toXML()外面包装一个Document,然后使用XMLOutputter把文档写入servlet就可以了。toXml()允许递归调用其子类的toXML()方法,以便生成包含子图的XML文档。

  使用类自行序列化成XML的方式,要每个类都实现自己的toXML()方法,而且存在数据模型与视图耦合的问题,即要么为每个可能的视图编写独立的toXML()方法,要么心甘情愿接收冗余的数据,一旦数据结构或者文档发生改变,toXML()就要做必要的修改。

  B、页面模板生成XML方式
  一般的,可以采用通用的页面模板技术来生成XML文档,这个XML文档可以符合任何需要的数据模型,供AJAX灵活的调用。另外,模板可以采用任何标记语言编写,提高工作效率。下面是一个采用Struts标签库编写的XML文档,输出之前提到的employees.xml:

  Sample8_2.jsp:

<%@ page contentType="application/xml; charset=gb2312" import="Employee"%><%@ page import="java.util.Collection,java.util.ArrayList"%><?xml version="1.0"?><%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %><%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%><%Employee em1 = new Employee();em1.setName("J.Doe");em1.setJob("Programmer");em1.setSalary("32768");Employee em2 = new Employee();em2.setName("A.Baker");em2.setJob("Sales");em2.setSalary("70000");Employee em3 = new Employee();em3.setName("Big Cheese");em3.setJob("CEO");em3.setSalary("100000");Collection employees = new ArrayList();employees.add(em1);employees.add(em2);employees.add(em3);pageContext.setAttribute("employees",employees);%><employees><logic:iterate name="employees" id="employee">	<employee name="<bean:write name='employee' property='name'/>">		<job><bean:write name="employee" property="job"/></job>		<salary><bean:write name="employee" property="salary"/></salary>	</employee></logic:iterate></employees>

  

  采用页面模板生成XML方式,需要为每个需要的的数据模型建立一个对立的JSP文件,用来生成符合规范的XML文档,而不能仅仅在类的toXML()方法中组织对象图来实现。不过,倒是可以更加方便的确保标记匹配、元素和属性的顺序正确以及XML实体正确转义。

  参考资料中Philip McCarthy的文章还描述了一种Javascript对象标注的生成方式,本文在此不赘述。有兴趣的读者可以自行查看了解。

7.5.3、如何在使用XML还是普通文本间权衡
  使用XML文档确实有其方便之处。不过XML文档的某些问题倒是要考虑一下,比如说延迟,即服务器不能立即解析XML文档成为DOM模型。这个问题在一定程度上会影响AJAX要求的快速反应能力。另外,某些情况下我们并不需要使用XML来表示数据,比如说数据足够简单成只有一个字符串而已。就好像我们之前提到的数据校验和级联菜单的例子一样。所以,个人认为在下面这些情况下可以考虑使用XML来作为数据表示的介质:
  • 数据比较复杂,需要用XML的结构化方式来表示
  • 不用考虑带宽和处理效率支出
  • 与系统其他API或者其他系统交互,作为一种数据中转中介
  • 需要特定各式的输出视图而文本无法表示的

  总之,要认真评估两种表示方式的表示成本和效率,选择合适的合理的表示方式。

posted @ 2007-04-16 15:35 七郎归来 阅读(133) | 评论 (0)编辑 收藏

Hibernate提供了HQL,方便查询的编写。但是在某些情况下,我更喜欢用Criteria,因为它的语义非常明确。

在处理对象关联的时候,经常要对对象下的某个集合字段进行条件限制。比如下面的类:

public class MainClass{  protected long id;  protected int type;  protected Set<SubClass> subs= new HashSet<SubClass>();  ......  getter/setter}  public class SubClass{  protected long id;  protected int value;  protected Set<MainClass> ms = new HashSet<MainClass>();  ...... getter/setter} 

在初始化数据中,假设MainClass的实例m1含有SubClass的实例s1,s2,s3;MainClass的实例m2含有SubClass的实例s2,s3,s4。

而其中s1,s2,s3,s4的value分别是1,2,3,4 

现在要查询出 MainClass中SubClass集合含有SubClass实例value为2的的MainClass实例并且type为1,可以使用下面的查询方法:

  DetachedCriteria criteria = DetachedCriteria        .forClass(MainClass.class);  criteria.add(        Restrictions.eq("type", new Integer(1)))        .createAlias("subs", "s").add(             Restrictions.eq("s.value", new Integer(2)));

执行此查询对象后会得到符合条件的MainClass实例。

需要注意的是在获取的MainClass实例中,subs是完全的记录集,而不是经过过滤的记录集,也就是相当于根据MainClass的ID获取的完整实例一样。

ps: 

  如果需要过滤subs的记录集,需要使用额外的过滤方法,请参考Hibernate的具体实现。

  使用HQL也可以很方便地实现,但是需要给出完整的join标记,不如createAlias来得方面和直观。 

posted @ 2007-04-16 15:35 七郎归来 阅读(189) | 评论 (0)编辑 收藏

Hibernate3提供了DetachedCriteria,使得我们可以在Web层构造detachedCriteria,然后调用业务层Bean,进行动态条件查询,根据这一功能,我设计了通用的抽象Bean基类和分页类支持,代码来自于Quake Wang的javaeye-core包的相应类,然后又做了很多修改。

分页支持类:

java代码: 


package com.javaeye.common.util;

import java.util.List;

public class PaginationSupport {

        public final static int PAGESIZE = 30;

        private int pageSize = PAGESIZE;

        private List items;

        private int totalCount;

        private int[] indexes = new int[0];

        private int startIndex = 0;

        public PaginationSupport(List items, int totalCount) {
                setPageSize(PAGESIZE);
                setTotalCount(totalCount);
                setItems(items);               
                setStartIndex(0);
        }

        public PaginationSupport(List items, int totalCount, int startIndex) {
                setPageSize(PAGESIZE);
                setTotalCount(totalCount);
                setItems(items);               
                setStartIndex(startIndex);
        }

        public PaginationSupport(List items, int totalCount, int pageSize, int startIndex) {
                setPageSize(pageSize);
                setTotalCount(totalCount);
                setItems(items);
                setStartIndex(startIndex);
        }

        public List getItems() {
                return items;
        }

        public void setItems(List items) {
                this.items = items;
        }

        public int getPageSize() {
                return pageSize;
        }

        public void setPageSize(int pageSize) {
                this.pageSize = pageSize;
        }

        public int getTotalCount() {
                return totalCount;
        }

        public void setTotalCount(int totalCount) {
                if (totalCount > 0) {
                        this.totalCount = totalCount;
                        int count = totalCount / pageSize;
                        if (totalCount % pageSize > 0)
                                count++;
                        indexes = new int[count];
                        for (int i = 0; i < count; i++) {
                                indexes[i] = pageSize * i;
                        }
                } else {
                        this.totalCount = 0;
                }
        }

        public int[] getIndexes() {
                return indexes;
        }

        public void setIndexes(int[] indexes) {
                this.indexes = indexes;
        }

        public int getStartIndex() {
                return startIndex;
        }

        public void setStartIndex(int startIndex) {
                if (totalCount <= 0)
                        this.startIndex = 0;
                else if (startIndex >= totalCount)
                        this.startIndex = indexes[indexes.length - 1];
                else if (startIndex < 0)
                        this.startIndex = 0;
                else {
                        this.startIndex = indexes[startIndex / pageSize];
                }
        }

        public int getNextIndex() {
                int nextIndex = getStartIndex() + pageSize;
                if (nextIndex >= totalCount)
                        return getStartIndex();
                else
                        return nextIndex;
        }

        public int getPreviousIndex() {
                int previousIndex = getStartIndex() - pageSize;
                if (previousIndex < 0)
                        return 0;
                else
                        return previousIndex;
        }

}



抽象业务类
java代码: 


/**
* Created on 2005-7-12
*/

package com.javaeye.common.business;

import java.io.Serializable;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.javaeye.common.util.PaginationSupport;

public abstract class AbstractManager extends HibernateDaoSupport {

        private boolean cacheQueries = false;

        private String queryCacheRegion;

        public void setCacheQueries(boolean cacheQueries) {
                this.cacheQueries = cacheQueries;
        }

        public void setQueryCacheRegion(String queryCacheRegion) {
                this.queryCacheRegion = queryCacheRegion;
        }

        public void save(final Object entity) {
                getHibernateTemplate().save(entity);
        }

        public void persist(final Object entity) {
                getHibernateTemplate().save(entity);
        }

        public void update(final Object entity) {
                getHibernateTemplate().update(entity);
        }

        public void delete(final Object entity) {
                getHibernateTemplate().delete(entity);
        }

        public Object load(final Class entity, final Serializable id) {
                return getHibernateTemplate().load(entity, id);
        }

        public Object get(final Class entity, final Serializable id) {
                return getHibernateTemplate().get(entity, id);
        }

        public List findAll(final Class entity) {
                return getHibernateTemplate().find("from " + entity.getName());
        }

        public List findByNamedQuery(final String namedQuery) {
                return getHibernateTemplate().findByNamedQuery(namedQuery);
        }

        public List findByNamedQuery(final String query, final Object parameter) {
                return getHibernateTemplate().findByNamedQuery(query, parameter);
        }

        public List findByNamedQuery(final String query, final Object[] parameters) {
                return getHibernateTemplate().findByNamedQuery(query, parameters);
        }

        public List find(final String query) {
                return getHibernateTemplate().find(query);
        }

        public List find(final String query, final Object parameter) {
                return getHibernateTemplate().find(query, parameter);
        }

        public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria) {
                return findPageByCriteria(detachedCriteria, PaginationSupport.PAGESIZE, 0);
        }

        public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria, final int startIndex) {
                return findPageByCriteria(detachedCriteria, PaginationSupport.PAGESIZE, startIndex);
        }

        public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria, final int pageSize,
                        final int startIndex) {
                return (PaginationSupport) getHibernateTemplate().execute(new HibernateCallback() {
                        public Object doInHibernate(Session session) throws HibernateException {
                                Criteria criteria = detachedCriteria.getExecutableCriteria(session);
                                int totalCount = ((Integer) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
                                criteria.setProjection(null);
                                List items = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
                                PaginationSupport ps = new PaginationSupport(items, totalCount, pageSize, startIndex);
                                return ps;
                        }
                }, true);
        }

        public List findAllByCriteria(final DetachedCriteria detachedCriteria) {
                return (List) getHibernateTemplate().execute(new HibernateCallback() {
                        public Object doInHibernate(Session session) throws HibernateException {
                                Criteria criteria = detachedCriteria.getExecutableCriteria(session);
                                return criteria.list();
                        }
                }, true);
        }

        public int getCountByCriteria(final DetachedCriteria detachedCriteria) {
                Integer count = (Integer) getHibernateTemplate().execute(new HibernateCallback() {
                        public Object doInHibernate(Session session) throws HibernateException {
                                Criteria criteria = detachedCriteria.getExecutableCriteria(session);
                                return criteria.setProjection(Projections.rowCount()).uniqueResult();
                        }
                }, true);
                return count.intValue();
        }
}




用户在web层构造查询条件detachedCriteria,和可选的startIndex,调用业务bean的相应findByCriteria方法,返回一个PaginationSupport的实例ps。

ps.getItems()得到已分页好的结果集
ps.getIndexes()得到分页索引的数组
ps.getTotalCount()得到总结果数
ps.getStartIndex()当前分页索引
ps.getNextIndex()下一页索引
ps.getPreviousIndex()上一页索引

posted @ 2007-04-16 15:34 七郎归来 阅读(178) | 评论 (0)编辑 收藏

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

//import com.modernmedia.mw.tag.Messages;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class Crypt {
// --------------------------------------------------------------------------------------------
// 获得密钥
public SecretKey getKey(String s) throws Exception {
//s ="g8TlgLEc6oqZxdwGe6pDiKB8Y";
System.out.println("s=="+s);
char[] ss = s.toCharArray();
String sss="";
    for(int i = 0;i<ss.length;i=i+2)
    {
    sss = sss + ss[i];
    }
SecretKeyFactory kf = SecretKeyFactory.getInstance("DES");
DESKeySpec ks = new DESKeySpec(sss.substring(0,8).getBytes());
SecretKey kd = kf.generateSecret(ks);
return kd;
}

// --------------------------------------------------------------------------------------------------
// 返回加密后的字符串
// key是用于生成密钥的字符串,input是要加密的字符串
public String getEncryptedString(String key, String input) {
String base64 = "";
try {
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, getKey(key));
System.out.print("getKey(key)==="+getKey(key)+"key=="+key);
byte[] inputBytes = input.getBytes("UTF8");
byte[] outputBytes = cipher.doFinal(inputBytes);
BASE64Encoder encoder = new BASE64Encoder();
base64 = encoder.encode(outputBytes);
} catch (Exception e) {
base64 = e.getMessage();
}
return base64;
}

// --------------------------------------------------------------------------------------------------
// 返回解密后的字符串
// key是用于生成密钥的字符串,input是要解密的字符串
public String getDecryptedString(String key, String input) {
String result = null;
try {
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, getKey(key));
BASE64Decoder decoder = new BASE64Decoder();
byte[] raw = decoder.decodeBuffer(input);
byte[] stringBytes = cipher.doFinal(raw);
result = new String(stringBytes, "UTF8");
} catch (Exception e) {
result = e.getMessage();
}
return result;
}

public static void main(String[] args){
Crypt mycrypt = new Crypt();
try {
//SecretKey skey = mycrypt.getKey("g8TlgLEc6oqZxdwGe6pDiKB8Y");
String ss = mycrypt.getEncryptedString("6678912345678906", "胖子");
System.out.println("ss=="+ss);
String ss2 = mycrypt.getDecryptedString("6678912345678906",ss);
System.out.println("ss2=="+ss2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

//String ss = Messages.getString("SendToMemberTag.5");
//System.out.print(ss);

posted @ 2007-04-16 15:34 七郎归来 阅读(1222) | 评论 (0)编辑 收藏

package com.routdata.org.user.test;
/************************************************
MD5 算法的Java Bean
@author:Topcat Tuppin
Last Modified:10,Mar,2001
*************************************************/
import java.lang.reflect.*;
/*************************************************
md5 类实现了RSA Data Security, Inc.在提交给IETF
的RFC1321中的MD5 message-digest 算法。
*************************************************/

public class MD5 {
/* 下面这些S11-S44实际上是一个4*4的矩阵,在原始的C实现中是用#define 实现的,
这里把它们实现成为static final是表示了只读,切能在同一个进程空间内的多个
Instance间共享*/
        static final int S11 = 7;
        static final int S12 = 12;
        static final int S13 = 17;
        static final int S14 = 22;

        static final int S21 = 5;
        static final int S22 = 9;
        static final int S23 = 14;
        static final int S24 = 20;

        static final int S31 = 4;
        static final int S32 = 11;
        static final int S33 = 16;
        static final int S34 = 23;

        static final int S41 = 6;
        static final int S42 = 10;
        static final int S43 = 15;
        static final int S44 = 21;

        static final byte[] PADDING = { -128, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        /* 下面的三个成员是MD5计算过程中用到的3个核心数据,在原始的C实现中
           被定义到MD5_CTX结构中
       
         */
        private long[] state = new long[4];  // state (ABCD)
        private long[] count = new long[2];  // number of bits, modulo 2^64 (lsb first)
        private byte[] buffer = new byte[64]; // input buffer
       
/* digestHexStr是MD5的唯一一个公共成员,是最新一次计算结果的
  16进制ASCII表示.
*/
        public String digestHexStr;
       
        /* digest,是最新一次计算结果的2进制内部表示,表示128bit的MD5值.
*/
        private byte[] digest = new byte[16];
       
/*
 getMD5ofStr是类MD5最主要的公共方法,入口参数是你想要进行MD5变换的字符串
 返回的是变换完的结果,这个结果是从公共成员digestHexStr取得的.
*/
        public String getMD5ofStr(String inbuf) {
                md5Init();
                md5Update(inbuf.getBytes(), inbuf.length());
                md5Final();
                digestHexStr = "";
                for (int i = 0; i < 16; i++) {
                        digestHexStr += byteHEX(digest[i]);
                }
                return digestHexStr;

        }
        // 这是MD5这个类的标准构造函数,JavaBean要求有一个public的并且没有参数的构造函数
        public MD5() {
                md5Init();

                return;
        }
       


        /* md5Init是一个初始化函数,初始化核心变量,装入标准的幻数 */
        private void md5Init() {
                count[0] = 0L;
                count[1] = 0L;
                ///* Load magic initialization constants.

                state[0] = 0x67452301L;
                state[1] = 0xefcdab89L;
                state[2] = 0x98badcfeL;
                state[3] = 0x10325476L;

                return;
        }
        /* F, G, H ,I 是4个基本的MD5函数,在原始的MD5的C实现中,由于它们是
        简单的位运算,可能出于效率的考虑把它们实现成了宏,在java中,我们把它们
       实现成了private方法,名字保持了原来C中的。 */

        private long F(long x, long y, long z) {
                return (x & y) | ((~x) & z);

        }
        private long G(long x, long y, long z) {
                return (x & z) | (y & (~z));

        }
        private long H(long x, long y, long z) {
                return x ^ y ^ z;
        }

        private long I(long x, long y, long z) {
                return y ^ (x | (~z));
        }
       
       /*
          FF,GG,HH和II将调用F,G,H,I进行近一步变换
          FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
          Rotation is separate from addition to prevent recomputation.
       */ 

        private long FF(long a, long b, long c, long d, long x, long s,
                long ac) {
                a += F (b, c, d) + x + ac;
                a = ((int) a << s) | ((int) a >>> (32 - s));
                a += b;
                return a;
        }

        private long GG(long a, long b, long c, long d, long x, long s,
                long ac) {
                a += G (b, c, d) + x + ac;
                a = ((int) a << s) | ((int) a >>> (32 - s));
                a += b;
                return a;
        }
        private long HH(long a, long b, long c, long d, long x, long s,
                long ac) {
                a += H (b, c, d) + x + ac;
                a = ((int) a << s) | ((int) a >>> (32 - s));
                a += b;
                return a;
        }
        private long II(long a, long b, long c, long d, long x, long s,
                long ac) {
                a += I (b, c, d) + x + ac;
                a = ((int) a << s) | ((int) a >>> (32 - s));
                a += b;
                return a;
        }
        /*
         md5Update是MD5的主计算过程,inbuf是要变换的字节串,inputlen是长度,这个
         函数由getMD5ofStr调用,调用之前需要调用md5init,因此把它设计成private的
        */
        private void md5Update(byte[] inbuf, int inputLen) {

                int i, index, partLen;
                byte[] block = new byte[64];
                index = (int)(count[0] >>> 3) & 0x3F;
                // /* Update number of bits */
                if ((count[0] += (inputLen << 3)) < (inputLen << 3))
                        count[1]++;
                count[1] += (inputLen >>> 29);

                partLen = 64 - index;

                // Transform as many times as possible.
                if (inputLen >= partLen) {
                        md5Memcpy(buffer, inbuf, index, 0, partLen);
                        md5Transform(buffer);

                        for (i = partLen; i + 63 < inputLen; i += 64) {

                                md5Memcpy(block, inbuf, 0, i, 64);
                                md5Transform (block);
                        }
                        index = 0;

                } else

                        i = 0;

                ///* Buffer remaining input */
                md5Memcpy(buffer, inbuf, index, i, inputLen - i);

        }
       
        /*
          md5Final整理和填写输出结果
        */
        private void md5Final () {
                byte[] bits = new byte[8];
                int index, padLen;

                ///* Save number of bits */
                Encode (bits, count, 8);

                ///* Pad out to 56 mod 64.
                index = (int)(count[0] >>> 3) & 0x3f;
                padLen = (index < 56) ? (56 - index) : (120 - index);
                md5Update (PADDING, padLen);

                ///* Append length (before padding) */
                md5Update(bits, 8);

                ///* Store state in digest */
                Encode (digest, state, 16);

        }
        
        /* md5Memcpy是一个内部使用的byte数组的块拷贝函数,从input的inpos开始把len长度的
      字节拷贝到output的outpos位置开始
        */

        private void md5Memcpy (byte[] output, byte[] input,
                int outpos, int inpos, int len)
        {
                int i;

                for (i = 0; i < len; i++)
                        output[outpos + i] = input[inpos + i];
        }
       
        /*
           md5Transform是MD5核心变换程序,有md5Update调用,block是分块的原始字节
        */
        private void md5Transform (byte block[]) {
                long a = state[0], b = state[1], c = state[2], d = state[3];
                long[] x = new long[16];

                Decode (x, block, 64);

                /* Round 1 */
                a = FF (a, b, c, d, x[0], S11, 0xd76aa478L); /* 1 */
                d = FF (d, a, b, c, x[1], S12, 0xe8c7b756L); /* 2 */
                c = FF (c, d, a, b, x[2], S13, 0x242070dbL); /* 3 */
                b = FF (b, c, d, a, x[3], S14, 0xc1bdceeeL); /* 4 */
                a = FF (a, b, c, d, x[4], S11, 0xf57c0fafL); /* 5 */
                d = FF (d, a, b, c, x[5], S12, 0x4787c62aL); /* 6 */
                c = FF (c, d, a, b, x[6], S13, 0xa8304613L); /* 7 */
                b = FF (b, c, d, a, x[7], S14, 0xfd469501L); /* 8 */
                a = FF (a, b, c, d, x[8], S11, 0x698098d8L); /* 9 */
                d = FF (d, a, b, c, x[9], S12, 0x8b44f7afL); /* 10 */
                c = FF (c, d, a, b, x[10], S13, 0xffff5bb1L); /* 11 */
                b = FF (b, c, d, a, x[11], S14, 0x895cd7beL); /* 12 */
                a = FF (a, b, c, d, x[12], S11, 0x6b901122L); /* 13 */
                d = FF (d, a, b, c, x[13], S12, 0xfd987193L); /* 14 */
                c = FF (c, d, a, b, x[14], S13, 0xa679438eL); /* 15 */
                b = FF (b, c, d, a, x[15], S14, 0x49b40821L); /* 16 */

                /* Round 2 */
                a = GG (a, b, c, d, x[1], S21, 0xf61e2562L); /* 17 */
                d = GG (d, a, b, c, x[6], S22, 0xc040b340L); /* 18 */
                c = GG (c, d, a, b, x[11], S23, 0x265e5a51L); /* 19 */
                b = GG (b, c, d, a, x[0], S24, 0xe9b6c7aaL); /* 20 */
                a = GG (a, b, c, d, x[5], S21, 0xd62f105dL); /* 21 */
                d = GG (d, a, b, c, x[10], S22, 0x2441453L); /* 22 */
                c = GG (c, d, a, b, x[15], S23, 0xd8a1e681L); /* 23 */
                b = GG (b, c, d, a, x[4], S24, 0xe7d3fbc8L); /* 24 */
                a = GG (a, b, c, d, x[9], S21, 0x21e1cde6L); /* 25 */
                d = GG (d, a, b, c, x[14], S22, 0xc33707d6L); /* 26 */
                c = GG (c, d, a, b, x[3], S23, 0xf4d50d87L); /* 27 */
                b = GG (b, c, d, a, x[8], S24, 0x455a14edL); /* 28 */
                a = GG (a, b, c, d, x[13], S21, 0xa9e3e905L); /* 29 */
                d = GG (d, a, b, c, x[2], S22, 0xfcefa3f8L); /* 30 */
                c = GG (c, d, a, b, x[7], S23, 0x676f02d9L); /* 31 */
                b = GG (b, c, d, a, x[12], S24, 0x8d2a4c8aL); /* 32 */

                /* Round 3 */
                a = HH (a, b, c, d, x[5], S31, 0xfffa3942L); /* 33 */
                d = HH (d, a, b, c, x[8], S32, 0x8771f681L); /* 34 */
                c = HH (c, d, a, b, x[11], S33, 0x6d9d6122L); /* 35 */
                b = HH (b, c, d, a, x[14], S34, 0xfde5380cL); /* 36 */
                a = HH (a, b, c, d, x[1], S31, 0xa4beea44L); /* 37 */
                d = HH (d, a, b, c, x[4], S32, 0x4bdecfa9L); /* 38 */
                c = HH (c, d, a, b, x[7], S33, 0xf6bb4b60L); /* 39 */
                b = HH (b, c, d, a, x[10], S34, 0xbebfbc70L); /* 40 */
                a = HH (a, b, c, d, x[13], S31, 0x289b7ec6L); /* 41 */
                d = HH (d, a, b, c, x[0], S32, 0xeaa127faL); /* 42 */
                c = HH (c, d, a, b, x[3], S33, 0xd4ef3085L); /* 43 */
                b = HH (b, c, d, a, x[6], S34, 0x4881d05L); /* 44 */
                a = HH (a, b, c, d, x[9], S31, 0xd9d4d039L); /* 45 */
                d = HH (d, a, b, c, x[12], S32, 0xe6db99e5L); /* 46 */
                c = HH (c, d, a, b, x[15], S33, 0x1fa27cf8L); /* 47 */
                b = HH (b, c, d, a, x[2], S34, 0xc4ac5665L); /* 48 */

                /* Round 4 */
                a = II (a, b, c, d, x[0], S41, 0xf4292244L); /* 49 */
                d = II (d, a, b, c, x[7], S42, 0x432aff97L); /* 50 */
                c = II (c, d, a, b, x[14], S43, 0xab9423a7L); /* 51 */
                b = II (b, c, d, a, x[5], S44, 0xfc93a039L); /* 52 */
                a = II (a, b, c, d, x[12], S41, 0x655b59c3L); /* 53 */
                d = II (d, a, b, c, x[3], S42, 0x8f0ccc92L); /* 54 */
                c = II (c, d, a, b, x[10], S43, 0xffeff47dL); /* 55 */
                b = II (b, c, d, a, x[1], S44, 0x85845dd1L); /* 56 */
                a = II (a, b, c, d, x[8], S41, 0x6fa87e4fL); /* 57 */
                d = II (d, a, b, c, x[15], S42, 0xfe2ce6e0L); /* 58 */
                c = II (c, d, a, b, x[6], S43, 0xa3014314L); /* 59 */
                b = II (b, c, d, a, x[13], S44, 0x4e0811a1L); /* 60 */
                a = II (a, b, c, d, x[4], S41, 0xf7537e82L); /* 61 */
                d = II (d, a, b, c, x[11], S42, 0xbd3af235L); /* 62 */
                c = II (c, d, a, b, x[2], S43, 0x2ad7d2bbL); /* 63 */
                b = II (b, c, d, a, x[9], S44, 0xeb86d391L); /* 64 */

                state[0] += a;
                state[1] += b;
                state[2] += c;
                state[3] += d;

        }
       
        /*Encode把long数组按顺序拆成byte数组,因为java的long类型是64bit的,
          只拆低32bit,以适应原始C实现的用途
        */
        private void Encode (byte[] output, long[] input, int len) {
                int i, j;

                for (i = 0, j = 0; j < len; i++, j += 4) {
                        output[j] = (byte)(input[i] & 0xffL);
                        output[j + 1] = (byte)((input[i] >>> 8) & 0xffL);
                        output[j + 2] = (byte)((input[i] >>> 16) & 0xffL);
                        output[j + 3] = (byte)((input[i] >>> 24) & 0xffL);
                }
        }

        /*Decode把byte数组按顺序合成成long数组,因为java的long类型是64bit的,
          只合成低32bit,高32bit清零,以适应原始C实现的用途
        */
        private void Decode (long[] output, byte[] input, int len) {
                int i, j;


                for (i = 0, j = 0; j < len; i++, j += 4)
                        output[i] = b2iu(input[j]) |
                                (b2iu(input[j + 1]) << 8) |
                                (b2iu(input[j + 2]) << 16) |
                                (b2iu(input[j + 3]) << 24);

                return;
        }
      
        /*
          b2iu是我写的一个把byte按照不考虑正负号的原则的"升位"程序,因为java没有unsigned运算
        */
        public static long b2iu(byte b) {
                return b < 0 ? b & 0x7F + 128 : b;
        }
       
/*byteHEX(),用来把一个byte类型的数转换成十六进制的ASCII表示,
 因为java中的byte的toString无法实现这一点,我们又没有C语言中的
 sprintf(outbuf,"%02X",ib)
*/
        public static String byteHEX(byte ib) {
                char[] Digit = { '0','1','2','3','4','5','6','7','8','9',
                'A','B','C','D','E','F' };
                char [] ob = new char[2];
                ob[0] = Digit[(ib >>> 4) & 0X0F];
                ob[1] = Digit[ib & 0X0F];
                String s = new String(ob);
                return s;
        }
}

posted @ 2007-04-16 15:32 七郎归来 阅读(115) | 评论 (0)编辑 收藏

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.net.URL;
import java.net.HttpURLConnection;
import java.io.PrintWriter;
import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * Created by IntelliJ IDEA.
 * User: zhengzhg
 * Mail: snake_country@sina.com
 * Date: 2004-10-13
 * Time: 15:30:28
 * To change this template use File | Settings | File Templates.
 * 常用工具包。包括生成各种密码随机串,加密解密,编码解码,执行url等
 */

public class CryptTool {
    /**
     * 生成密码.
     * @param count 密码位数
     * @param letters 是否包含字符
     * @param numbers 是否包含数字
     * @return String password
     */
    public static String getPassword(int count, boolean letters, boolean numbers) {
        return org.apache.commons.lang.RandomStringUtils.random(count, letters, numbers);
    }

    /**
     * 生成字符数字混合的密码.
     * @param count 密码位数
     * @return String password
     */
    private static String getPassword(int count) {
        return getPassword(count, true, true);
    }


    /**
     * 生成纯数字密码.
     * @param count 密码位数
     * @return String password
     */
    public static String getPasswordOfNumber(int count) {
        return getPassword(count, false, true);
    }

    /**
     * 生成纯字符密码.
     * @param count 密码位数
     * @return String password
     */
    public static String getPasswordOfCharacter(int count) {
        return getPassword(count, true, false);
    }

    /**
     * 生成3DES密钥.
     * @param key_byte seed key
     * @throws Exception
     * @return javax.crypto.SecretKey Generated DES key
     */
    public static javax.crypto.SecretKey genDESKey(byte[] key_byte) throws Exception {
        SecretKey k = new SecretKeySpec(key_byte, "DESede");

        return k;
    }

    /**
     * 3DES 解密(byte[]).
     * @param key SecretKey
     * @param crypt byte[]
     * @throws Exception
     * @return byte[]
     */
    public static byte[] desDecrypt(javax.crypto.SecretKey key, byte[] crypt) throws Exception {
        javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("DESede");
        cipher.init(javax.crypto.Cipher.DECRYPT_MODE, key);

        return cipher.doFinal(crypt);
    }

    /**
     * 3DES 解密(String).
     * @param key SecretKey
     * @param crypt byte[]
     * @throws Exception
     * @return byte[]
     */
    public static String desDecrypt(javax.crypto.SecretKey key, String crypt) throws Exception {
        return new String(desDecrypt(key, crypt.getBytes()));
    }

    /**
     * 3DES加密(byte[]).
     * @param key SecretKey
     * @param src byte[]
     * @throws Exception
     * @return byte[]
     */
    public static byte[] desEncrypt(javax.crypto.SecretKey key, byte[] src) throws Exception {
        javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("DESede");
        cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, key);

        return cipher.doFinal(src);
    }

    /**
     * 3DES加密(String).
     * @param key SecretKey
     * @param src byte[]
     * @throws Exception
     * @return byte[]
     */
    public static String desEncrypt(javax.crypto.SecretKey key, String src) throws Exception {
        return new String(desEncrypt(key, src.getBytes()));
    }

    /**
     * MD5 摘要计算(byte[]).
     * @param src byte[]
     * @throws Exception
     * @return byte[] 16 bit digest
     */
    public static byte[] md5Digest(byte[] src) throws Exception {
        java.security.MessageDigest alg = java.security.MessageDigest.getInstance("MD5");
        // MD5 is 16 bit message digest

        return alg.digest(src);
    }

    /**
     * MD5 摘要计算(String).
     * @param src String
     * @throws Exception
     * @return String
     */
    public static String md5Digest(String src) throws Exception {
        return new String(md5Digest(src.getBytes()));
    }

    /**
     * BASE64 编码.
     * @param src String inputed string
     * @return String returned string
     */
    public static String base64Encode(String src) {
        sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();

        return encoder.encode(src.getBytes());
    }

    /**
     * BASE64 编码(byte[]).
     * @param src byte[] inputed string
     * @return String returned string
     */
    public static String base64Encode(byte[] src) {
        sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();

        return encoder.encode(src);
    }

    /**
     * BASE64 解码.
     * @param src String inputed string
     * @return String returned string
     */
    public static String base64Decode(String src) {
        sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();

        try {
            return new String(decoder.decodeBuffer(src));
        } catch (Exception ex) {
            return null;
        }
    }

    /**
     * BASE64 解码(to byte[]).
     * @param src String inputed string
     * @return String returned string
     */
    public static byte[] base64DecodeToBytes(String src) {
        sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();

        try {
            return decoder.decodeBuffer(src);
        } catch (Exception ex) {
            return null;
        }
    }

    /**
     * 对给定字符进行 URL 编码GB2312.
     * @param src String
     * @return String
     */
    public static String urlEncode(String src) {
        return urlEncode(src, "GB2312");
    }

    /**
     * 对给定字符进行 URL 解码GB2312
     * @param value 解码前的字符串
     * @return 解码后的字符串
     */
    public static String urlDecode(String value) {
        return urlDecode(value, "GB2312");
    }

    /**
     * 对给定字符进行 URL 编码.
     * @param src String
     * @param coder 字符编码格式(GB2312/GBK)
     * @return String
     */
    public static String urlEncode(String src, String coder) {
        try {
            src = java.net.URLEncoder.encode(src, coder);

            return src;
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return src;
    }

    /**
     * 对给定字符进行 URL 解码
     * @param value 解码前的字符串
     * @param coder 字符编码格式(GB2312/GBK)
     * @return 解码后的字符串
     */
    public static String urlDecode(String value, String coder) {
        try {
            return java.net.URLDecoder.decode(value, coder);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return value;
    }

    /**
     * 执行给定url
     * @param urlString 给定的url
     * @return 返回值
     */
    public static String executeURL(String urlString) throws Exception {
        StringBuffer document = new StringBuffer();
        URL url = new URL(urlString);
        URLConnection conn = url.openConnection();
        BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));

        String line = null;
        while ((line = reader.readLine()) != null)
            document.append(line + "\n");

        reader.close();
       
        return document.toString();
    }

posted @ 2007-04-16 15:31 七郎归来 阅读(519) | 评论 (0)编辑 收藏

仅列出标题
共6页: 上一页 1 2 3 4 5 6 下一页