Java生成图片验证码
参考资料
步骤
1.编写图形随机码生成器
package com.*.util;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
/**
* 图片验证码生成器
*
* @author limo
* @date 2022-01-24 17:19:023
*/
public class ImageVerifyCodeGenerator {
// 随机字符词典(去掉0和1,因为它们和字母O,l在图片展示容易混淆)
public static final String RANDOM_CHARS = "23456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// 字体数组
public static final String[] FONT_NAMES = { "Chandas" };
/**
* 生成4位随机图片验证码
*
* @return
*/
public static synchronized Map<String, Object> generate() {
// 1. 初始化图片缓冲器
BufferedImage image = initImage();
// 2. 生成随机验证码
String[] codes = createVerifyCodes();
// 3. 验证码写入图片中
draw(image, codes);
// 4. 返回图片和验证码
Map<String, Object> imageInfo = new HashMap<String, Object>();
imageInfo.put("image", image);
StringBuffer verfyCode = new StringBuffer();
for (String c : codes) {
verfyCode.append(c);
}
imageInfo.put("code", verfyCode.toString());
return imageInfo;
}
/**
* 生成图片验证码
*
* @param width 图片验证码宽度
* @param height 图片验证码高度
* @param verfyCodeNumber 验证码字符个数
* @return 图片验证码和验证码
*/
public static synchronized Map<String, Object> generate(int width, int height, int verfyCodeNumber) {
// 1. 初始化图片缓冲器
BufferedImage image = initImage(100, 40, BufferedImage.TYPE_INT_RGB);
// 2. 生成随机验证码
String[] codes = createVerifyCodes(verfyCodeNumber);
// 3. 验证码写入图片中
draw(image, codes);
// 4. 返回图片和验证码
Map<String, Object> imageInfo = new HashMap<String, Object>();
imageInfo.put("image", image);
StringBuffer verfyCode = new StringBuffer();
for (String c : codes) {
verfyCode.append(c);
}
imageInfo.put("code", verfyCode);
return imageInfo;
}
public static BufferedImage initImage() {
// 默认图片宽100,高 40 底色白色,颜色系统使用RGB
return initImage(100, 40, BufferedImage.TYPE_INT_RGB);
}
public static BufferedImage initImage(int width, int height, int imageType) {
BufferedImage image = initImage(width, height, imageType, Color.white);
return image;
}
public static BufferedImage initImage(int width, int height, int imageType, Color color) {
BufferedImage image = new BufferedImage(width, height, imageType);
// 获取画笔
Graphics graphics = image.getGraphics();
// 设置底色
graphics.setColor(color);
// 画一个长方形
graphics.fillRect(0, 0, width, height);
return image;
}
public static synchronized String[] createVerifyCodes() {
return createVerifyCodes(4);
}
public static String[] createVerifyCodes(int verfyCodeNumber) {
return createVerifyCodes(RANDOM_CHARS.toCharArray(), verfyCodeNumber);
}
public static String[] createVerifyCodes(char[] chars, int verfyCodeNumber) {
String[] codes = new String[verfyCodeNumber];
for (int i = 0; i < codes.length; i++) {
char c = randomChar(chars);
codes[i] = String.valueOf(c);
}
return codes;
}
/**
* 获取随机字符
*
* @return
*/
public static synchronized char randomChar(char[] chars) {
int index = ThreadLocalRandom.current().nextInt(chars.length);
return RANDOM_CHARS.charAt(index);
}
public static void draw(BufferedImage image, String[] codes) {
int width = image.getWidth();
int height = image.getHeight();
Graphics2D graphics = (Graphics2D) image.getGraphics();
for (int i = 0; i < codes.length; i++) {
// 计算字符所在图片中x的位置,一般按字符个数平均分
float x = i * 1.0f * width / codes.length;
float y = height - 5 / 1.0f;
drawString(graphics, codes[i], x, y);
}
graphics.dispose();
}
public static void drawString(Graphics2D graphics, String code, float x, float y) {
drawString(graphics, code, x, y, randomFont(), randomColor());
}
public static void drawString(Graphics2D graphics, String code, float x, float y, Font font, Color color) {
graphics.setColor(color);
graphics.setFont(font);
graphics.drawString(code, x, y);
}
/**
* 获取随机字体
*
* @return
*/
public static Font randomFont() {
return randomFont(FONT_NAMES);
}
/**
* 获取随机字体
*
* @return
*/
public static Font randomFont(String[] fonts) {
int index = ThreadLocalRandom.current().nextInt(fonts.length); // 获取随机的字体
String fontName = fonts[index];
int style = ThreadLocalRandom.current().nextInt(4); // 随机获取字体的样式,0是无样式,1是加粗,2是斜体,3是加粗加斜体
int size = ThreadLocalRandom.current().nextInt(10) + 24; // 随机获取字体的大小
return new Font(fontName, style, size); // 返回一个随机的字体
}
/**
* 随机颜色
*
* @return
*/
public static Color randomColor() {
int r = ThreadLocalRandom.current().nextInt(225); // 这里为什么是225,因为当r,g,b都为255时,即为白色,为了好辨认,需要颜色深一点。
int g = ThreadLocalRandom.current().nextInt(225);
int b = ThreadLocalRandom.current().nextInt(225);
return new Color(r, g, b); // 返回一个随机颜色
}
}
获取本机可用字体名(按需使用):
GraphicsEnvironment graphicsEnv = GraphicsEnvironment.getLocalGraphicsEnvironment();
String[] fontNames = graphicsEnv.getAvailableFontFamilyNames();
2.编写Controller,将生成的图片响应码写到响应流
@GetMapping("/verify/code")
public void verifyCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 生成验证码图片
Map<String, Object> imageVerifyCode = ImageVerifyCodeGenerator.generate();
BufferedImage bfm = (BufferedImage) imageVerifyCode.get("image");
String code = String.valueOf(imageVerifyCode.get("code"));
System.out.println("验证码:" + code);
HttpSession session = request.getSession();
session.setAttribute("verifyCode", code);
// 使用 ImageIO工具类将 图片验证码输出到响应流
ImageIO.write(bfm, "PNG", response.getOutputStream());
}
3.测试
使用postman 工具请求 http://localhost:8080/verify/code 结果如下:
编写完成.