1.定义一个验证码工具类CaptchaUtil
package com.zzq.ams.util;
import com.zzq.ams.model.CaptchaImage;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.*;
import java.util.List;
/**
* @author zzq
* @project ams-simple
* @description 验证码工具
* @date 2021/3/4 22:47
*/
public class CaptchaUtil {
private static final Random random = new Random();
private static final int imgWidth = 412; //图片宽度
private static final int imgHeight = 150; //图片高度
private static final int fontSize = 70; //字体大小
private static final int fontSizeFloat = 10; //字体大小浮动值
private static final int lineCount = 10; //线条数量
private static final float noiseRage = 0.05f; //噪声率
private static final int charSpace = 15; //验证码字符间距
private static final int frontColor = 220; //前景色RGB值
private static final int frontColorFloat = 20; //前景色浮动值
private static final int backColor = 100; //背景色RGB值
private static final int backColorFloat = 20; //背景色浮动值
private static final int minCodeLen = 4; //最短验证码字符数
private static final int maxCodeLen = 5; //最长验证码字符数
private static final Character[] charArr; //验证码基础字符数组
private static final String[] fontNameArr; //字体名称数组
static {
//默认字体
List<String> fontNames = new ArrayList<>();
fontNames.add("Cambria");
fontNames.add("Arial");
fontNames.add("Comic Sans MS");
fontNames.add("Consolas");
fontNames.add("Lucida Console");
fontNames.add("Microsoft YaHei UI");
fontNames.add("Segoe Print");
//集合转数组
fontNameArr = new String[fontNames.size()];
fontNames.toArray(fontNameArr);
//基础字符数组[0-9a-zA-Z]
charArr = new Character[62];
int i = 0;
for (char j = '0'; j <= '9'; j++) {
charArr[i++] = j;
}
for (char j = 'a'; j <= 'z'; j++) {
charArr[i++] = j;
}
for (char j = 'A'; j <= 'Z'; j++) {
charArr[i++] = j;
}
//数组转集合
List<Character> characterList = Arrays.asList(charArr);
//集合洗牌
Collections.shuffle(characterList);
//集合转数组
characterList.toArray(charArr);
}
/**
* 获取验证码
*
* @return 图片验证码
*/
public static CaptchaImage getCaptchaImage() {
BufferedImage image = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_BGR);
Graphics graph = image.getGraphics();
//设置背景
graph.setColor(getRandColor(frontColor, frontColorFloat)); //背景色
graph.fillRect(0, 0, imgWidth, imgHeight); //填充矩形尺寸
//设置字体
Font font = getRandFont(fontSize, fontSizeFloat);
graph.setFont(font);
//绘制干扰线
drawRandLine(graph, lineCount, imgWidth, imgHeight);
//添加噪点
addNoisePoint(image, noiseRage, imgWidth, imgHeight);
//绘制字符
String code = getRandChars(minCodeLen, maxCodeLen);
drawCaptcha(graph, code);
return CaptchaImage.of(code, image);
}
/**
* 绘制验证码
*
* @param graph 图像
* @param captcha 验证码
*/
private static void drawCaptcha(Graphics graph, String captcha) {
char[] charArr = captcha.toCharArray();
for (int i = 0; i < charArr.length; i++) {
Font font = getRandFont(fontSize, fontSizeFloat);
int bottom = imgHeight - font.getSize(); //底部距离
graph.setColor(getRandColor(backColor, backColorFloat));
graph.drawString(String.valueOf(charArr[i]), i * font.getSize() + charSpace, bottom);
}
}
/**
* 添加图片噪点
*
* @param image 图片
* @param noiseRate 噪声率
*/
private static void addNoisePoint(BufferedImage image, float noiseRate, int imgWidth, int imgHeight) {
int area = (int) (noiseRate * imgWidth * imgHeight);
for (int i = 0; i < area; i++) {
int x = random.nextInt(imgWidth);
int y = random.nextInt(imgHeight);
int rgb = random.nextInt(256);
image.setRGB(x, y, rgb);
}
}
/**
* 绘制随机线条
*
* @param graph 图像
* @param lineCount 线条数
* @param imgWidth 图片宽度
* @param imgHeight 图片高度
*/
private static void drawRandLine(Graphics graph, int lineCount, int imgWidth, int imgHeight) {
for (int i = 0; i < lineCount; i++) {
int x1 = random.nextInt(imgWidth);
int y1 = random.nextInt(imgHeight);
int x2 = random.nextInt(imgWidth);
int y2 = random.nextInt(imgHeight);
graph.setColor(getRandColor(50, 30));
graph.drawLine(x1, y1, x2, y2);
}
}
/**
* 生成随机字体
*
* @param size 字体最小size
* @param floatValue 浮动值
* @return 字体对象
*/
private static Font getRandFont(int size, int floatValue) {
int minFontSize = size - floatValue;
int maxFontSize = size + floatValue;
String fontName = fontNameArr[random.nextInt(fontNameArr.length)];
int fontStyle = random.nextInt(3);
int fontSize = random.nextInt(maxFontSize - minFontSize + 1) + minFontSize;
return new Font(fontName, fontStyle, fontSize);
}
/**
* 生成随机颜色
*
* @param rgbVal 颜色基本值
* @param floatVal 浮动值
* @return 颜色对象
*/
private static Color getRandColor(int rgbVal, int floatVal) {
if (rgbVal > 255) {
rgbVal = 255;
}
int min = rgbVal - floatVal;
if (min < 0) {
min = 0;
}
int max = rgbVal + floatVal;
if (max > 255) {
max = 255;
}
int r = random.nextInt(max - min + 1) + min;
int g = random.nextInt(max - min + 1) + min;
int b = random.nextInt(max - min + 1) + min;
return new Color(r, g, b);
}
/**
* 生成随机字符串
*
* @param minLen 最小长度
* @param maxLen 最大长度
* @return 字符串
*/
private static String getRandChars(int minLen, int maxLen) {
int len = random.nextInt(maxLen - minLen + 1) + minLen;
char[] randCharArr = new char[len];
for (int j = 0; j < len; j++) {
randCharArr[j] = charArr[random.nextInt(62)]; //26*2+10
}
return String.valueOf(randCharArr);
}
}
2.配置图片消息转换器
/**
* @author zzq
* @project ams-simple
* @description mvc配置
* @date 2021/3/4 1:00
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
//注册图片消息转换器
converters.add(new BufferedImageHttpMessageConverter());
}
}
3.Controller代码
@RequestMapping("/login")
@Controller
public class LoginController extends BaseController {
@RequestMapping(value = "/captcha", produces = MediaType.IMAGE_JPEG_VALUE)
@ResponseBody
public BufferedImage captcha(HttpServletResponse response) {
//获取验证码图片
CaptchaImage captchaImage = CaptchaUtil.getCaptchaImage();
//获取验证码
String code = captchaImage.getCode();
System.err.println(code);
//通知浏览器不缓存
response.setHeader("cache-control","no-store");
return captchaImage.getImage();
}
}
4.页面部分代码
<div class="layui-form-item">
<label class="layui-icon layui-icon-vercode" for="captcha"></label>
<input type="text" id="captcha" name="captcha" lay-verify="required|captcha" placeholder="图形验证码"
autocomplete="off" class="layui-input verification captcha" value="xszg">
<div class="captcha-img">
<img id="captchaPic" src="">
</div>
</div>
//JS:点击切换验证码图片
$("#captchaPic").click(function () {
$(this).attr("src", "/login/captcha");
});
5.几张效果图