一、实现思路
- 使用BufferedImage用于在内存中存储生成的验证码图片
- 使用Graphics来进行验证码图片的绘制
- 最后通过ImageIO将生成的图片进行输出
二、实现代码
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
/**
* 验证码工具类
*/
@WebServlet("/cta")
public class CaptcahCode extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
CaptcahCode.drawImage(resp);
}
/**
* 验证码的生成方法
* @param response
* @return
*/
public static void drawImage(HttpServletResponse response) {
//1、使用stringbuilder类,对字符串进行处理。不用String,因为其赋值后不能改变。
StringBuilder builder = new StringBuilder();
//2、产生随机数,长度为4
for (int i = 0; i < 4; i++) {
builder.append(randomChar());
}
Random random = new Random();
String code = builder.toString();
//3、定义图片的宽度和高度,使用BufferedImage对象。
int width = 120;
int height = 25;
BufferedImage bi = new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);
//4、获取Graphics2D 绘制对象,开始绘制验证码
Graphics2D g = bi.createGraphics();
//6、定义字体的颜色
Color color = new Color(0,0,0);
// 设置字体(定义文字的字体和大小)
//Font font1 = getFont(fontHeight);
Font font = new Font("Fixedsys", Font.BOLD, 20);
g.setFont(font);
//设置颜色
g.setColor(color);
//设置背景
g.setBackground(new Color(226,226,240 ));
//开始绘制对象
g.clearRect(0,0,width,height);
//绘制形状,获取矩形对象
FontRenderContext context = g.getFontRenderContext();
Rectangle2D bounds = font.getStringBounds(code,context);
//计算文件的坐标和间距
double x = (width - bounds.getWidth())/2;
double y = (height- bounds.getHeight())/2;
double ascent = bounds.getY();
double baseY = y - ascent;
//干扰线
for (int i = 0; i < 20; i++) {
int xs = random.nextInt(width);
int ys = random.nextInt(height);
int xe = xs + random.nextInt(width);
int ye = ys + random.nextInt(height);
g.setColor(getRandColor(1, 255));
g.drawLine(xs, ys, xe, ye);
}
// 添加噪点
float yawpRate = 0.01f;
int area = (int) (yawpRate * width * height);
for (int i = 0; i < area; i++) {
int xz = random.nextInt(width);
int yz = random.nextInt(height);
bi.setRGB(xz, yz, random.nextInt(255));
}
g.drawString(code,(int)x,(int)baseY);
//结束绘制
g.dispose();
try {
ImageIO.write(bi,"jpg",response.getOutputStream());
//刷新响应流
response.flushBuffer();
} catch (IOException e) {
e.printStackTrace();
}
// return code;
}
/**
* 此方法用于用户产生随机字母和数字
* @return
*/
private static char randomChar(){
// 1、定义验证需要的字母和数字
String str = "ZXCVBNMASDFGHJKLQWERTYUIOP0123456789";
//2、定义随机对象
Random random = new Random();
//3、返回随机字符
return str.charAt(random.nextInt(str.length()));
}
/**
* 得到随机颜色
* @param fc
* @param bc
* @return
*/
private static Color getRandColor(int fc, int bc) {
Random random = new Random();
if (fc > 255){
fc = 255;
}
if (bc > 255){
bc = 255;
}
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
/**
* 产生随机字体
*/
private Font getFont(int size) {
Random random = new Random();
Font[] font = new Font[5];
font[0] = new Font("Ravie", Font.PLAIN, size);
font[1] = new Font("Antique Olive Compact", Font.PLAIN, size);
font[2] = new Font("Fixedsys", Font.PLAIN, size);
font[3] = new Font("Wide Latin", Font.PLAIN, size);
font[4] = new Font("Gill Sans Ultra Bold", Font.PLAIN, size);
return font[random.nextInt(5)];
}
}
三、结果展示

四、总结
生成的验证码添加比较简单线条等干扰因素,比较容易识别。在实际的项目中可采用其他的第三方验证码库来生成验证码。