java 验证码实现

功能:验证码,多种背景图,多种字体,相互变换。

实现原理:你懂的。

技术:ajax html struts 

步骤:

1.jsp 页面 包括 srcipt 和 html 

   	<script>
   	var ccUrl = '<%=request.getContextPath() %>/invest/verifyCode.action';
    $(function () {
  	  //点击图片更换验证码
        $("#changeImages").click(function(){
  	        $("#Verify").attr("src","<%=request.getContextPath()%>/invest/imagecode.action?timestamp="+new Date().getTime());
  	    });
  	 });
  	 
  function checkCodePaper()
  {
	 	var re = false;
  		var dataInfo = $('#firsForm').serialize();
  	    try{
  		    $.ajax
  		    (
  				{
  					type: "POST",
  					url:ccUrl, 
  					dataType: 'json',
  					data:dataInfo,
  					async: false,
  					success: function (data)
  					{			
  					    	if(data=='n')
  					    	{
  					    	<span style="white-space:pre">	</span>alert('success')
  					    	
  					    	}
  					    	else
  					    	{
  					    	<span style="white-space:pre">	</span>alert('worry')
  	  							re = true;
  					    	}
  					}
  				}
  			)
  	    }catch(e)
  	    {
  			alert("数据加载失败!"+e);
  	    }
  	return re;
  	
  }	
   	</script>
<body class="project">
	<form name="queryForm" id="firsForm" action="" method="post">
 <span style="white-space:pre">		</span><table width="100%">
<span style="white-space:pre">			</span><tr>
                             <td align="right">验证码</td>
                             <td>
                               <input type="text" value='' maxlength="4" id="verifyCode" name="verifyCode" οnblur="checkCodePaper()" class="form-control word pull-left"/>
   				 <a href="script:void(0)" id="changeImages" > <img src="<%=request.getContextPath()%>/invest/imagecode.action" id="Verify"  style="cursor:pointer;display: block;border:0;width:115px;height:45px;margin-left:10px;float: left;" alt="看不清,换一张" /></a>
   				 <span class="span_wrong d3 form-group" id="codeResult"></span>
                             </td>
                        </tr>
<span style="white-space:pre">		</span></table>
     </form>
 </body>

2.struts.xml

			<!-- 验证码 -->
			
			<action name="imagecode" class="com.hksj.rrcpro.front.action.SecurityCodeImageAction" method="imagecode">
					<result name="success" type="stream">
             			 <param name="contentType">image/jpeg</param>
            			 <param name="inputName">imageStream</param>
            			 <param name="bufferSize">2048</param>
        			 </result>
			</action>
			<action name="verifyCode" class="com.hksj.rrcpro.front.action.SecurityCodeImageAction" method="verifyCode">
				
			</action>


3.SecurityCodeImageAction

package com.hksj.rrcpro.front.action;



import java.io.ByteArrayInputStream;
import java.util.Map;

import org.apache.struts2.interceptor.SessionAware;

import com.hksj.rrcpro.core.util.CommonUtil;
import com.hksj.rrcpro.front.common.SecurityCode;
import com.hksj.rrcpro.front.common.SecurityCode.SecurityCodeLevel;
import com.hksj.rrcpro.front.common.SecurityImage;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;


public class SecurityCodeImageAction  extends ActionSupport  implements SessionAware{
	private static final long serialVersionUID = 1496691731440581303L;
	//图片流
    private ByteArrayInputStream imageStream;
    //session域
    private Map<String, Object> session ;
    
    private String verifyCode;
    
    public ByteArrayInputStream getImageStream() {
        return imageStream;
    }
    public void setImageStream(ByteArrayInputStream imageStream) {
        this.imageStream = imageStream;
    }
    public void setSession(Map<String, Object> session) {
        this.session = session;
    }
    
    public Map<String, Object> getSession() {
		return session;
	}
    
    
	public String getVerifyCode() {
		return verifyCode;
	}
	public void setVerifyCode(String verifyCode) {
		this.verifyCode = verifyCode;
	}

    public String imagecode() throws Exception {
        //如果开启Hard模式,可以不区分大小写
    	String securityCode = SecurityCode.getSecurityCode(4,SecurityCodeLevel.Hard, false).toLowerCase();
        
        //获取默认难度和长度的验证码
       // String securityCode = SecurityCode.getSecurityCode();
        imageStream = SecurityImage.getImageAsInputStream(securityCode);
        //放入session中
        session.put("securityCode", securityCode);
        ActionContext.getContext().getSession().put("securityCode", securityCode);
        return SUCCESS;
    }
	

