[导读]本文通过实例,介绍在做验证码的时候为了给用户很好的体验,需要在原有验证方式基础之上增加一段js,通过xmlhttp来获取返回值,以此来验证是否有效。同时,本例还特别适合检验用户名是否有效。  

1、我们在做验证码的时候往往由于要反作弊,验证有时故意加入多的干扰因素,这时验证码显示不很清楚,用户经常输入错误。这样不但要重新刷新页面,导致用户没有看清楚验证码而重填而不是修改,而且如果没有用session保存下用户输入的其它数据的话(如姓名),用户刚刚输入的内容也不存在了,这样给用户造成不好的体验。  

2、本例在原有验证方式基础之上增加一段js,通过xmlhttp来获取返回值,以此来验证是否有效,这样即使用户浏览器不支持js,也不会影响他的正常使用了。  

3、为了防止作弊,当用户连接3次输入错误时则重载一下图片,这样也利于用户因为图片上的验证码辨认不清而使其终无法输入正确。  

4、本例还特别适合检验用户名是否有效,只要从后台做个sql查询,返回一个值或是xml即可。(这种例子太多  ,就在此不赘述了)。  

5、本例的优点在于非常方便用户输入,而且减少对服务器端的请求,可以说既改善用户体验而且略会节省带宽成本,但相应地要在页面上增加一段JavaScript代码,在目前网速越来越快人们要求便捷舒适的今天,似乎我们更应注意提供给用户良好的使用感受。  

代码如下:  

1、img.jsp,输入主页面  
<% @ page contentType = " text/html; charset=GBK "  language = " java "  import = " java.sql.* "  errorPage = ""  pageEncoding = " GBK " %>  

<%
// set  Chinese Char
// Cody by [email protected] ;
// homepage:jiarry. 126 .com 
request.setCharacterEncoding(
" GBK " ); 
response.setCharacterEncoding(
" GBK " );
response.setContentType(
" text/html; charset=GBK " ); 
%>  

< html >
< head >
< title > 图片验证 </ title >
< meta  http-equiv ="Content-Type"  content ="text/html; charset=gb2312" >  

< script  src ="net.js" ></ script >
</ head >
< body >  
AJAX(无刷新及时提示)验证码实例!cody by jarry 
< hr >

<%
String  num = request.getParameter( " num " ); 

String  random = ( String )session.getAttribute( " random " ); 

String  name = request.getParameter( " name " ); 

