工具类源码
import org.apache.commons.codec.binary.Base64;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.QuadCurve2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* 生成验证码工具类
*
* @author whw
* @date 2020/1/7 16:49
*/
public class CaptchaUtil {
/**
* 默认宽度
*/
private static final int WIDTH = 108;
/**
* 默认高度
*/
private static final int HEIGHT = 40;
/**
* 默认长度
*/
private static final int CODE_SIZE = 4;
/**
* 验证码随机字符数组
*/
//private static final char[] charArray = "23456789ABCDEFGHJKMNPQRSTUVWXY".toCharArray();
private static final char[] CHAR_ARRAY = "0123456789".toCharArray();
/**
* 生成随机类
*/
private static final Random RANDOM = new Random();
/**
* 验证码字体
*/
private static final Font[] RANDOM_FONT = new Font[]{
new Font(Font.DIALOG, Font.BOLD, 33),
new Font(Font.DIALOG_INPUT, Font.BOLD, 34),
new Font(Font.SERIF, Font.BOLD, 33),
new Font(Font.SANS_SERIF, Font.BOLD, 34),
new Font(Font.MONOSPACED, Font.BOLD, 34)
};
/**
* 生成验证码字符串
*/
public static String generateCode() {
int count = CODE_SIZE;
char[] buffer = new char[count];
for (int i = 0; i < count; i++) {
buffer[i] = CHAR_ARRAY[RANDOM.nextInt(CHAR_ARRAY.length)];
}
return new String(buffer);
}
public static Map<String, String> generate(String code) {
Map<String, String> map = new HashMap<>(2);
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
drawGraphic(image, code);
ImageIO.write(image, "jpeg", baos);
//转换成字节
byte[] bytes = baos.toByteArray();
//转换成base64串
String base64 = Base64.encodeBase64String(bytes);
//删除 \r\n
base64 = base64.replaceAll("\n", "").replaceAll("\r", "");
map.put("base64", "data:image/jpeg;base64," + base64);
map.put("code", code);
baos.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
return map;
}
private static void drawGraphic(BufferedImage image, String code) {
// 获取图形上下文
Graphics2D g = image.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
// 图形抗锯齿
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 字体抗锯齿
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// 设定背景色,淡色
g.setColor(getRandColor(210, 250));
g.fillRect(0, 0, WIDTH, HEIGHT);
// 画小字符背景
Color color = null;
for (int i = 0; i < 20; i++) {
color = getRandColor(120, 200);
g.setColor(color);
String rand = String.valueOf(CHAR_ARRAY[RANDOM.nextInt(CHAR_ARRAY.length)]);
g.drawString(rand, RANDOM.nextInt(WIDTH), RANDOM.nextInt(HEIGHT));
color = null;
}
// 取随机产生的认证码(4位数字)
char[] buffer = code.toCharArray();
for (int i = 0; i < buffer.length; i++) {
//旋转度数 最好小于45度
int degree = RANDOM.nextInt(28);
if (i % 2 == 0) {
degree = degree * (-1);
}
//定义坐标
int x = 22 * i, y = 21;
//旋转区域
g.rotate(Math.toRadians(degree), x, y);
//设定字体颜色
color = getRandColor(20, 130);
g.setColor(color);
//设定字体,每次随机
g.setFont(RANDOM_FONT[RANDOM.nextInt(RANDOM_FONT.length)]);
//将认证码显示到图象中
g.drawString("" + buffer[i], x + 8, y + 10);
//旋转之后,必须旋转回来
g.rotate(-Math.toRadians(degree), x, y);
}
//图片中间曲线,使用上面缓存的color
g.setColor(color);
//width是线宽,float型
BasicStroke bs = new BasicStroke(3);
g.setStroke(bs);
//画出曲线
QuadCurve2D.Double curve = new QuadCurve2D.Double(0d, RANDOM.nextInt(HEIGHT - 8) + 4, WIDTH / 2, HEIGHT / 2, WIDTH, RANDOM.nextInt(HEIGHT - 8) + 4);
g.draw(curve);
// 销毁图像
g.dispose();
}
/**
* 给定范围获得随机颜色
*
* @param fc
* @param bc
* @return
*/
private static Color getRandColor(int fc, int bc) {
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);
}
}
调用方法
// 获取验证码code
String code = CaptchaUtil.generateCode();
// 传入code生成验证码对象
Map<String, String> captchaMap = CaptchaUtil.generate(code);
生成之后返回的是一个Map,Map中包含了code
和base64码
两个对象:
前端渲染
直接将base64码放到img
标签的src
属性里即可