    public String verifyCode() throws Exception {
        //如果开启Hard模式,可以不区分大小写
    	verifyCode = convertString(verifyCode);
		if(verifyCode.equals(session.get("securityCode")))
		{
			return CommonUtil.jsonOut("y");
		}
		else
		{
			return CommonUtil.jsonOut("n");
		}
        
    }
    /**
     * 大写转化成小写
     * @param src
     * @return
     */
    public static String convertString(String src)
    {
         char[] array = src.toCharArray();
          int temp = 0;
          for (int i = 0; i < array.length; i++)
          {
              temp = (int) array[i];
              if (temp <= 90 && temp >= 65)
              { // array[i]为大写字母
                  array[i] = (char) (temp + 32);
              } 
              else
              {
            	  array[i] = (char) (temp);
              }
           }
           return String.valueOf(array);
       }
}


4.SecurityImage

package com.hksj.rrcpro.front.common;



import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;

/**
 * 验证码生成器类,可生成数字、大写、小写字母及三者混合类型的验证码。
 * 支持自定义验证码字符数量;
 * 支持自定义验证码图片的大小;
 * 支持自定义需排除的特殊字符;
 * 支持自定义干扰线的数量;
 * 支持自定义验证码图文颜色
 * @author yzj
 * @version 1.0 
 */
public class SecurityImage {
	     /**
	       * 生成验证码图片
	       * @param securityCode   验证码字符
	       * @return  BufferedImage  图片
	      */
	     public static BufferedImage createImage(String securityCode){
	         //验证码长度
	         int codeLength=securityCode.length();
	         //字体大小
	        int fSize = 20;
	          int fWidth = fSize + 1;
	         //图片宽度
	         int width = codeLength * fWidth + 6 ;
	         //图片高度
	         int height = fSize * 2 + 1;
	          //图片
	          BufferedImage image=new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
	          Graphics g=image.createGraphics();
	         //设置背景色
	          g.setColor(Color.WHITE);
	           //填充背景
	          g.fillRect(0, 0, width, height);
	           //设置边框颜色
	          g.setColor(Color.LIGHT_GRAY);
	           //边框字体样式
	         // g.setFont(new Font("Arial", Font.BOLD, height - 2));
	          g.setFont(new Font("Aldine", Font.BOLD, height - 2));
	          
	           //绘制边框
	          g.drawRect(0, 0, width - 1, height -1);
	           //绘制噪点
	          Random rand = new Random();
	           //设置噪点颜色
	          // g.setColor(Color.LIGHT_GRAY);
	          g.setColor(Color.black);
	           for(int i = 0;i < codeLength * 6;i++){
	               int x = rand.nextInt(width);
	               int y = rand.nextInt(height);
	              //绘制1*1大小的矩形
	               g.drawRect(x, y, 10, 1);
	           }
	          //绘制验证码
	         int codeY = height - 10;  
	          //设置字体颜色和样式
	           //g.setColor(new Color(19,148,246));
	         Random rand2 = new Random(5);
	         //System.out.println("rand2 = "+rand2.hashCode()%5);
	         switch(rand2.hashCode()%5)
	         {
	         case 1:
	        	 g.setColor(new Color(200,148,201));
	 	         g.setFont(new Font("Aldine", Font.BOLD, fSize));
	        	 break;
	         case 2:
	        	 g.setColor(new Color(10,15,20));
	 	         g.setFont(new Font("Georgia", Font.BOLD, fSize));
	        	 break;
	         case 3:
	        	 g.setColor(new Color(100,105,209));
	 	         g.setFont(new Font("Arial", Font.BOLD, fSize));
	        	 break;
	         case 4:
	        	 g.setColor(new Color(150,15,2));
	 	         g.setFont(new Font("Serif", Font.BOLD, fSize));
	        	 break;
	        default:
	        	 g.setColor(new Color(250,15,100));
	 	         g.setFont(new Font("Aldine", Font.BOLD, fSize)); 
	        	 break;
	        	 
	         }
	         
	      
	         
	           for(int i = 0; i < codeLength;i++){
	               g.drawString(String.valueOf(securityCode.charAt(i)), i * 16 + 5, codeY);
	          }
	           //关闭资源
	           g.dispose();
	           return image;
	       }
	       /**
	       * 返回验证码图片的流格式
	       * @param securityCode  验证码
	        * @return ByteArrayInputStream 图片流
	        */
	       public static ByteArrayInputStream getImageAsInputStream(String securityCode){
	         BufferedImage image = createImage(securityCode);
	          return convertImageToStream(image);
	      }
	      /**
	        * 将BufferedImage转换成ByteArrayInputStream
	        * @param image  图片
	        * @return ByteArrayInputStream 流
	        */
	       private static ByteArrayInputStream convertImageToStream(BufferedImage image){
	         ByteArrayInputStream inputStream = null;
	          ByteArrayOutputStream bos = new ByteArrayOutputStream();
	          try {
	              ImageIO.write(image, "JPEG", bos);
	              byte[] bts = bos.toByteArray();
	              inputStream = new ByteArrayInputStream(bts);
	          } catch (IOException e1) {
	              // TODO Auto-generated catch block
	              e1.printStackTrace();
	          }
	          return inputStream;
	     }
}


