当前位置: 首页 > news >正文

Java验证码(图片、字符串)生成工具

验证码生成工具

本工具可以生成:

  • 数字+字符
  • 纯数字
  • 纯字符

验证码样式:

  • 字符串
  • base64 字符图片验证码

主要方法:

  • generateCaptchaImage:获取图片验证码
  • generateCaptchaImageVerifyCode:获取图片验证码:(更多自定义参数)
  • getVerifyCode:获取验证码
  • getStringVerifyCode:获取默认长度验证码
  • getNumberVerifyCode:获取默认长度纯数字验证码
  • getStringAndNumberVerifyCode:获取默认长度,数字加字符
@Slf4j
public class VerifyCodeUtils {// 加载字体并缓存private static volatile Font cacheFont = null;//默认宽度private static final Integer imgWidth = 150;//默认高度private static final Integer imgHeight = 50;//随机字符串和数字private static final String STRING_NUMBER_VERIFY_CODE = "123456789ABCDEFGHJKLNPQRSTUVXYZ";//随机字符串private static final String STRING_VERIFY_CODE = "ABCDEFGHIJKLMNPOQRSTUVWXYZ";//随机数private static Random random = new Random();//默认验证码长度private static int DEFAULT_VERIFY_CODE_LENGTH = 4;//验证码最大长度private static int MAX_VERIFY_CODE_LENGTH = 6;//默认干扰线系数private static float DEFAULT_INTERFERE_RATE = 0.1f;//默认噪声系数private static float DEFAULT_NOISE_RATE = 0.3f;/*** 纯数字验证码* @param length 4-6位,默认4位* @return*/private static String generateNumberVerifyCode(int length) {String code;if (length == 6){code = String.valueOf(ThreadLocalRandom.current().nextInt(0, 999999));}else if (length == 5){code = String.valueOf(ThreadLocalRandom.current().nextInt(0, 99999));}else {code = String.valueOf(ThreadLocalRandom.current().nextInt(0, 9999));}if (code.length() == length) {return code;} else {StringBuilder str = new StringBuilder();for(int i = 0; i < length - code.length(); ++i) {str.append("0");}return str + code;}}/*** 生成随机验证码* @param length* @param sources* @return*/private static String generateVerifyCode(int length, String sources) {if (sources == null || sources.length() == 0) {sources = STRING_NUMBER_VERIFY_CODE;}int codeLen = sources.length();Random rand = new Random();StringBuilder verifyCode = new StringBuilder(length);for (int i = 0; i < length; i++) {verifyCode.append(sources.charAt(rand.nextInt(codeLen - 1)));}return verifyCode.toString();}/*** 默认长度4,数字加字符串* @return*/public static String getStringAndNumberVerifyCode() {return generateVerifyCode(DEFAULT_VERIFY_CODE_LENGTH, STRING_NUMBER_VERIFY_CODE);}/*** 默认长度4,获取纯数字验证码* @return*/public static String getNumberVerifyCode() {return generateNumberVerifyCode(DEFAULT_VERIFY_CODE_LENGTH);}/*** 默认长度4,字符串* @return*/public static String getStringVerifyCode() {return generateVerifyCode(DEFAULT_VERIFY_CODE_LENGTH, STRING_VERIFY_CODE);}/*** 获取验证码* @param length 验证码长度 最长不超过6位 ,默认4位* @param type 验证码类型 0-数字+字符,1-纯数字,2-纯字符 默认0* @return*/public static String getVerifyCode(int length, int type) {if (length == 0){length = DEFAULT_VERIFY_CODE_LENGTH;}if (length < DEFAULT_VERIFY_CODE_LENGTH){throw new DescribeException("length不能小于"+DEFAULT_VERIFY_CODE_LENGTH, ServerCodeEnum.PARAM_ERROR.getCode());}if (length > MAX_VERIFY_CODE_LENGTH){throw new DescribeException("length不能大于"+MAX_VERIFY_CODE_LENGTH,ServerCodeEnum.PARAM_ERROR.getCode());}if (type == 1){return generateNumberVerifyCode(length);}if (type == 2){return generateVerifyCode(length, STRING_VERIFY_CODE);}return generateVerifyCode(length, STRING_NUMBER_VERIFY_CODE);}/*** 返回base64图片验证码* @param code 验证码* @param imgWidth 宽度* @param imgHeight 高度* @return*/public static String generateCaptchaImageVerifyCode(String code, Integer imgWidth, Integer imgHeight){if (imgWidth == null){imgWidth = VerifyCodeUtils.imgWidth;}if (imgHeight == null){imgHeight = VerifyCodeUtils.imgHeight;}return generateCaptchaImage(imgWidth, imgHeight, code,DEFAULT_INTERFERE_RATE , DEFAULT_NOISE_RATE);}/*** 返回base64图片验证码* @param code 验证码* @param imgWidth 宽度* @param imgHeight 高度* @param interfereRate 干扰性系数0.0-1.0* @param noiseRate 噪声系数 0.0-1.0* @return*/public static String generateCaptchaImage(String code, int imgWidth, int imgHeight,float interfereRate, float noiseRate){return generateCaptchaImage(imgWidth, imgHeight, code, interfereRate, noiseRate);}/*** 生成验证码图片* @param imgWidth 宽度* @param imgHeight 高度* @param code 验证码* @param interfereRate 干扰系数 0.1-1* @param noiseRate 噪声系数 0.1-1*/private static String generateCaptchaImage(int imgWidth, int imgHeight, String code, float interfereRate, float noiseRate){String base64Img = null;try {int length = code.length();BufferedImage image = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);Random rand = new Random();Graphics2D graphics2D = image.createGraphics();graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// 设置边框色graphics2D.setColor(Color.GRAY);graphics2D.fillRect(0, 0, imgWidth, imgHeight);// 设置背景色Color c = new Color(235, 235, 235);graphics2D.setColor(c);graphics2D.fillRect(0, 1, imgWidth, imgHeight - 2);//绘制干扰interfere(image, graphics2D, imgWidth, imgHeight, interfereRate, noiseRate);//使图片扭曲shear(graphics2D, imgWidth, imgHeight, c);//字体颜色graphics2D.setColor(getRandColor(30, 100));//字体大小int fontSize = imgHeight >= 50 ?  imgHeight - 8 : imgHeight >= 30 ? imgHeight - 6 : imgHeight - 4;//字体 Fixedsys/AlgerianFont font = new Font("Fixedsys", Font.ITALIC, fontSize);graphics2D.setFont(font);char[] chars = code.toCharArray();for (int i = 0; i < length; i++) {//设置旋转AffineTransform affine = new AffineTransform();//控制在-0.3-0.3double theta = ((Math.PI / 4 * rand.nextDouble())*0.3) * (rand.nextBoolean() ? 1 : -1);affine.setToRotation(theta, (imgWidth / length) * i + fontSize / 2, imgHeight / 2);graphics2D.setTransform(affine);int x = ((imgWidth - 10) / length) * i + 4;//文字居中FontMetrics fm = graphics2D.getFontMetrics();int stringAscent = fm.getAscent();int stringDescent = fm.getDescent ();int y = imgHeight / 2 + (stringAscent - stringDescent) / 2;graphics2D.drawChars(chars, i, 1, x, y);}graphics2D.dispose();ByteArrayOutputStream outputStream = new ByteArrayOutputStream();ImageIO.write(image, "jpg", outputStream);Base64.Encoder encoder = Base64.getEncoder();base64Img = encoder.encodeToString(outputStream.toByteArray());base64Img = base64Img.replaceAll("\n", "").replaceAll("\r", "");}catch (Exception e){log.error("生成图片验证码异常:", e);}return base64Img;}/*** 绘制干扰线和噪点* @param image 图像* @param graphics2D 二维图* @param imgWidth 宽度* @param imgHeight 高度* @param interfereRate 干扰线率 0.1-1* @param noiseRate 噪声率 0.1-1*/private static void interfere(BufferedImage image,Graphics2D graphics2D, int imgWidth, int imgHeight, float interfereRate, float noiseRate){Random random = new Random();graphics2D.setColor(getRandColor(160, 200));int line = (int) (interfereRate * 100);for (int i = 0; i < line; i++) {int x = random.nextInt(imgWidth - 1);int y = random.nextInt(imgHeight - 1);int xl = random.nextInt(6) + 1;int yl = random.nextInt(12) + 1;graphics2D.drawLine(x, y, x + xl + 40, y + yl + 20);}int area = (int) (noiseRate * imgWidth * imgHeight)/10;for (int i = 0; i < area; i++) {int x = random.nextInt(imgWidth);int y = random.nextInt(imgHeight);int rgb = getRandomIntColor();image.setRGB(x, y, rgb);}}/*** 获取随机颜色* @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);}/*** 获取rgb* @return*/private static int getRandomIntColor() {int[] rgb = getRandomRgb();int color = 0;for (int c : rgb) {color = color << 8;color = color | c;}return color;}/*** 获取随机rgb颜色* @return*/private static int[] getRandomRgb() {int[] rgb = new int[3];for (int i = 0; i < 3; i++) {rgb[i] = random.nextInt(255);}return rgb;}/*** 使图片扭曲* @param g* @param w1* @param h1* @param color*/private static void shear(Graphics g, int w1, int h1, Color color) {distortionX(g, w1, h1, color);distortionY(g, w1, h1, color);}/*** 使图片x轴扭曲* @param g* @param w1* @param h1* @param color*/private static void distortionX(Graphics g, int w1, int h1, Color color) {int period = random.nextInt(4);boolean borderGap = true;int frames = 2;int phase = random.nextInt(4);for (int i = 0; i < h1; i++) {double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);g.copyArea(0, i, w1, 1, (int) d, 0);if (borderGap) {g.setColor(color);g.drawLine((int) d, i, 0, i);g.drawLine((int) d + w1, i, w1, i);}}}/*** 使图片y轴扭曲* @param g* @param w1* @param h1* @param color*/private static void distortionY(Graphics g, int w1, int h1, Color color) {int period = random.nextInt(20) + 10;boolean borderGap = true;int frames = 20;int phase = 8;for (int i = 0; i < w1; i++) {double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);g.copyArea(i, 0, 1, h1, 0, (int) d);if (borderGap) {g.setColor(color);g.drawLine(i, (int) d, i, 0);g.drawLine(i, (int) d + h1, i, h1);}}}/*** 创建字体* @param style 字体样式* @param size  字体大小* @return 字体*/private static Font createFont(int style, int size) {if (cacheFont != null) {return cacheFont.deriveFont(style, size);} else {cacheFont = loadFont();return cacheFont;}}/*** 加载字体,解决Centos 7.2 以后,使用OpenJDK11 生成不了验证码问题* @return 生成验证码的字体*/private static Font loadFont() {if (StringUtils.startsWithIgnoreCase(System.getProperty("os.name"), "windows")) {// windows 操作系统直接返回即可return new Font("Fixedsys", Font.BOLD, 0);} else {// linux 操作系统字体需要特殊处理try {InputStream inputStream = null;Resource fontFile = new DefaultResourceLoader().getResource("classpath:ALGER.TTF");try {// 加载字体配置文件Resource fontProperties = new DefaultResourceLoader().getResource("classpath:fontconfig.properties");System.setProperty("sun.awt.fontconfig", fontProperties.getURL().getPath());inputStream = fontFile.getInputStream();return Font.createFont(Font.TRUETYPE_FONT, inputStream);} catch (Exception e) {log.error("Create Font Error", e);} finally {IOUtils.closeQuietly(inputStream);}} catch (Exception e) {log.error("Load Font Error", e);}return null;}}/*** 生成验证码* @param code* @param imgWidth* @param imgHeight* @return*/private static String generateCaptchaImage(String code, Integer imgWidth, Integer imgHeight) {if (StringUtils.isBlank(code)) {return null;}imgWidth = imgWidth == null ? VerifyCodeUtils.imgWidth : imgWidth;imgHeight = imgHeight == null ? VerifyCodeUtils.imgHeight: imgHeight;Integer codeLength = code.length();BufferedImage bufferedImg = null;String base64Img = null;try {int x = 0;// 每个字符的宽度x = imgWidth / (codeLength + 1);int fontHeight = 0;// 字体的高度fontHeight = imgHeight - 10;float codeY;codeY = (float) (imgHeight - 10.1);// 生成一张图片bufferedImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);Graphics2D graph = bufferedImg.createGraphics();// 填充图片颜色graph.setColor(Color.WHITE);graph.fillRect(0, 0, imgWidth, imgHeight);// 创建字体Font font = new Font("Fixedsys", Font.TRUETYPE_FONT, fontHeight);graph.setFont(font);Random random = new Random();// 随机画干扰的圈圈int red = 0;int green = 0;int blue = 0;for (int i = 0; i < 10; i++) {int xs = random.nextInt(imgWidth);int ys = random.nextInt(imgHeight);int xe = random.nextInt(imgWidth / 16);int ye = random.nextInt(imgHeight / 16);red = random.nextInt(255);green = random.nextInt(255);blue = random.nextInt(255);graph.setColor(new Color(red, green, blue));graph.drawOval(xs, ys, xe, ye);}// 画随机线for (int i = 0; i < 20; i++) {int xs = random.nextInt(imgWidth);int ys = random.nextInt(imgHeight);int xe = xs + random.nextInt(imgWidth / 16);int ye = ys + random.nextInt(imgHeight / 16);red = random.nextInt(255);green = random.nextInt(255);blue = random.nextInt(255);graph.setColor(new Color(red, green, blue));graph.drawLine(xs, ys, xe, ye);}// 产生随机的颜色值,让输出的每个字符的颜色值都将不同。for (int i = 0; i < codeLength; i++) {red = random.nextInt(225);green = random.nextInt(225);blue = random.nextInt(225);graph.setColor(new Color(red, green, blue));String c = String.valueOf(code.charAt(i));graph.drawString(c, (float) (i + 0.5) * x, codeY);}ByteArrayOutputStream outputStream = new ByteArrayOutputStream();ImageIO.write(bufferedImg, "jpg", outputStream);Base64.Encoder encoder = Base64.getEncoder();base64Img = encoder.encodeToString(outputStream.toByteArray());base64Img = base64Img.replaceAll("\n", "").replaceAll("\r", "");} catch (Exception e) {log.error("生成验证码异常:", e);}
//        return "data:image/jpg;base64," + base64Img;return base64Img;}
}
http://www.xdnf.cn/news/808381.html

