java生成图形验证码详细教程 带注释 拷贝即用 兼容linux系统

先看效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
比较难看清 因为我用了些花里胡哨的字体,用传统点的字体还是比较好分辨的
在这里插入图片描述
demo地址(每一次打开都不一样 该链接随时可能关闭)

此版本不兼容jdk8后的版本 如果用的是jdk8后的版本请点↓这里

https://blog.csdn.net/u010756046/article/details/122040240

1.准备字体

在这里插入图片描述
上图用的是这几种字体 由于是商用字体涉及到版权问题这里就不提供下载了
本项目用的是以下两种字体
在这里插入图片描述
这两种字体相信大家都有吧
没有的童鞋打开 控制面板-搜索字体-点这个-把里面的字体复制出来就行了
在这里插入图片描述
在这里插入图片描述

2.创建项目

创建一个普通的java项目即可 这里用的是idea、jdk1.8.0_144
在这里插入图片描述
在项目根目录创建一个fonts文件夹
把刚刚拿到的字体丢到文件夹里
在这里插入图片描述
创建好项目之后 开始创建我们的第一个类
在这里插入图片描述

3.创建类VerifyImageCodeUtils

该类用来生成验证码

package com.liziguo.utils;

import sun.font.FontDesignMetrics;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Random;

/**
 * @Author:Liziguo
 * @Date:2019/12/11 23:45
 */
public class VerifyImageCodeUtils {

	//	private static final String ALL = "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";

	private static final String ALL = "2345678wertyuipasdfghjkzxcvbnmQWERTYUIPASDFGHJKLZXCVBNM";//去除容易混淆的字母

	private static final Font[] fonts = getFonts();//本地字体库

	private static final Random ran = new Random();//获取随机数