if (num! = null && random! = null && name! = null



if (num.equals(random)) 



out.println(
" <font style=\ " color:green;font - weight:bold \ "

恭喜您,验证码输入成功,这里是提交结果页面,可以写入数据库了!
</ font >  

< a href =\ " img.jsp\ " > 返回再测试 </ a >< br > " ); 

out.println(
" 您的名字是: " + name); 

out.println(
" <br> " ); 

out.println(
" 您输入的是: " + num); 

out.println(
" 验证码是: " + random); 

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

return;
// javascript:history.go( - 1


%>  

< script  type ="text/javascript" >
var  times = 0 ;
function  subform(){
var  gtext = this .req.responseText;
var  info = document.getElementById( " info " );
if (gtext.indexOf( " validate_successful " ) !=- 1 ){ 

// info.innerHTML="<font color=green>验证码通过</font>"; 

document.forms[
" myform " ].submit(); 

// 当得到的值表示合法,则验证码通过。 

}
else

times
++

if (times >= 3 ){ // 如果连接3次输入错误,则重载图片,可以防止作弊和用户看不清图片; 

info.innerHTML
= " 接连3次输入错误。更新验证码,请重新输入 "

document.forms[
" myform " ].num.value = ""

show(document.getElementById('random')); 

times
= 0

}
else

info.innerHTML
= " " + times + " 次验证码错误,请注意区分大小写  "



document.forms[
" myform " ].num.select(); 





function  validata(obj){ 

var  enter = true

var  info = document.getElementById( " info " ); 

var  msg = ""

if (obj.name.value.match( /^ \s * $ / g)){ // 如果未输入名字,提示 

msg
+= " 请输入您的姓名<br> " ;enter = false  



if (obj.num.value.match( /^ \s * $ / g)){ // 如果未输入验证码,提示 

msg
+= " 请输入验证码<br> " ;enter = false  



if (enter == false ){ 

info.innerHTML
= msg; 

return   false



var  url = " num.jsp?num= " + obj.num.value; 

var  newxmlhttp = new  net.ContentLoader(url,subform, "" , " get " , null , null ); 

return   false



function  show(o){ 

// 重载验证码 

var  timenow  =   new  Date().getTime(); 

o.src
= " random.jsp?d= " + timenow; 

/*  

//超时执行; 

setTimeout(function(){ 

o.src="random.jsp?d="+timenow; 



,20); 

*/  



</ script >  

< form  action ="img.jsp"  name ="myform"  method ="post"  

onsubmit
="return validata(this);" >  

您的姓名:
< input  type ="text"  name ="name"  size =10 >  (为了更好地说明此例,特加姓名一项) < br >  

验 证 码:
< input  type ="text"  name ="num"  size =10  maxlength ="4" >  

< img  src ="random.jsp"  id ="random"  align =""  valign ="absmiddle"  hspace ="5" >  

< href ="javascript:show(document.getElementById('random'))" > 验证码看不清 </ a >< br >  

< br >   < input  type ="submit"  value =" 提交 " >< br >  

< div  id =info  style ="color:red;padding:10px;font-size:12px;" ></ div >  

</ form >  

</ body >  

</ html >

2、num.jsp,反馈xmlhttp请求的页面
<% @ page contentType = " text/html; charset=GBK "  language = " java "  

import
= " java.sql.* "  errorPage = ""  pageEncoding = " GBK " %>  

<%  

// set  Chinese Char 

// Cody by [email protected] ; 

// homepage:jiarry. 126 .com 

request.setCharacterEncoding(
" GBK " ); 

response.setCharacterEncoding(
" GBK " ); 

response.setContentType(
" text/html; charset=GBK " ); 

%>  

<%  

String  num = request.getParameter( " num " ); 

String  random = ( String )session.getAttribute( " random " ); 

if (num! = null && random! = null



if (!num.equals(random)) 



/*  

out.println(
" <script>alert('验证码错误!请重试。')</script> " ); 

out.println(
" <script>history.go(-1)</script> " ); 

// response.sendRedirect( " img.jsp " ); 

*/  

out.print(
" validate_failed: " + random); 



else  



// out.println( " <center>验证成功!</center> " ); 

out.print(
" validate_successful: " + random); 





%>  

3、random.jsp,生成验证码图片的页面
<% @ page autoFlush = " false "  import = " java.util.*,java.awt.*, 

java.awt.image.
* ,com.sun.image.codec.jpeg. * ,java.util. * "  %> 

<

// set  Chinese Char 

// Cody by [email protected] ; 

// homepage:jiarry. 126 .com 

request.setCharacterEncoding(
" GBK " ); 

response.setCharacterEncoding(
" GBK " ); 

response.setContentType(
" text/html; charset=GBK " ); 

%>  

<%  

String  chose = " 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ "

char display[]
= { ' 0',' ','0',' ','0',' ','0'},ran[]={'0','0','0','0'},temp; 

Random rand
= new  Random(); 

for ( int  i = 0 ;i < 4 ;i ++



temp
= chose.charAt(rand.nextInt(chose.length())); 

display[i
* 2 ] = temp; 

ran[i]
= temp; 





String  random = String .valueOf(display); 

session.setAttribute(
" random " , String .valueOf(ran)); 

%>  

<%  

out.clear(); 

response.setContentType(
" image/jpeg " ); 

response.addHeader(
" pragma " , " NO-cache " ); 

response.addHeader(
" Cache-Control " , " no-cache " ); 

response.addDateHeader(
" Expries " , 0 ); 

int  width = 80 , height = 30

BufferedImage image 
=   new  BufferedImage(width, height, 

BufferedImage.TYPE_INT_RGB); 

Graphics g 
=  image.getGraphics(); 

// 以下填充背景颜色 

g.setColor(Color.GREEN); 

g.fillRect(
0 0 , width, height); 

// 设置字体颜色 

g.setColor(Color.RED); 

Font font
= new  Font( " Arial " ,Font.PLAIN, 20 ); 

g.setFont(font); 

// g.drawString(random, 5 , 14 ); 

g.drawString(random,
5 , 20 ); 

g.dispose(); 

ServletOutputStream outStream 
=  response.getOutputStream(); 

JPEGImageEncoder encoder 
= JPEGCodec.createJPEGEncoder(outStream); 

encoder.encode(image); 

outStream.close(); 

%>  

4、net.js,封装好的xmlhttp对象,可以很方便的调用
/*  namespacing object  */  

var  net = new  Object(); 



net.READY_STATE_UNINITIALIZED
= 0

net.READY_STATE_LOADING
= 1

net.READY_STATE_LOADED
= 2

net.READY_STATE_INTERACTIVE
= 3

net.READY_STATE_COMPLETE
= 4

/* --- content loader object for cross-browser requests --- */  

net.ContentLoader
= function (url,on_load,on_error,method,params,contentType){ 

this .req = null

this .on_load = on_load; 

this .on_error = (on_error)  ?  on_error :  this .defaultError; 

this .loadXMLDoc(url,method,params,contentType); 



net.ContentLoader.prototype.loadXMLDoc
= function (url,method,params,contentType){ 

if  ( ! method) 



method
= " GET "



if  ( ! contentType  &&  method == " POST "



contentType
= 'application / x - www - form - urlencoded'; 



if  (window.XMLHttpRequest) 



this .req = new  XMLHttpRequest(); 



else   if  (window.ActiveXObject) 



// add try catch; 

try  { 

this .req  =   new  ActiveXObject( " Msxml2.XMLHTTP " ); 

}
catch  (e1){ 

try  { 

this .req  =   new  ActiveXObject( " Microsoft.XMLHTTP " ); 

catch  (e2){ 





//  

// this.req=new ActiveXObject("Microsoft.XMLHTTP"); 



if  ( this .req) 



try  



var  loader = this

this .req.onreadystatechange = function () 



net.ContentLoader.onReadyState.call(loader); 



this .req.open(method,url, true ); 

if  (contentType) 



this .req.setRequestHeader('Content - Type', contentType); 



this .req.send(params); 



catch  (err) 



this .on_error.call( this ); 







net.ContentLoader.onReadyState
= function (){ 

var  req = this .req; 

var  ready = req.readyState; 

if  (ready == net.READY_STATE_COMPLETE){ 

var  httpStatus = req.status; 

if  (httpStatus == 200   ||  httpStatus == 0 ){ 

this .on_load.call( this ); 

}
else

this .on_error.call( this ); 







net.ContentLoader.prototype.defaultError
= function (){ 

alert(
" error fetching data! "  

+ " \n\nreadyState: " + this .req.readyState 

+ " \nstatus:  " + this .req.status 

+ " \nheaders:  " + this .req.getAllResponseHeaders());