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

本文详细介绍了如何使用Java实现一个每秒生成约83张验证码图片的验证码生成器,包括配置参数的设定、初始化过程以及生成图片的具体步骤。此程序能够自动生成包含数字和字母的随机验证码,并将其保存到会话中,同时禁止图像缓存,确保安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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张验证码。验证码图样如下
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值