这个验证码将包括以下特性:
1. 7个字符,包含英文大小写字母、数字和符号;
2. 不同的字符将有不同的颜色;
3. 字符随机旋转;
4. 随机噪点(包括随机噪点颜色、数量和大小);
5. 随机干扰弧线(包括干扰弧线颜色、数量、宽度和角度);
6. 随机干扰直线(包括干扰直线颜色、数量、宽度和长度);
7. 随机背景色;
8. 随机字体(包括字体、大小和样式)。
下面是这个验证码的示例代码:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.QuadCurve2D;
import java.awt.image.BufferedImage;
import java.io.OutputStream;
import java.util.Random;
import javax.imageio.ImageIO;
public class ComplexCaptchaUtil {
private static final int IMAGE_WIDTH = 200; // 验证码图片宽度
private static final int IMAGE_HEIGHT = 80; // 验证码图片高度
private static final int CHAR_COUNT = 7; // 字符个数
private static final String CHAR_SET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+[];:/?<>,.'{}\"\\|~`"; // 字符集
private static final int CHAR_SPACING = 20; // 字符间距
private static final int ROTATION_RANGE = 45; // 字符随机旋转角度范围
private static final int NOISE_POINT_COUNT = 200; // 随机噪点数量
private static final int NOISE_POINT_RADIUS_MIN = 1; // 随机噪点半径最小值
private static final int NOISE_POINT_RADIUS_MAX = 3; // 随机噪点半径最大值
private static final int NOISE_ARC_COUNT = 6; // 随机弧线数量
private static final int NOISE_ARC_WIDTH_MIN = 5; // 随机弧线宽度最小值
private static final int NOISE_ARC_WIDTH_MAX = 10; // 随机弧线宽度最大值
private static final int NOISE_ARC_ANGLE_MIN = -30; // 随机弧线角度最小值
private static final int NOISE_ARC_ANGLE_MAX = 30; // 随机弧线角度最大值
private static final int NOISE_LINE_COUNT = 20; // 随机直线数量
private static final int NOISE_LINE_WIDTH_MIN = 1; // 随机直线宽度最小值
private static final int NOISE_LINE_WIDTH_MAX = 3; // 随机直线宽度最大值
private static final int NOISE_LINE_LENGTH_MIN = 10; // 随机直线长度最小值
private static final int NOISE_LINE_LENGTH_MAX = 30; // 随机直线长度最大值
private static final String[] FONT_NAMES = { "Arial", "Courier New", "Georgia", "Times New Roman", "Verdana" }; // 字体名称
private static final int FONT_SIZE_MIN = 36; // 字体大小最小值
private static final int FONT_SIZE_MAX = 48; // 字体大小最大值
private static final int FONT_STYLE_NORMAL = Font.PLAIN; // 字体样式-正常
private static final int FONT_STYLE_BOLD = Font.BOLD; // 字体样式-加粗
private static final int FONT_STYLE_ITALIC = Font.ITALIC; // 字体样式-斜体
private static final int FONT_STYLE_BOLD_ITALIC = Font.BOLD | Font.ITALIC; // 字体样式-加粗斜体
private static final int BACKGROUND_COLOR_RANGE = 100; // 背景色范围
public static void generate(OutputStream os) throws Exception {
// 创建验证码图片
BufferedImage image = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
// 获取绘制对象
Graphics2D g = image.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
// 生成随机背景色
Random random = new Random();
int r = random.nextInt(BACKGROUND_COLOR_RANGE);
int gVal = random.nextInt(BACKGROUND_COLOR_RANGE);
int b = random.nextInt(BACKGROUND_COLOR_RANGE);
g.setColor(new Color(r, gVal, b));
g.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
// 设置字体
Font font = new Font(FONT_NAMES[random.nextInt(FONT_NAMES.length)],
getRandomFontStyle(), getRandomFontSize());
g.setFont(font);
// 随机生成字符、颜色、位置和旋转角度
char[] captcha = new char[CHAR_COUNT];
Color[] colors = new Color[CHAR_COUNT];
int[] xPos = new int[CHAR_COUNT];
int[] yPos = new int[CHAR_COUNT];
double[] rotations = new double[CHAR_COUNT];
for (int i = 0; i < CHAR_COUNT; i++) {
captcha[i] = CHAR_SET.charAt(random.nextInt(CHAR_SET.length()));
colors[i] = new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
xPos[i] = CHAR_SPACING * i + 10;
yPos[i] = IMAGE_HEIGHT / 2 + font.getSize() / 2 - random.nextInt(10);
rotations[i] = Math.toRadians(random.nextInt(ROTATION_RANGE) - ROTATION_RANGE / 2);
}
// 绘制字符
for (int i = 0; i < CHAR_COUNT; i++) {
g.setColor(colors[i]);
AffineTransform transform = new AffineTransform();
transform.rotate(rotations[i], xPos[i], yPos[i]);
g.setTransform(transform);
g.drawString(String.valueOf(captcha[i]), xPos[i], yPos[i]);
}
// 随机生成噪点
for (int i = 0; i < NOISE_POINT_COUNT; i++) {
int x = random.nextInt(IMAGE_WIDTH);
int y = random.nextInt(IMAGE_HEIGHT);
int radius = random.nextInt(NOISE_POINT_RADIUS_MAX - NOISE_POINT_RADIUS_MIN + 1)
+ NOISE_POINT_RADIUS_MIN;
Color color = new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
g.setColor(color);
g.fillOval(x, y, radius, radius);
}
// 随机生成干扰弧线
for (int i = 0; i < NOISE_ARC_COUNT; i++) {
int x1 = random.nextInt(IMAGE_WIDTH);
int y1 = random.nextInt(IMAGE_HEIGHT);
int x2 = random.nextInt(IMAGE_WIDTH);
int y2 = random.nextInt(IMAGE_HEIGHT);
int width = random.nextInt(NOISE_ARC_WIDTH_MAX - NOISE_ARC_WIDTH_MIN + 1) + NOISE_ARC_WIDTH_MIN;
int angle1 = random.nextInt(NOISE_ARC_ANGLE_MAX - NOISE_ARC_ANGLE_MIN + 1) + NOISE_ARC_ANGLE_MIN;
int angle2 = random.nextInt(NOISE_ARC_ANGLE_MAX - NOISE_ARC_ANGLE_MIN + 1) + NOISE_ARC_ANGLE_MIN;
Color color = new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
g.setColor(color);
g.setStroke(new BasicStroke(width));
g.draw(new QuadCurve2D.Float(x1, y1, IMAGE_WIDTH / 2, IMAGE_HEIGHT / 2 + 20, x2, y2));
g.setStroke(new BasicStroke(1));
}
// 随机生成干扰直线
for (int i = 0; i < NOISE_LINE_COUNT; i++) {
int x1 = random.nextInt(IMAGE_WIDTH);
int y1 = random.nextInt(IMAGE_HEIGHT);
int x2 = x1
+ (int) ((random.nextInt(NOISE_LINE_LENGTH_MAX - NOISE_LINE_LENGTH_MIN + 1)
+ NOISE_LINE_LENGTH_MIN)
* Math.cos(Math.toRadians(random.nextInt(360))));
int y2 = y1
+ (int) ((random.nextInt(NOISE_LINE_LENGTH_MAX - NOISE_LINE_LENGTH_MIN + 1)
+ NOISE_LINE_LENGTH_MIN)
* Math.sin(Math.toRadians(random.nextInt(360))));
int width = random.nextInt(NOISE_LINE_WIDTH_MAX - NOISE_LINE_WIDTH_MIN + 1) + NOISE_LINE_WIDTH_MIN;
Color color = new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
g.setColor(color);
g.setStroke(new BasicStroke(width));
g.drawLine(x1, y1, x2, y2);
g.setStroke(new BasicStroke(1));
}
// 将验证码图片输出到流中
ImageIO.write(image, "JPEG", os);
}
private static int getRandomFontSize() {
return new Random().nextInt(FONT_SIZE_MAX - FONT_SIZE_MIN + 1) + FONT_SIZE_MIN;
}
private static int getRandomFontStyle() {
int[] styles = { FONT_STYLE_NORMAL, FONT_STYLE_BOLD, FONT_STYLE_ITALIC, FONT_STYLE_BOLD_ITALIC };
return styles[new Random().nextInt(styles.length)];
}
}
这个示例代码生成一个包含7个数字与字母字符的验证码图片,使用了随机颜色的干扰线来增加验证码的难度。可以调整常量值以自定义验证码的属性。
可以通过调用CaptchaUtil.generate(os)方法传入输出流来得到一个新的验证码图片。
@RequestMapping("/test1")
public void test1(HttpServletResponse response) throws IOException {
ServletOutputStream responseOutputStream = response.getOutputStream();
try {
ComplexCaptchaUtil.generate(responseOutputStream);
} catch (Exception e) {
throw new RuntimeException(e);
}
responseOutputStream.flush();
responseOutputStream.close();
}
版权声明:本文为qq_39827935原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。