在开发中验证码是比较常用到有效防止这种问题对某一个特定注册用户用特定程序破解方式进行不断的登陆尝试的方式。
此演示程序
包 括三个文件:
1.login.jsp:登录页面
2.code.jsp:生成验证码图片页面
3.check.jsp:验证结果
code.jsp
< % @ page contentType= "image/jpeg" import = "java.awt.*, java.awt.image.*,java.util.*,javax.imageio.*" % > < % // 在内存中创建图象 int width= 60, height= 20; BufferedImage image = new BufferedImage( width, height, BufferedImage. TYPE_INT_RGB) ; // 获取图形上下文 Graphics g = image. getGraphics( ) ; // 设定背景色 g. setColor( new Color( 0xDCDCDC) ) ; g. fillRect( 0, 0, width, height) ; //画边框 g. setColor( Color. black) ; g. drawRect( 0, 0, width- 1, height- 1) ; // 随机产生的认证码(4位数字) String rand = "" + ( Math . random ( ) * 10000) ; rand = rand. substring( 0, rand. indexOf( "." ) ) ; switch ( rand. length ( ) ) { case 1: rand = "000" + rand; break ; case 2: rand = "00" + rand; break ; case 3: rand = "0" + rand; break ; default : rand = rand. substring( 0, 4) ; break ; } // 将认证码存入SESSION session. setAttribute( "rand" , rand) ; // 将认证码显示到图象中 g. setColor( Color. black) ; Integer tempNumber = new Integer ( rand) ; String numberStr = tempNumber. toString( ) ; g. setFont( new Font( "Atlantic Inline" , Font. PLAIN, 18) ) ; String Str = numberStr. substring( 0, 1) ; g. drawString( Str, 8, 17) ; Str = numberStr. substring( 1, 2) ; g. drawString( Str, 20, 15) ; Str = numberStr. substring( 2, 3) ; g. drawString( Str, 35, 18) ; Str = numberStr. substring( 3, 4) ; g. drawString( Str, 45, 15) ; // 随机产生88个干扰点,使图象中的认证码不易被其它程序探测到 Random random = new Random ( ) ; for ( int i= 0; i< 20; i+ + ) { int x = random . nextInt( width) ; int y = random . nextInt( height) ; g. drawOval( x, y, 0, 0) ; } // 图象生效 g. dispose( ) ; // 输出图象到页面 ImageIO. write( image, "JPEG" , response. getOutputStream( ) ) ; //在页面上调用 % >
login.jsp
< % @ page contentType= "text/html;charset=gb2312" % > < ! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" > < html > < head > < title > 认证码输入页面< / title > < meta http- equiv= "Content-Type" content = "text/html; charset=gb2312" > < META HTTP- EQUIV= "Pragma" CONTENT = "no-cache" > < META HTTP- EQUIV= "Cache-Control" CONTENT = "no-cache" > < META HTTP- EQUIV= "Expires" CONTENT = "0" > < / head > < body > < form method = post action = "check.jsp" > < table > < tr > < td align = left> 系统产生的认证码:< / td > < td > < img border = 0 src = "code.jsp" > < / td > < / tr > < tr > < td align = left> 输入上面的认证码:< / td > < td > < input type = text name = rand maxlength = 4 value = "" > < / td > < / tr > < tr > < td colspan = 2 align = center > < input type = submit value = "提交检测" > < / td > < / tr > < / form > < / body > < / html >
check.jsp
< % @ page contentType= "text/html; charset=gb2312" language= "java" import = "java.sql.*" errorPage= "" % > < html > < head > < title > 认证码验证页面< / title > < meta http- equiv= "Content-Type" content = "text/html; charset=gb2312" > < META HTTP- EQUIV= "Pragma" CONTENT = "no-cache" > < META HTTP- EQUIV= "Cache-Control" CONTENT = "no-cache" > < META HTTP- EQUIV= "Expires" CONTENT = "0" > < / head > < body > < % String rand = ( String ) session. getAttribute( "rand" ) ; String input = request. getParameter( "rand" ) ; % > 系统产生的认证码为: < % = rand % > < br > 您输入的认证码为: < % = input % > < br > < br > < % if ( rand. equals( input) ) { % > < font color = green> 输入相同,认证成功!< / font > < % } else { % > < font color = red> 输入不同,认证失败!< / font > < % } % > < / body > < / html >
在写JSP程序的时候,如果程序中调用了response.getOutputStream()去向客户端输出文件等数据流,容器就会抛出这样的异常: Java.lang.IllegalStateException: getOutputStream() has already been called for this response at org.apache.catalina.connector.Response.getWriter(Response.java:596) at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:186) 产生这样的异常原因:是web容器生成的servlet代码中有out.write(""),这个和JSP中调用的response.getOutputStream()产生冲突.即Servlet规范说明,不能既调用response.getOutputStream(),又调用response.getWriter(),无论先调用哪一个,在调用第二个时候应会抛出IllegalStateException,因为在jsp中,out变量实际上是通过response.getWriter得到的,你的程序中既用了response.getOutputStream,又用了out变量,故出现以上错误。 解决方案:在程序的最后添加: out.clear(); out = pageContext.pushBody(); 就可以了。