相关文章:

  • 什么是ip地址什么是网关_ip地址.网关.子掩码是什么?今天终于搞清楚了!
  • 短视频剪辑真的不难!50个新手必备剪辑技巧。
  • 安卓玩机搞机技巧综合资源-----“另类更新“偷渡”操作步骤 无需解锁bl 无需内侧用户【十三】
  • 找人改论文2023最新更新
  • 神经网络算法--文搞懂Tokenization(分词)
  • gateway网关的理解和使用
  • Mysql current_time,current_date()与now()区别
  • response.setHeader()的用法
  • C语言read函数和pread函数
  • 实训-永恒之蓝入侵系统
  • Linux:分享七款界面非常漂亮的Linux操作系统
  • Linux命令:traceroute命令(路由跟踪)
  • 实用在线词典
  • 一文搞懂Path环境变量
  • 【一】Java快速入门
  • CyanogenMOD移植教程]
  • Android SDK安装教程(超详细),从零基础入门到实战,从看这篇开始
  • 【转】Linux下进程隐藏的常见手法及侦测手段
  • VRRP----虚拟路由器冗余协议
  • 软件测试笔记:黑盒测试——边界测试
  • zCloud - 自治智能的数据库云管平台
  • 《通信技术 - USB》USB基础知识
  • 【C语言编程】新手学C语言时,那些不得不注意的小细节!
  • Pytorch 版本的lookahead 优化函数使用(附代码)
  • WML语言与编程
  • Java 枚举(enum)剖析
  • AI编程助手 Kodezi : 记录、分享一个 VS code 插件
  • 如何符合E-NCAP测试规范?TPT让AEB场景测试更简单:AEB系统的测试场景 | 测试执行与评估 | 测试用例渲染展示
  • 允许Traceroute探测
  • SQL中的distinct的使用方法