最近在项目上,遇到一个问题,做一个验证码,本来很简单的事,直接使用kaptcha插件来生成就可以了。结果,不知道什么奇葩原因,至今还没找到问题根源。实在没办法,只能自己写了个验证码。
不多说,下面上干货:
package com.hzseek.web.util;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.QuadCurve2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
import javax.imageio.ImageIO;
/**
* @author dingjunjie
* @date 2018-02-07 21:14:34
* @desc 图片验证码工具类
*/
public class GenerateCaptcha {
// 图片宽度
private int width = 160;
// 图片高度
private int height = 40;
// 验证码字符个数
private int codeCount = 5;
// 字体数组
private String[] fontTypes = { "黑体", "微软雅黑"};
// private String[] fontTypes = { "Arial", "Courier"};
// 验证码干扰线数
private int lineCount = 2;
// 验证码
private String captchaCode = null;
// 验证码图片Buffer
private BufferedImage buffImg = null;
// 验证码范围,去掉0(数字)和O(拼音)容易混淆的(小写的1和L也可以去掉,大写不用了)
private String codeStr = "23456789abcdefghjkmnopqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ";
// 获得随机数
private Random random = new Random();
/**
* 获取随机的颜色
*
* @return
*/
private Color randomColor() {
int r = this.random.nextInt(100); // 这里为什么是150,因为当r,g,b都为255时,即为白色,为了好辨认,需要颜色深一点。
int g = this.random.nextInt(100);
int b = this.random.nextInt(100);
return new Color(r, g, b); // 返回一个随机颜色
}
/**
* 获得随机字体
*
* @return
*/
private Font randomFont() {
int index = random.nextInt(fontTypes.length); // 获取随机的字体
String fontName = fontTypes[index];
int style = random.nextInt(4); // 随机获取字体的样式,0是无样式,1是加粗,2是斜体,3是加粗加斜体
int size = random.nextInt(5) + 24; // 随机获取字体的大小
return new Font(fontName, style, size); // 返回一个随机的字体
}
/**
* 获得随机字符
*
* @return
*/
private char randomChar() {
int index = random.nextInt(codeStr.length());
return codeStr.charAt(index);
}
/**
* 画干扰线,验证码干扰线用来防止计算机解析图片
*
* @param image
* @param lineCount
* 干扰线的数量
*/
private void drawLine(BufferedImage image, int lineCount) {
Graphics2D g = (Graphics2D) image.getGraphics();
for (int i = 0; i < lineCount; i++) {
int x1 = random.nextInt(width);
int y1 = random.nextInt(height);
int x2 = random.nextInt(width);
int y2 = random.nextInt(height);
g.setStroke( new BasicStroke( 2.5f ) );
g.setColor(randomColor());
// g.drawLine(x1, y1, x2, y2);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
QuadCurve2D a = new QuadCurve2D.Double(5, y1, 80, random.nextInt(20) + 10, 155, y2);
g.draw(a);
}
}
/**
* 创建图片的方法
*
* @return
*/
private BufferedImage createImage() {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // 创建图片缓冲区
Graphics2D g = (Graphics2D) image.getGraphics(); // 获取画笔
g.setColor(Color.LIGHT_GRAY); // 设置背景色
g.fillRect(0, 0, width, height);
// 随机产生10个干扰点
// Random rand = new Random();
// for (int i = 0; i < 10; i++) {
// int x = rand.nextInt(width);
// int y = rand.nextInt(height);
// g.setColor(randomColor());
// g.drawOval(x, y, 1, 1);
// }
return image; // 返回一个图片
}
/**
* 获取验证码图片
*
* @return
*/
public BufferedImage getImage() {
BufferedImage image = createImage();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < codeCount; i++) // 显示字符数
{
Graphics2D g = (Graphics2D) image.getGraphics(); // 获取画笔
String s = randomChar() + ""; // 随机生成字符,因为只有画字符串的方法,没有画字符的方法,所以需要将字符变成字符串再画
sb.append(s); // 添加到StringBuilder里面
float x = width / (codeCount + 2); // 每个字符的宽度,左右各空出一个字符的位置
g.setFont(randomFont()); // 设置字体,随机
g.setColor(Color.BLACK); // 设置颜色,为了区分度高,设为黑色
g.rotate(-5* Math.PI / 180);
g.drawString(s, x * (i + 1 + random.nextFloat()/2), height - 5);
}
this.captchaCode = sb.toString();
drawLine(image, lineCount);
return image;
}
/**
* 获取验证码的文本
*
* @return
*/
public String getCaptchaCode() {
return captchaCode;
}
/**
* 将验证码图片写出的方法
*
* @param image
* @param out
* @throws IOException
*/
public void output(BufferedImage image, OutputStream out) throws IOException {
ImageIO.write(image, "JPEG", out);
}
}
至于调用,就不多说了,调用output就可以生成验证码了。
效果如图: