Java Web验证码功能
文章目录
1 明确需求
- 验证码最常用的是一个图片类型的验证码,由后端进行产生并且发送到前端页面显示。
- 验证码的生成原理简单来说就是在一张画板上面,画上数字或字母,以及点缀一些干扰信息。
- 这里只介绍手动生成的简单方案,明白原理即可。
2 BufferedImage类介绍
import java.awt.image.BufferedImage
继承java.awt.Image
类,BufferedImage是一个带缓冲区的图像类,可以将图片加载到内存的一片连续区域中,这样可以非常方便对加载的图像进行操作,包括图像剪切旋转缩放、图像绘制、像素级别的处理、灵活的图片格式等。
BufferedImage是没有读取功能,只能通过ImageIO
类进行IO操作:
ImageIO.read() // 返回BufferedImage类型
ImageIO.write() //写到输出流,或者文件对象
3 实现
3.1 创建工具类
创建验证码工具类,这个工具可以传入绘制的图像的宽和高,以及所需绘制数字的位数
public class CaptchaUtil {
public static byte[] getCaptcha(int width, int height, int num) {
}
}
3.2 创建画板
//创建一个BufferedImage对象
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
// 创建Graphics对象,用于绘制图像 真正提供绘图功能的是Graphics对象
Graphics graphics = bufferedImage.createGraphics();
3.3 定制画笔
先选择自己需要的画笔,再在画板中绘制
//设置画笔颜色
graphics.setColor(Color.WHITE);
//使用画笔填充背景颜色
graphics.fillRect(0, 0, width, height);
//设置字体
graphics.setFont(new Font("Times New Roman", Font.PLAIN, 20));
3.4 画数字
//生成随机码
Random random = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < num; i++) {
String code = String.valueOf(random.nextInt(10));
sb.append(code);
// 设置随机颜色 为了对不同的数字实现随机颜色的效果
graphics.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));
// 绘制验证码
graphics.drawString(code, 20 * i + 10, 25);
}
3.5 绘制干扰线
// 绘制干扰线
for (int i = 0; i < 6; i++) {
//设置画笔随机颜色
graphics.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));
//生成直线的坐标,两点确定一条直线
int x1 = random.nextInt(width);
int y1 = random.nextInt(height);
int x2 = random.nextInt(width);
int y2 = random.nextInt(height);
graphics.drawLine(x1, y1, x2, y2);
}
3.6 返回字节数组对象
// 释放Graphics对象
graphics.dispose();
//输出图片到输出流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "JPEG", outputStream);```java
// 获取图片的字节数组并返回
return outputStream.toByteArray();
4 返回字节流
@RequestMapping("/user/getCaptcha")
public ResponseEntity<byte[]> getCaptcha(HttpServletResponse response) throws IOException {
byte[] captcha = CaptchaUtil.getCaptcha(100, 30, 4);
// 设置响应头
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.IMAGE_JPEG);
httpHeaders.setContentLength(captcha.length);
return new ResponseEntity<>(captcha, httpHeaders, HttpStatus.OK);
}
5 测试效果
element-plus实现
<el-form-item label="验证码">
<el-input v-model="ruleForm.code" type="text" autocomplete="off" style="width: 70%" />
<el-image style="width: 30%; height: 32px; border: 1px solid #8ca2ab;" :src="captchaUrl" fit="fill"
@click="getCodeImg()" />
</el-form-item>
6 所有代码
6.1 CaptchaUtil
package com.song.util;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Stream;
/**
* 生成captcha的工具类
*/
public class CaptchaUtil {
public static byte[] getCaptcha(int width, int height, int num) throws IOException {
//创建一个BufferedImage对象
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
// 创建Graphics对象,用于绘制图像
Graphics graphics = bufferedImage.createGraphics();
//设置画笔颜色
graphics.setColor(Color.WHITE);
//使用画笔填充背景颜色
graphics.fillRect(0, 0, width, height);
//设置字体
graphics.setFont(new Font("Times New Roman", Font.PLAIN, 20));
//生成随机码
Random random = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < num; i++) {
String code = String.valueOf(random.nextInt(10)); // 10以内的数字
sb.append(code);
// 设置随机颜色
graphics.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));
// 绘制验证码
graphics.drawString(code, 20 * i + 10, 25);
}
String captcha = sb.toString();
// 打印验证码
System.out.println("验证码:" + captcha);
// 绘制干扰线
for (int i = 0; i < 6; i++) {
//设置画笔随机颜色
graphics.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));
//生成直线的坐标,两点确定一条直线
int x1 = random.nextInt(width);
int y1 = random.nextInt(height);
int x2 = random.nextInt(width);
int y2 = random.nextInt(height);
graphics.drawLine(x1, y1, x2, y2);
}
// 释放Graphics对象
graphics.dispose();
//输出图片到输出流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "JPEG", outputStream);
// 获取图片的字节数组
return outputStream.toByteArray();
}
}
6.2 Controller代码
@RequestMapping("/user/getCaptcha")
public ResponseEntity<byte[]> getCaptcha(HttpServletResponse response) throws IOException {
byte[] captcha = CaptchaUtil.getCaptcha(100, 30, 4);
// 设置响应头
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.IMAGE_JPEG);
httpHeaders.setContentLength(captcha.length);
return new ResponseEntity<>(captcha, httpHeaders, HttpStatus.OK);
}
6.3 前端代码
可以在浏览器直接输入请求地址查看http://127.0.0.1:8081/user/getCaptcha
,换成自己的地址。
<el-form-item label="验证码">
<el-input v-model="ruleForm.code" type="text" autocomplete="off" style="width: 70%" />
<el-image style="width: 30%; height: 32px; border: 1px solid #8ca2ab;" :src="captchaUrl" fit="fill"
@click="getCodeImg()" />
</el-form-item>
//验证码
var captchaUrl = ref(store.baseUrl + "/user/getCaptcha")
const getCodeImg = () => {
//Date.now()防止浏览器缓存而不发送请求
captchaUrl.value = store.baseUrl + "/user/getCaptcha?data=" + Date.now()
}