1.图文验证码的原理

在servlet中随机生成一个指定位置的验证码,一般为四位,然后把该验证码保存到session中.在通过Java的绘图类以图片的形式输出该验证码。为了增加验证码的安全级别,可以输出图片的同时输出干扰线,最后在用户提交数据的时候,在服务器端将用户提交的验证码和Session保存的验证码进行比较。

 

2.验证码所需的技术

i.因为验证码中的文字,数字,应为都是可变的,故要用到随机生成数技术。

       ii.如果验证码中包含汉字,则要用到汉字生成技术.

       iii.可以使用Ajax技术实现局部刷新

       iv.可以使用图片的缩放和旋转技术,

       vi.随机绘制干扰线(可以是折现,直线等)

       vii.如果考虑到验证码的安全性,可以使用MD5加密.


验证码模块实例

1.编写生成英文,数字,汉字随机生成的Servlet类.源代码如下:


package com.servlet;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * 随机生成英文,数字,汉字验证码
 * 
 *
 */
public class PictureCheckCode extends HttpServlet{

  	//定义变量
	//序列化      Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。
 	private static final long serialVersionUID = 1L;

 	//构造方法
	 public PictureCheckCode() {
		 super();
  	}

  	//重写destory方法(服务结束时,调用destory()方法,在init()方法中创建的任何资源都应该被清除和释放)
 	public void destroy() {
  		super.destroy();
 	}
	
 	//重写init方法(在init()方法中,servlet创建和初始化它在处理请求时需要用到的资源)
  	public void init() throws ServletException {
 		super.init();
  	}  
	
	//获得随机生成的颜色  
        public Color getRandColor(int s, int e){ 
    	
               Random random = new Random();  
               if(s > 255) s = 255;  
               if(e > 255) e = 255;  
               int r, g, b;  
               r = s + random.nextInt(e - s);    //随机生成RGB颜色中的r值  
               g = s + random.nextInt(e - s);    //随机生成RGB颜色中的g值  
               b = s + random.nextInt(e - s);    //随机生成RGB颜色中的b值  
               return new Color(r, g, b);  
        }     
    
	//重写service方法
 	protected void service(HttpServletRequest request, HttpServletResponse response)
 			 throws ServletException, IOException {
		
  		//设置不缓存  
                response.setHeader("Pragma", "No-cache");  
                response.setHeader("Cache-Control", "No-cache"); 
                //设置过期的时间期限
                response.setDateHeader("Expires", 0);
                //指定生成的响应图片,一定不能缺少这句话,否则错误.  
                response.setContentType("image/jpeg");  
        
                //指定生成验证码的宽度和高度
               int width = 86;
               int height = 22;
               //创建BufferedImage对象,其作用相当于一图片  
               BufferedImage image  =new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 
        
               //创建Graphics对象,其作用相当于画笔 
               Graphics g = image.getGraphics(); 
               //创建Grapchics2D对象(绘制2D图形) 
               Graphics2D g2d = (Graphics2D)g; //把Graphics类的对象g,强制转换成Graphics2D类的对象g2d 
        
               Random random = new Random();  
               //定义字体样式(bold 粗体)
               Font mfont = new Font("楷体", Font.BOLD, 16);   
               g.setColor(getRandColor(200, 250)); 
               //绘制背景 
               g.fillRect(0, 0, width, height);
               //设置字体 
               g.setFont(mfont);
               g.setColor(getRandColor(180, 200));
        
               //绘制100条颜色和位置全部为随机产生的线条,该线条为2f  
               for(int i = 0; i < 100; i++){  
                  int x = random.nextInt(width - 1);  
                  int y = random.nextInt(height - 1);  
                  int x1 = random.nextInt(6) + 1;  
                  int y1 = random.nextInt(12) + 1;  
                  //定制线条样式(CAP_BUTT为一种线端       JOIN_BEVEL两条线连接时,连接处的形状) 
                  BasicStroke bs = new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);  
                  //Line2D。Double 根据指定坐标(x + x1, y + y1) (x, y)构造一条线
                  Line2D line = new Line2D.Double(x, y, x + x1, y + y1);  
                  g2d.setStroke(bs);
                  //绘制直线
                  g2d.draw(line);
               }
            
