`
kong0itey
  • 浏览: 299027 次
社区版块
存档分类
最新评论

我写的验证码生成方案,可防止绝大多数机械识别。

    博客分类:
  • java
阅读更多
web.xml
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
	<!-- ******************************************** -->
	<!-- **********验证码生成器************************** -->
	<!-- ******************************************** -->
	<servlet>
		<servlet-name>CaptchaServlet</servlet-name>
		<servlet-class>com.lowca.activity.web.servlet.CaptchaServlet</servlet-class>
		<init-param>
			<param-name>width</param-name>
			<param-value>150</param-value>
		</init-param>
		<init-param>
			<param-name>height</param-name>
			<param-value>100</param-value>
		</init-param>
		<init-param>
			<param-name>bgColor</param-name>
			<param-value>255,255,255</param-value>
		</init-param>
		<init-param>
			<param-name>fontColor</param-name>
			<param-value>0,255,0</param-value>
		</init-param>
		<init-param>
			<param-name>fontSize</param-name>
			<param-value>44</param-value>
		</init-param>
		<init-param>
			<param-name>fontCount</param-name>
			<param-value>4</param-value>
		</init-param>
		<init-param>
			<param-name>fontName</param-name>
			<param-value>宋体</param-value>
		</init-param>
		<init-param>
			<param-name>chars</param-name>
			<!-- 去掉了容易造成误解的字符,例如:i o z 和 1 0 2 -->
			<param-value>ABCDEFGHJKLMNPQRSTUVWXYabcdefghjkmnpqrstuvwxy3456789</param-value>
		</init-param>
		<init-param>
			<param-name>sessionKey</param-name>
			<param-value>com.lowca.activity.captcha</param-value>
		</init-param>
		<init-param>
			<param-name>maxRotateAngle</param-name>
			<param-value>40</param-value>
		</init-param>
		<init-param>
			<param-name>fontPadding</param-name>
			<param-value>-15</param-value>
		</init-param>
	</servlet>

	<servlet-mapping>
		<servlet-name>CaptchaServlet</servlet-name>
		<url-pattern>/captcha.jpg</url-pattern>
	</servlet-mapping>
</web-app>


servlet类文件
package com.lowca.activity.web.servlet;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;

public class CaptchaServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	private static final String CONTENT_TYPE = "image/jpeg";

	// ==================以下变量用于保存配置参数的默认值 ==================
	/**
	 * 验证码的宽度
	 */
	private int width = 200;
	/**
	 * 验证码的高度
	 */
	private int height = 150;
	/**
	 * 验证码背景色
	 */
	private Color bgColor = Color.WHITE;
	/**
	 * 文字颜色
	 */
	private Color fontColor = Color.GREEN;
	/**
	 * 验证码字符字号
	 */
	private int fontSize = 42;
	/**
	 * 验证码字符个数
	 */
	private int fontCount = 4;
	/**
	 * 验证码字符间距,单位是像素
	 */
	private int fontPadding = -15;
	/**
	 * 验证码字符最大旋转角度
	 */
	private int maxRotateAngle = 40;
	/**
	 * 验证码字体
	 */
	private String fontName = "宋体";
	/**
	 * 验证码用到的字符
	 */
	private String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
	/**
	 * 验证码在session中的键名
	 */
	private String sessionKey = "com.lowca.activity.captcha";

	// ==================以下变量用于在初始化时候保存数据,减少重复计算 ==================

	private Font font;

	private char[] seedArray;

	private int offsetX = 0;

	private int offsetY = 0;

	/**
	 * 生成由数字和字母随机组成的图片
	 */
	protected void service(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, java.io.IOException {
		BufferedImage buffImg = new BufferedImage(width, height,
				BufferedImage.TYPE_INT_RGB);
		Graphics2D g2d = buffImg.createGraphics();
		g2d.setColor(bgColor);
		g2d.fillRect(0, 0, width, height);
		g2d.setPaint(fontColor);
		g2d.setFont(font);
		// 旋转文本

		StringBuffer randCode = new StringBuffer();
		for (int i = 0; i < fontCount; i++) {
			g2d.setStroke(new BasicStroke((float) (Math.random() * 5)));
			double angle = Math.random() * maxRotateAngle * Math.PI / 180;
			int p = (int) (Math.random() * chars.length());
			String word = String.valueOf(seedArray[p]);
			randCode.append(word);
			int x = offsetX + i * (fontSize + fontPadding);

			AffineTransform origXform = g2d.getTransform();
			AffineTransform newXform = (AffineTransform) (origXform.clone());
			newXform.rotate(angle, x, offsetY);
			g2d.setTransform(newXform);
			g2d.drawString(word, x, offsetY);
			g2d.setTransform(origXform);
		}
		g2d.setStroke(new BasicStroke(2.0f));
		int x = offsetX - (int) (20 * Math.random());
		int y = offsetY - (int) (20 * Math.random());
		int w = (int) (width - 10 - Math.random() * 6);
		int h = (int) (height - 10 - Math.random() * 6);
		int startAngle = (int) (Math.random() * 16 + 45);
		int arcAngle = (int) (Math.random() * 45 + 90);
		g2d.drawArc(x, y, w, h, startAngle, arcAngle);
		g2d.dispose();

		// 将四位数字的验证码保存到Session里面
		HttpSession session = req.getSession();
		session.setAttribute(sessionKey, randCode);

		// 禁止图像缓存
		resp.setHeader("Prama", "no-cache");
		resp.setHeader("Coche-Control", "no-cache");
		resp.setDateHeader("Expires", 0);

		// 将图像输出到Servelt输出流中
		ServletOutputStream out = resp.getOutputStream();
		ImageIO.write(buffImg, "jpeg", out);
		out.close();
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType(CONTENT_TYPE);
	}

	public void init() throws ServletException {
		// 初始化配置参数
		String param = getInitParameter("width");
		if (NumberUtils.isDigits(param)) {
			width = Integer.parseInt(param);
		}
		param = getInitParameter("height");
		if (NumberUtils.isDigits(param)) {
			height = Integer.parseInt(param);
		}
		param = getInitParameter("bgColor");
		if (param != null && param.matches("^\\d+,\\d+,\\d+$")) {
			bgColor = getColor(param);
		}
		param = getInitParameter("fontColor");
		if (param != null && param.matches("^\\d+,\\d+,\\d+$")) {
			fontColor = getColor(param);
		}
		param = getInitParameter("fontSize");
		if (NumberUtils.isDigits(param)) {
			fontSize = Integer.parseInt(param);
		}
		param = getInitParameter("maxRotateAngle");
		if (NumberUtils.isDigits(param)) {
			maxRotateAngle = Integer.parseInt(param);
		}
		param = getInitParameter("fontPadding");
		if (param != null && param.matches("-?\\d+")) {
			fontPadding = Integer.parseInt(param);
		}
		param = getInitParameter("fontName");
		if (StringUtils.isNotBlank(param)) {
			fontName = param;
		}
		param = getInitParameter("chars");
		if (StringUtils.isNotBlank(param)) {
			chars = param;
		}
		param = getInitParameter("sessionKey");
		if (StringUtils.isNotBlank(sessionKey)) {
			sessionKey = param;
		}
		// 初始化状态变量
		font = new Font(fontName, Font.ITALIC, fontSize);
		seedArray = chars.toCharArray();
		offsetX = width / 2 - fontCount * fontSize / 2 - (fontCount - 1)
				* fontPadding / 2 - 8;
		offsetY = height / 2 + fontSize / 2 - 8;
	}

	private Color getColor(String rgb) {
		String[] array = rgb.split(",");
		return new Color(Integer.parseInt(array[0]),
				Integer.parseInt(array[1]), Integer.parseInt(array[2]));
	}

}


在我的机器上,这个程序每秒钟可以产生大约83张验证码。验证码图样如下
  • 大小: 2.6 KB
  • 大小: 2.5 KB
  • 大小: 2.4 KB
  • 大小: 2.4 KB
分享到:
评论
1 楼 我会是微博 2015-03-11  
<img src="CaptchaServlet" />是这样调用么?为何显示不了?

相关推荐

Global site tag (gtag.js) - Google Analytics