	/**
	 * 加载fonts文件夹下的所有字体
	 *
	 * @return
	 */
	private static Font[] getFonts() {
		File file = new File("fonts");
		File[] files = file.listFiles();
		Font[] fonts = new Font[files.length];
		for (int i = 0, len = files.length; i < len; i++) {
			try {
				fonts[i] = Font.createFont(Font.TRUETYPE_FONT, files[i]);
			} catch (FontFormatException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return fonts;
	}

	/**
	 * 获取随机颜色
	 *
	 * @return
	 */
	private static Color randomColor() {
		return new Color(ran.nextInt(256), ran.nextInt(256), ran.nextInt(256));
	}

	/**
	 * 获取相似颜色
	 *
	 * @param color      样本
	 * @param similarity 相似度(越小越相似)
	 * @return
	 */
	private static Color randomColor(Color color, int similarity) {
		int r = color.getRed() + ran.nextInt(similarity) - similarity / 2;
		int g = color.getGreen() + ran.nextInt(similarity) - similarity / 2;
		int b = color.getBlue() + ran.nextInt(similarity) - similarity / 2;
		if (r > 255) r = 255;
		if (r < 0) r = 0;
		if (g > 255) g = 255;
		if (g < 0) g = 0;
		if (b > 255) b = 255;
		if (b < 0) b = 0;
		return new Color(r, g, b);
	}

	/**
	 * 获取随机字符串
	 *
	 * @param len 验证码长度
	 * @return
	 */
	public static String randomCode(int len) {
		StringBuilder str = new StringBuilder();
		for (int i = 0; i < len; i++)
			str.append(ALL.charAt(ran.nextInt(ALL.length())));
		return str.toString();
	}

	/**
	 * 生成120*40字体大小为40长度为4的随机验证码
	 *
	 * @return
	 */
	public static VerifyImageCode createVerifyCode() {
		return createVerifyCode(randomCode(4), 120, 40, 40);
	}

	/**
	 * 生成指定字符串验证码
	 *
	 * @param code     验证码
	 * @param width    图片宽度
	 * @param height   图片高度
	 * @param fontSize 字体大小
	 * @return
	 */
	public static VerifyImageCode createVerifyCode(final String code, int width, int height, int fontSize) {
		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Graphics2D g = image.createGraphics();
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);//抗锯齿

		final float stroke = fontSize / 40f;//干扰线 噪点粗细

		Color backColor = randomColor();//背景颜色
		Color bodyColor = randomColor();//验证码颜色

		//先给背景上色
		g.setColor(backColor);
		g.fillRect(0, 0, width, height);

		//绘制干扰线
		g.setStroke(new BasicStroke(stroke));//干扰线粗细
		for (int i = 0; i < 20; i++) {
			g.setColor(randomColor());// 设置线条的颜色
			g.drawLine(ran.nextInt(width), ran.nextInt(height), ran.nextInt(width * 2) - width / 2, ran.nextInt(height * 2) - height / 2);
		}

		//绘制验证码
		Font font = fonts[ran.nextInt(fonts.length)].deriveFont(Font.BOLD, fontSize);//从我们的字体库里随机取一种字体并重新设置样式大小
		//Font.deriveFont(int style, float size)通过复制此 Font 对象并应用新样式和大小,创建一个新 Font 对象
		g.setFont(font);
		FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);//通过这个类获取字体的宽高 以保证验证码画在图片合适的位置
		int bodyX = width / code.length();//确定每个字符的位置
		for (int i = 0; i < code.length(); i++) {
			String str = code.substring(i, i + 1);//取第i个字符
			int strWidth = metrics.stringWidth(str);//字体宽度
			int strHeight = metrics.getHeight();//字体高度
			int asent = metrics.getAscent();//基线baseline之上的长度
			//xy为每个字符的中心坐标
			float x = i * bodyX + bodyX / 2f;
			float y = height / 2f;
			g.setColor(randomColor(bodyColor, 50));//获取bodyColor相似颜色
			double angle = Math.random() * Math.PI / 2 - Math.PI / 4;//角度在-45°到45°之间
			g.rotate(angle, x, y);//旋转画笔
			g.drawString(str, x - strWidth / 2, y + asent - strHeight / 2);//把验证码的第i个字符画到图片上
			g.rotate(-angle, x, y);//再转回来
		}

		//绘制干扰线
		for (int i = 0; i < 5; i++) {
			g.setColor(randomColor());// 设置线条的颜色
			g.drawLine(ran.nextInt(width), ran.nextInt(height), ran.nextInt(width * 2) - width, ran.nextInt(height * 2) - height);
		}

		//绘制噪点
		float ratio = 0.05f;//噪声率
		//噪声率×总面积÷点面积 保证图片越大噪点不会越多
		int area = (int) (ratio * (width * height) / (stroke * stroke));
		for (int i = 0; i < area; i++) {
			g.setColor(randomColor());
			int x = ran.nextInt(width);
			int y = ran.nextInt(height);
			g.drawLine(x, y, x, y);
		}

		//生成id的规则你们自己改 这里我就随便写了
		//例如 当前时间戳+Math.random()的md5值 或图片的md5值保证id不会重复
		//主要是发送给前端验证的时候要用到
		String id = "64aab58041013e68b479bd68a027515c";
		return new VerifyImageCode(id, code, image);
	}
}

4.创建类VerifyImageCode

相当于一个带功能的实体类吧

package com.liziguo.utils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;

/**
 * @Author:Liziguo
 * @Date:2019/12/13 23:02
 */
public class VerifyImageCode {

	public final String id;

	public final String code;

	public final BufferedImage image;

	public VerifyImageCode(String id, String code, BufferedImage image) {
		this.id = id;
		this.code = code;
		this.image = image;
	}

	/**
	 * @return 获取小写验证码
	 */
	public String getLowerCode() {
		return code.toLowerCase();
	}

	/**
	 * @return 大写验证码
	 */
	public String getUpperCode() {
		return code.toUpperCase();
	}

	/**
	 * 把图片转换成字节数组
	 *
	 * @return
	 */
	public byte[] toBytes() {
		ByteArrayOutputStream out = null;
		try {
			out = new ByteArrayOutputStream();
			ImageIO.write(image, "png", out);
			return out.toByteArray();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return null;
	}

	/**
	 * 生成图片的base64编码
	 *
	 * @return
	 */
	public String toBase64Code() {
		return Base64.getEncoder().encodeToString(toBytes());
	}

}

到了这一步直接调用VerifyImageCodeUtils.createVerifyCode就能生成验证码了不过还看不到效果
如果想看到效果请继续往下走

5.创建测试类Test

package com.liziguo.utils;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

/**
 * @Author:Liziguo
 * @Date:2019/12/14 0:30
 */
public class Test extends JFrame {

	private BufferedImage image;