               //输出由英文,数字,和中文随机组成的验证文字,具体的组合方式根据生成随机数确定。  
               String sRand = "";  
               String ctmp = "";  
               int itmp = 0;  
               //制定输出的验证码为四位  
               for(int i = 0; i < 4; i++){  
                  switch(random.nextInt(3)){  
                    case 1:
                            itmp = random.nextInt(26) + 65;      //生成A-Z的字母 
                            ctmp = String.valueOf((char)itmp);  
                            break;  
                    case 2:                   //生成汉字  
                            String[] rBase= {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};   
                            //生成第一位区码  
                            int r1 = random.nextInt(3) + 11;    //生成11到14之间的随机数
                            String str_r1 = rBase[r1];  
                            //生成第二位区码  
                            int r2;  
                            if(r1 == 13){  
                                r2 = random.nextInt(7);         //生成0到7之间的随机数  
                            }else{  
                                r2 = random.nextInt(16);        //生成0到16之间的随机数
                            }  
                            String str_r2 = rBase[r2];  
                            //生成第一位位码  
                            int r3 = random.nextInt(6) + 10;    //生成10到16之间的随机数
                            String str_r3 = rBase[r3];  
                            //生成第二位位码  
                            int r4;  
                            if(r3 == 10){  
                                r4 = random.nextInt(15) + 1;    //生成1到16之间的随机数 
                            }else if(r3 == 15){  
                                r4 = random.nextInt(15);        //生成0到15之间的随机数
                            }else{  
                                r4 = random.nextInt(16);        //生成0到16之间的随机数
                            }  
                            String str_r4 = rBase[r4];  
                            //将生成的机内码转换为汉字  
                            byte[] bytes = new byte[2];  
                            //将生成的区码保存到字节数组的第一个元素中  
                            String str_12 = str_r1 + str_r2;  
                            int tempLow = Integer.parseInt(str_12, 16);  
                            bytes[0] = (byte) tempLow;  
                            //将生成的位码保存到字节数组的第二个元素中  
                            String str_34 = str_r3 + str_r4;  
                            int tempHigh = Integer.parseInt(str_34, 16);  
                            bytes[1] = (byte)tempHigh; 
                     
                            ctmp = new String(bytes);           //根据字节数组生成汉字
                            //测试参数
//                          System.out.println("生成汉字:" + ctmp);  
                            break;  
                     default:  
                            itmp = random.nextInt(10) + 48;     //生成0~9的数字
                            ctmp = String.valueOf((char)itmp);  
                            break;  
                  }
                  sRand += ctmp;  
                  Color color = new Color(20 + random.nextInt(110), 20 + random.nextInt(110), random.nextInt(110));  
                  g.setColor(color);  
            
                  //将生成的随机数进行随机缩放并旋转制定角度                        PS.建议不要对文字进行缩放与旋转,因为这样图片可能不正常显示  
                  //将文字旋转制定角度  
                  Graphics2D g2d_word = (Graphics2D)g;  
                  AffineTransform trans = new AffineTransform();
                  //初始化 RotateTransform 类的一个新实例,该实例具有指定的角度和中心点
                  trans.rotate((45) * 3.14 / 180, 15 * i + 8, 7);  
                  //缩放文字  
                  float scaleSize = random.nextFloat() + 0.8f;  
                  if(scaleSize > 1f) scaleSize = 1f;  
                  trans.scale(scaleSize, scaleSize);  
                  g2d_word.setTransform(trans);  
                  g.drawString(ctmp, 15 * i + 18, 14);  
               }  
               //将生成的验证码保存到Session中  
               HttpSession session = request.getSession(true);  
               session.setAttribute("randCheckCode", sRand);  
               //释放g所占用的系统资源
               g.dispose();   
               //输出图片
               ImageIO.write(image, "JPEG", response.getOutputStream());  
        }  
}




 2.配置Servlet

 在web.xml中的配置如下:


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
	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_3_0.xsd">
  <display-name></display-name>
  <servlet>
    <description>输出验证码</description>
    <display-name>This is the display name of my J2EE component</display-name>
    <servlet-name>PictureCheckCode</servlet-name>
    <servlet-class>com.servlet.PictureCheckCode</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>PictureCheckCode</servlet-name>
    <url-pattern>/picturecheckcode</url-pattern>
  </servlet-mapping>	
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>




3.测试验证码

      可以编写JSP页面来验证是否可以输出验证码图片,JSP代码如下:

1.index.jsp:显示界面


    1. <%@ page language="java" import="java.util.*" pageEncoding="gbk"%>  
    2.   
    3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
    4. <html>  
    5.     <head>  
    6.         <title>验证码</title>  
    7. "javascript">  
    8. function myReload() {  
    9. "CreateCheckCode").src = document  
    10. "CreateCheckCode").src  
    11. "?nocache=" + new
    12. }  
    13. </script>  
    14.     </head>  
    15.   
    16.     <body>  
    17. "Check.jsp" method="post">  
    18. "checkCode" type="text" id="checkCode" title="验证码区分大小写"
    19. "8" ,maxlength="4"
    20. "PictureCheckCode" id="CreateCheckCode" align="middle">  
    21. "" οnclick="myReload()"> 看不清,换一个</a>  
    22. "submit" value="提交"
    23.         </form>  
    24.     </body>  
    25. </html>


     

    2.Check.jsp :主要验证提交的数据是否和Session中保存的验证码是否相同


      1. <%@ page language="java" import="java.util.*" pageEncoding="gbk"%>  
      2. <html>  
      3.   <head>  
      4.     <title>验证码校验</title>  
      5.   </head>  
      6.     
      7.   <body>  
      8.     <%  
      9. "checkCode");  
      10. if(checkcode.equals("")||checkcode==null){  
      11. "<script>alert('请输入验证码');window.location.href('index.jsp')</script>");  
      12. else{  
      13. if(!checkcode.equalsIgnoreCase((String)session.getAttribute("randCheckCode"))){  
      14. "<script>alert('验证码不正确,请重新输入');history.back(-1);</script>");  
      15. else{  
      16. "登录成功");  
      17.             }  
      18.         }  
      19.      %>  
      20.   </body>  
      21. </html>


       

      3.工程项目结构,及运行截图 

      java session注册验证码 java web验证码_java

      java session注册验证码 java web验证码_验证码_02