5.SecurityCode

package com.hksj.rrcpro.front.common;


import java.util.Arrays;
/**
  * 工具类,生成随机验证码字符串
  * @version 1.0 2012/12/01
  * @author yzj
  *
  */
public class SecurityCode {
	    /**
	      * 验证码难度级别,Simple只包含数字,Medium包含数字和小写英文,Hard包含数字和大小写英文
	      */
	     public enum SecurityCodeLevel {Simple,Medium,Hard};
	     
	     /**
	      * 产生默认验证码,4位中等难度
	     * @return  String 验证码
	     */
	    public static String getSecurityCode(){
	         return getSecurityCode(4,SecurityCodeLevel.Medium,false);
	     }
	    /**
	     * 产生长度和难度任意的验证码
	     * @param length  长度
	      * @param level   难度级别
	      * @param isCanRepeat  是否能够出现重复的字符,如果为true,则可能出现 5578这样包含两个5,如果为false,则不可能出现这种情况
	     * @return  String 验证码
	     */
	     public static String getSecurityCode(int length,SecurityCodeLevel level,boolean isCanRepeat){
	         //随机抽取len个字符
	         int len=length;
	         
	         //字符集合(除去易混淆的数字0、数字1、字母l、字母o、字母O)
	         char[] codes={'1','2','3','4','5','6','7','8','9',
	                       'A','B','C','D','E','F','G','H','I','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z'};
	         
	         //根据不同的难度截取字符数组
	         if(level==SecurityCodeLevel.Simple){
	             codes=Arrays.copyOfRange(codes, 0,9);
	         }else if(level==SecurityCodeLevel.Medium){
	             codes=Arrays.copyOfRange(codes, 0,33);
	         }
	         //字符集合长度
	         int n=codes.length;
	        
	         //抛出运行时异常
	         if(len>n&&isCanRepeat==false){
	             throw new RuntimeException(
	                    String.format("调用SecurityCode.getSecurityCode(%1$s,%2$s,%3$s)出现异常,当isCanRepeat为%3$s时,传入参数%1$s不能大于%4$s",
	                                    len,level,isCanRepeat,n));
	        }
	        //存放抽取出来的字符
	         char[] result=new char[len];
	         //判断能否出现重复的字符
	        if(isCanRepeat){
	             for(int i=0;i<result.length;i++){
	                 //索引 0 and n-1
	                 int r=(int)(Math.random()*n);
	             
	                 //将result中的第i个元素设置为codes[r]存放的数值
	                 result[i]=codes[r];
	            }
	         }else{
	             for(int i=0;i<result.length;i++){
	                 //索引 0 and n-1
	                 int r=(int)(Math.random()*n);
	                
	                 //将result中的第i个元素设置为codes[r]存放的数值
	                 result[i]=codes[r];
	                 
	                //必须确保不会再次抽取到那个字符,因为所有抽取的字符必须不相同。
	                 //因此,这里用数组中的最后一个字符改写codes[r],并将n减1
	                codes[r]=codes[n-1];
	                n--;
	             }
	        }
	         return String.valueOf(result);
	    }
}


以上内容都复制过去 就可以 实现java 的验证码功能。

PS:com.sun.image.codec.jpeg不存在 错误在本例中是不会出现的。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值