	public Test(BufferedImage image) {
		this.image = image;
		setResizable(false);//用户不能随意调节窗口大小
		setSize(image.getWidth(), image.getHeight());//设置大小
		setLocationRelativeTo(null);//窗口居中
		setDefaultCloseOperation(3);//x掉后彻底退出程序
		setAlwaysOnTop(true);//窗口始终在最上方
		setUndecorated(true);//去除修饰(去除窗口边框、最大化、最小化、关闭按钮等)
		//添加一个键盘事件 按Esc关闭窗口 F5重新生成验证码
		addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == 27) {
					//27是键盘Esc的Ascii码
					System.exit(0);
				} else if (e.getKeyCode() == 116) {
					//116是键盘F5的Ascii码
					reImage();
				}
			}
		});
		setVisible(true);//显示
	}

	private void reImage() {
		String code = VerifyImageCodeUtils.randomCode(4);//随机生成4位数字符串
		VerifyImageCode v = VerifyImageCodeUtils.createVerifyCode(code, 1200, 400, 400);//生成图形验证码
		image = v.image;
		setSize(image.getWidth(), image.getHeight());//设置大小
		setLocationRelativeTo(null);//窗口居中
		repaint();//重绘
	}

	@Override
	public void paint(Graphics g) {
		super.paint(g);
		//这里我们重写一下paint方法 把图片画出来
		g.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
	}

	public static void main(String[] args) throws IOException {
//		String code = "龘亣龖䪏";
		String code = VerifyImageCodeUtils.randomCode(4);//随机生成4位数字符串
		//最佳宽高计算公式 height=fontSize  width=height*len*0.75
		VerifyImageCode v = VerifyImageCodeUtils.createVerifyCode(code, 1200, 400, 400);//生成图形验证码

		new Test(v.image);//图形界面测试验证码

		//获取桌面路径
		File file = new File(FileSystemView.getFileSystemView().getHomeDirectory().getAbsolutePath() + "/verifyImage.png");
		//把这张验证码保存到桌面
		ImageIO.write(v.image, "png", file);

		System.out.println("验证码信息:");
		System.out.println("id:" + v.id);
		System.out.println("code:" + v.code);
		System.out.println("lowerCode:" + v.getLowerCode());
		System.out.println("upperCode:" + v.getUpperCode());
		System.out.println("imageBase64Code:" + v.toBase64Code());
	}
}

最终目录结构
在这里插入图片描述

7.运行效果

在这里插入图片描述
在这里插入图片描述

8.补充

有没有发现最后生成了一串长的base64编码
把这一串编码放到img标签在前面加上"data:image/gif;base64,"是能直接使用的

<img src="https://img-blog.csdnimg.cn/2022010709394978676.gif"/>

验证码最佳宽高计算公式:字体大小和图片高度相等,图片宽度=图片高度×验证码长度×0.75

由于这里使用的不是本地字体 所以直接丢到linux系统也能正常运行

验证码可以输入中文 前提是你的字体支持中文

下载地址:不要忘记点个赞哦

最后送大家一张1920×1080 字体大小400的验证码壁纸 哪去用吧

i miss you

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个示例代码,可以生成6位数字验证码注释: ``` import java.util.Random; public class VerificationCodeGenerator { public static void main(String[] args) { String code = generateVerificationCode(); System.out.println("生成验证码为:" + code); } /** * 生成6位数字验证码 */ public static String generateVerificationCode() { Random random = new Random(); String code = ""; for (int i = 0; i < 6; i++) { code += random.nextInt(10); } return code; } } ``` 注释解释: - `import java.util.Random;`:导入Java的随机数生成器类。 - `public class VerificationCodeGenerator`:定义了一个名为`VerificationCodeGenerator`的公共类。 - `public static void main(String[] args)`:主方法,程序入口。 - `String code = generateVerificationCode();`:调用`generateVerificationCode()`方法生成验证码,并将结果保存在`code`变量中。 - `System.out.println("生成验证码为:" + code);`:输出生成验证码。 - `public static String generateVerificationCode()`:定义了一个名为`generateVerificationCode`的公共静态方法,返回值为字符串类型。 - `Random random = new Random();`:生成一个随机数生成器实例。 - `String code = "";`:初始化一个空字符串变量,用于保存生成验证码。 - `for (int i = 0; i < 6; i++)`:循环6次,生成6位验证码。 - `code += random.nextInt(10);`:生成一个0到9之间的随机数,并将其添加到`code`变量中。 - `return code;`:返回生成验证码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值