java生成验证码(多种抗OCR识别技术)随机间距、干扰线、背景变化、旋转、扭曲等

package cmcc.jx.ict.xsgj.system.yzm.action;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.ServletActionContext;

import sun.font.FontDesignMetrics;

import com.opensymphony.xwork2.ActionSupport;

/**
 * @author 朱银涛 
 * @version : 2017年2月8日
 */
public class ValidateCodeAction extends ActionSupport{

	//验证码存在session中的name
	public static final String VALIDATE_CODE = "code";
	//可选字体
	String[] fontTypes = {"Arial","Arial Black","AvantGarde Bk BT","Calibri","Times New Roman","宋体","黑体","Arial Unicode MS","Lucida Sans"};
	//随机字符的范围
	char[] codeSeq = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J','K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
			'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9'};
	//验证码长度
	private final int CODE_LENGTH = 4;
	//验证码的宽和高
	private int w;
	private int h = 25;
	Random random = new Random();
	
	public static boolean validate(HttpServletRequest request, String validateCode){
		String code = (String)request.getSession().getAttribute(VALIDATE_CODE);
		return validateCode.toUpperCase().equals(code); 
	}

	public void validateCode(){
		HttpServletRequest request = ServletActionContext.getRequest();
		HttpServletResponse response = ServletActionContext.getResponse();
		String rd = (String) request.getSession().getAttribute("rd");
		String rd2 = request.getParameter("rd2");
		System.out.println("session中的数字"+rd);
		System.out.println("request中的数字"+rd2);

		request.getSession().removeAttribute("rd");   //删除session中的数字
		try {
			if (rd != null && rd.equals(rd2)) {
				createImage(request,response);
			}else{
				response.sendRedirect("error.jsp");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 生成图像数据
	 * */
	private void createImage(HttpServletRequest request,
			HttpServletResponse response) throws IOException {

		response.setHeader("Pragma", "no-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0);
		response.setContentType("image/jpeg");
		/*
		 * 得到参数高,宽,都为数字时,则使用设置高宽,否则使用默认值
		 */
		String width = request.getParameter("width");
		String height = request.getParameter("height");
		if ((width != null && "".equals(width))&&(height != null && "".equals(height))) {
			w = Integer.valueOf(width);
			h = Integer.valueOf(height);
		}else{
			w = CODE_LENGTH * 18 +20;
		}
		BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
		//获取图片上下文
		Graphics g = image.getGraphics();
		Graphics2D g2 = (Graphics2D) g;
		/*
		 * 生成背景
		 */
		createBackground(g2);
		/*
		 * 生成字符
		 */
		String s = createCharacter(g2);
		request.getSession().setAttribute(VALIDATE_CODE, s);
		
		g2.dispose();
		OutputStream out = response.getOutputStream();
		ImageIO.write(image, "JPEG", out);
		out.close();

	}
	/**
	 * 生成随机颜色
	 * @param fc 产生颜色值下限
	 * @param bc 产生颜色值上限
	 * @return 生成的随机颜色对象
	 */
	private Color getRandColor(int fc,int bc) { 
		int f = fc;
		int b = bc;
		if(f>255) {
			f=255; 
		}
		if (f<1) {
			f=1;
		}
		if(b>255) {
			b=255; 
		}
		if (b<1) {
			b=1;
		}
		return new Color(f+random.nextInt(b-f),f+random.nextInt(b-f),f+random.nextInt(b-f)); 
	}

	private void createBackground(Graphics2D g) {
		// 填充背景
		g.setColor(getRandColor(220,250)); 
		g.fillRect(0, 0, w, h);
		// 加入干扰线条
		for (int i = 0; i < 7; i++) {
			g.setColor(getRandColor(40,150));
			int x = random.nextInt(w);
			int y = random.nextInt(h);
			int x1 = random.nextInt(w);
			int y1 = random.nextInt(h);
			g.drawLine(x, y, x1, y1);
		}
	}

	//生成随机字符并且返回
	private String createCharacter(Graphics2D g) {
		StringBuilder s = new StringBuilder();
		int fontsize;  //生成字符的字体大小
		int charX = 0; //生成字符x的位置
		int chartY = h - 5; //生成字符y的位置
		Color color = g.getColor();
		//旋转或扭曲
        int rotateOrWarp = random.nextInt(2);
		for (int i = 0; i < CODE_LENGTH; i++) {
			String r = String.valueOf(codeSeq[random.nextInt(codeSeq.length)]);//random.nextInt(10));
			//随机设置字体颜色
			g.setColor(new Color(50 + random.nextInt(100), 50 + random.nextInt(100), 50 + random.nextInt(100)));
			//随机字体大小18-22
			fontsize = Math.abs(18+random.nextInt(4));
			Font font = new Font(fontTypes[random.nextInt(fontTypes.length)],Font.BOLD,fontsize);
			g.setFont(font); 
			
			FontMetrics fontMetrics = FontDesignMetrics.getMetrics(font);  
            int charWidth = fontMetrics.stringWidth("M"); //当前随机生成字符的宽度  
            int charsRealWidth = charWidth * CODE_LENGTH;
            //第一次循环的时候初始化
            if (i == 0) {
            	if(w > charsRealWidth){  
                    charX = (w - charsRealWidth)/2;  
                } 
			}
			if(rotateOrWarp == 0){
				//画旋转文字
	            double radianPercent = 0D;  
	            radianPercent =  Math.PI * (random.nextInt(40)/180D);  
	            if(random.nextBoolean()) radianPercent = -radianPercent;  
	            g.rotate(radianPercent, charX + 9, chartY);  
	            g.drawString(r, charX, chartY);  
	            g.rotate(-radianPercent, charX + 9, chartY);  
	            charX += charWidth;  
			}else{
				g.drawString(r, charX, chartY);
				charX += charWidth;
			}
			s.append(r);
		}
		if (rotateOrWarp == 1) {
			//扭曲
			shear(g, w, h, color);
		}
		return s.toString();
	}
	
	// 扭曲方法
	private void shear(Graphics g, int w1, int h1, Color color) {
		shearX(g, w1, h1, color);
		shearY(g, w1, h1, color);
	}

	private void shearX(Graphics g, int w1, int h1, Color color) {
		int period = random.nextInt(2);

		boolean borderGap = true;
		int frames = 1;
		int phase = random.nextInt(2);

		for (int i = 0; i < h1; i++) {
			double d = (double) (period >> 1)
					* Math.sin((double) i / (double) period
							+ (6.2831853071795862D * (double) phase)
							/ (double) frames);
			g.copyArea(0, i, w1, 1, (int) d, 0);
			if (borderGap) {
				g.setColor(color);
				g.drawLine((int) d, i, 0, i);
				g.drawLine((int) d + w1, i, w1, i);
			}
		}

	}

	private void shearY(Graphics g, int w1, int h1, Color color) {

		int period = random.nextInt(8)+8;

		boolean borderGap = true;
		int frames = 20;
		int phase = 7;
		for (int i = 0; i < w1; i++) {
			double d = (double) (period >> 1)
					* Math.sin((double) i / (double) period
							+ (6.2831853071795862D * (double) phase)
							/ (double) frames);
			g.copyArea(i, 0, 1, h1, 0, (int) d);
			if (borderGap) {
				g.setColor(color);
				g.drawLine(i, (int) d, i, 0);
				g.drawLine(i, (int) d + h1, i, h1);
			}

		}

	}

	//验证码安全检验
	public void safetyTest(){
		HttpServletRequest request = ServletActionContext.getRequest();
		HttpServletResponse response = ServletActionContext.getResponse();
		String rd="";
		Random random = new Random();
		for(int i=0;i<5;i++){
			rd += random.nextInt(10);
		}
		System.out.println("随机出的数字:"+rd);
		request.getSession().setAttribute("rd", rd);
		long d = new Date().getTime();
		System.out.println("当前验证码的时间:"+d);
		String json = rd+"-"+d;
		try {
			response.getWriter().write(json);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

 

 

<package name="system-validateCode" extends="struts-default">
		<action name="validateCode" class="validateCodeAction" method="validateCode">
		</action>
		<action name="safetyTest" class="validateCodeAction" method="safetyTest">
		</action>
	</package>

 

<%
	//properties 配置文件名称
	PropertyResourceBundle res = (PropertyResourceBundle) PropertyResourceBundle.getBundle("validateCode");
	// 获取properties配置文件中的验证码过期时间的值
	String oldTime = res.getString("validateCode.oldTime");
%>
<script src="./js/jquery-1.7.2.min.js"></script>
<script language="javascript">
		$(document).ready(function (){
			$("#validateCode2").trigger("click");
		});
		var ddd;   //验证码生成的时间
		var timeArray;  //记录验证码每次刷新的时间 10秒钟最多刷新4次
		function validateCodeRefresh(){
			if(limitRefresh(10,4)){
				$.post("safetyTest.action",function(data){
					var data2 = data.split("-");
					ddd = data2[1];
					$("#validateCode2").attr("src","validateCode.action?"+new Date().getTime()+"&rd2="+data2[0]);
				});
			}else{
			 	alert("刷新过于频繁,请稍后再试...");
			}
		}
		//点击登录按钮
		function mysubmit() {
			var a = $("#validateCode").val();
			if(a == "" || a == null){
				alert("请输入验证码!");
				
				return false;
			}
			var newDate = new Date().getTime();
			var oldTime = parseInt("<%=oldTime %>");
			if(isNaN(oldTime)){
				oldTime = 10;
			}
			//验证码超时判断
			if(ddd != "" && ddd != null && newDate - ddd >= oldTime*1000){
				alert("验证码超时...");
				$("#validateCode2").trigger("click");
			}else{
				//提交表单
			}
			return true;
		}
	
		function limitRefresh(allTime,count){
			var newTime = new Date().getTime();
			if (timeArray == undefined) {
				timeArray = new Array();
			}else{
				var ttt = 0;
				for (var i=0;i<timeArray.length;i++) {
					if (newTime - timeArray[i] < allTime*1000) {
						ttt++;
					}else{
						//每隔十秒就可以清空一次
						timeArray = new Array();
						break;
					}
					if (ttt >= count) {
						return false;
					}
				}
			}
			timeArray.push(newTime);
			return true;
		}
	</script>

<td height="30" align="right" nowrap><strong>验证码:</strong></td>
<td nowrap>
	<input id="validateCode" name="j_code" maxlength="5" type="text" style="position:relative; top:1px;width:87px;">
        <img id="validateCode2" onclick="validateCodeRefresh()" style="position:relative; top:4px;">
</td>

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值