生成验证码图片

引入依赖包

<!-- 图形验证码 -->
<dependency><groupId>com.github.penggle</groupId><artifactId>kaptcha</artifactId><version>2.3.2</version>
</dependency>

 配置DefaultKaptcha类

类方法配置了验证码的生成格式和规则,并返回一个DefaultKaptcha对象并注入到Spring中

package com.dream.datacenter.config;import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;import java.util.Properties;/*** Created with IntelliJ IDEA* 图形验证码属性配置* @Author: Mr.HPC* @Date: 2022/1/6 23:08* @Version 1.0*/
@Component
public class CodeImgConfig {@Beanpublic DefaultKaptcha getDefaultKaptcha() {DefaultKaptcha defaultKaptcha = new DefaultKaptcha();Properties properties = new Properties();// 图片边框properties.setProperty("kaptcha.border", "no");// 边框颜色properties.setProperty("kaptcha.border.color", "black");//边框厚度properties.setProperty("kaptcha.border.thickness", "1");// 图片宽properties.setProperty("kaptcha.image.width", "200");// 图片高properties.setProperty("kaptcha.image.height", "50");//图片实现类properties.setProperty("kaptcha.producer.impl", "com.google.code.kaptcha.impl.DefaultKaptcha");//文本实现类properties.setProperty("kaptcha.textproducer.impl", "com.google.code.kaptcha.text.impl.DefaultTextCreator");//文本集合,验证码值从此集合中获取properties.setProperty("kaptcha.textproducer.char.string", "01234567890");//验证码长度properties.setProperty("kaptcha.textproducer.char.length", "4");//字体properties.setProperty("kaptcha.textproducer.font.names", "宋体");//字体颜色properties.setProperty("kaptcha.textproducer.font.color", "black");//文字间隔properties.setProperty("kaptcha.textproducer.char.space", "5");//干扰实现类properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.DefaultNoise");//干扰颜色properties.setProperty("kaptcha.noise.color", "blue");//干扰图片样式properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.WaterRipple");//背景实现类properties.setProperty("kaptcha.background.impl", "com.google.code.kaptcha.impl.DefaultBackground");//背景颜色渐变,结束颜色properties.setProperty("kaptcha.background.clear.to", "white");//文字渲染器properties.setProperty("kaptcha.word.impl", "com.google.code.kaptcha.text.impl.DefaultWordRenderer");Config config = new Config(properties);defaultKaptcha.setConfig(config);return defaultKaptcha;}
}

Controller 请求方法

package com.dream.datacenter.controller;import com.dream.datacenter.shiro.JWTUtil;
import com.dream.datacenter.utils.ImageUtil;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;@RestController
@RequestMapping("/test")
public class testController {public static final String VERIFICATION_CODE = "verificationCode_";@Autowiredpublic RedisTemplate redisTemplate;@Resourceprivate DefaultKaptcha captcha;/*** 第一种方式* 使用DefaultKaptcha生成登录验证码图片* 转成base64编码的字符串输出到前端* 实际项目这里还要加入JWT令牌校验和redis缓存*/@RequestMapping(value = {"/loginValidateCode"})public String loginValidateCode(HttpServletRequest request, HttpServletResponse response) throws Exception{response.setDateHeader("Expires", 0);// Set standard HTTP/1.1 no-cache headers.response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");// Set IE extended HTTP/1.1 no-cache headers (use addHeader).response.addHeader("Cache-Control", "post-check=0, pre-check=0");// Set standard HTTP/1.0 no-cache header.response.setHeader("Pragma", "no-cache");// return a jpegresponse.setContentType("image/jpeg");// 生成图片验证码内容String capText = captcha.createText();// 获取用户的jwt令牌String userVerificationJwt = request.getHeader(JWTUtil.JWT_VERIFICATION_KEY);//验证码令牌Claims claims = JWTUtil.validateJwtToken(userVerificationJwt);if(claims == null){//如果用户令牌过期那么对应存放在redis中的数据也要清空if(!org.apache.commons.lang3.StringUtils.isEmpty(userVerificationJwt)){redisTemplate.expire(VERIFICATION_CODE + userVerificationJwt, 1, TimeUnit.DAYS);}//重新生成用户令牌userVerificationJwt =  JWTUtil.createJwt(new HashMap<String, Object>() ,JWTUtil.EXPIRE_TIME);//将jwt令牌放入 response head中response.setHeader(JWTUtil.JWT_VERIFICATION_KEY, userVerificationJwt);}//刷新缓存,更新验证码redisTemplate.opsForValue().set(VERIFICATION_CODE + userVerificationJwt , capText,60, TimeUnit.SECONDS);System.out.println(capText);
//        ImageUtil.validateCode(response,captcha,capText);//生成图片String code = "data:image/png;base64," + ImageUtil.validateCode(captcha,capText);return code;}/*** 第二种方式* 使用Graphics绘图来定制格式,生成验证码* 转成base64编码的字符串输出到前端*/@RequestMapping(value = {"/loginValidateCode1"})public String loginValidateCode1(HttpServletRequest request, HttpServletResponse response) throws Exception{response.setDateHeader("Expires", 0);// Set standard HTTP/1.1 no-cache headers.response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");// Set IE extended HTTP/1.1 no-cache headers (use addHeader).response.addHeader("Cache-Control", "post-check=0, pre-check=0");// Set standard HTTP/1.0 no-cache header.response.setHeader("Pragma", "no-cache");// return a jpegresponse.setContentType("image/png");String str = captcha.createText();//使用DefaultKaptcha规则生成随机码//生成图片String code = "data:image/png;base64," + ImageUtil.createImageWithVerifyCode(str,200,50);return code;}/*** 第三种方式* 使用DefaultKaptcha生成登录验证码图片* 并用文件流方式输出到前端*/@RequestMapping(value = {"/loginValidateCode2"})public void loginValidateCode2(HttpServletRequest request, HttpServletResponse response) throws Exception{response.setDateHeader("Expires", 0);// Set standard HTTP/1.1 no-cache headers.response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");// Set IE extended HTTP/1.1 no-cache headers (use addHeader).response.addHeader("Cache-Control", "post-check=0, pre-check=0");// Set standard HTTP/1.0 no-cache header.response.setHeader("Pragma", "no-cache");// return a jpegresponse.setContentType("image/png");ImageUtil.validateCode(response,captcha,captcha.createText());}}

 ImageUtil公共类

package com.dream.datacenter.utils;import com.google.code.kaptcha.impl.DefaultKaptcha;
import java.util.Base64;
import java.util.Base64.Encoder;import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Random;/*** Created with IntelliJ IDEA** @Author: Mr.HPC* @Date: 2022/1/6 23:19* @Version 1.0* 验证码工具类*/
public class ImageUtil {/*** 第一种,用于IO输出* @param captchaProducer 生成图片方法类* @throws Exception*/public static void validateCode(HttpServletResponse response,DefaultKaptcha captchaProducer,String capText) throws Exception{// create the image with the textBufferedImage bi = captchaProducer.createImage(capText);ServletOutputStream out = response.getOutputStream();// write the data outImageIO.write(bi, "JPEG", out);try {out.flush();} finally {out.close();}}/*** 第二种* 生成验证码图片转 base64,用于方法请求后,将结果赋值到img标签src属性* @param captchaProducer 生成图片方法类* @throws Exception*/public static String validateCode(DefaultKaptcha captchaProducer,String capText) throws Exception{// create the image with the textBufferedImage bi = captchaProducer.createImage(capText);return returnPicBase64(bi);}/*** 第三种,生成验证码图片转 base64,用于方法请求后,将结果赋值到img标签src属性* @param word 要生存的验证码随机字符串* @param width 图片宽度* @param height 图片高度* @return base64 格式生成的验证码图片* @throws IOException*/public static String createImageWithVerifyCode(String word, int width, int height) throws IOException {String png_base64="";//绘制内存中的图片BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);//得到画图对象Graphics graphics = bufferedImage.getGraphics();//绘制图片前指定一个颜色graphics.setColor(getRandColor(160,200));graphics.fillRect(0,0,width,height);//绘制边框graphics.setColor(Color.white);graphics.drawRect(0, 0, width - 1, height - 1);// 步骤四 四个随机数字Graphics2D graphics2d = (Graphics2D) graphics;graphics2d.setFont(new Font("宋体", Font.BOLD, 18));Random random = new Random();// 定义x坐标int x = 10;for (int i = 0; i < word.length(); i++) {// 随机颜色graphics2d.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));// 旋转 -30 --- 30度int jiaodu = random.nextInt(60) - 30;// 换算弧度double theta = jiaodu * Math.PI / 180;// 获得字母数字char c = word.charAt(i);//将c 输出到图片graphics2d.rotate(theta, x, 20);graphics2d.drawString(String.valueOf(c), x, 20);graphics2d.rotate(-theta, x, 20);x += 30;}// 绘制干扰线graphics.setColor(getRandColor(160, 200));int x1;int x2;int y1;int y2;for (int i = 0; i < 30; i++) {x1 = random.nextInt(width);x2 = random.nextInt(12);y1 = random.nextInt(height);y2 = random.nextInt(12);graphics.drawLine(x1, y1, x1 + x2, x2 + y2);}graphics.dispose();// 释放资源return returnPicBase64(bufferedImage);}/*** 将图片字节数组码转为base64编码* @param bi* @return* @throws IOException*/private static String returnPicBase64(BufferedImage bi) throws IOException {String png_base64;ByteArrayOutputStream baos = new ByteArrayOutputStream();//io流ImageIO.write(bi, "png", baos);//写入流中byte[] bytes = baos.toByteArray();//转换成字节
//        BASE64Encoder encoder = new BASE64Encoder();
//        png_base64 = encoder.encodeBuffer(bytes).trim();Encoder encoder = Base64.getEncoder();png_base64 = encoder.encodeToString(bytes).trim();png_base64 = png_base64.replaceAll("\n", "").replaceAll("\r", "");//删除 \r\nreturn png_base64;}/**设置随机颜色*/private static Color getRandColor(int fc, int bc) {// 取其随机颜色Random random = new Random();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);}
}

前端代码的调用

test.js 文件

// 图形校验码接口
export const codeImgUrl = "/api/test/loginValidateCode";export const codeImgUrl1 = "/api/test/loginValidateCode1";
export const codeImgUrl2 = "/api/test/loginValidateCode2";

yzm.vue 文件,其中 refreshCode2() 方法的 this.ruleForm.codeimg2 = window.URL.createObjectURL(blob); 是将图片io流转成浏览器可以识别的URL

<template><div class="login-wrap"><el-form label-position="left" :model="ruleForm" :rules="rules" ref="ruleForm" label-width="0px" class="demo-ruleForm login-container"><el-row><el-col :span="4" class="code-box"><el-text>生成验证码图片转 base64,用于方法请求后,将结果赋值到img标签src属性</el-text><img :src="ruleForm.codeimg" alt="验证码" class="codeimg" @click="refreshCode()"></el-col><el-col :span="4" class="code-box"><el-text>生成验证码图片转 base64,用于方法请求后,将结果赋值到img标签src属性</el-text><img :src="ruleForm.codeimg1" alt="验证码" class="codeimg" @click="refreshCode1()"></el-col><el-col :span="4" class="code-box"><el-text>生成验证码图片转 base64,用于方法请求后,将结果赋值到img标签src属性</el-text><img :src="ruleForm.codeimg2" alt="验证码" class="codeimg" @click="refreshCode2()"></el-col></el-row></el-form></div></template><script type="text/ecmascript-6">import { codeImgUrl,codeImgUrl1,codeImgUrl2 } from '../../api/test';import md5 from 'js-md5';import axios from 'axios';export default {name: 'yzm',data() {return {ruleForm: {code: '',codeimg: '',codeimg1: '',codeimg2: ''},//rules前端验证rules: {}}},// 创建完毕状态(里面是操作)created() {// 获取图形验证码this.refreshCode()this.refreshCode1()this.refreshCode2()},methods: {//获取图形验证码refreshCode() {// this.ruleForm.codeimg = codeImgUrl+"?t="+Date.now();let url = codeImgUrl+"?t="+Date.now();axios.get(url).then(res => {this.ruleForm.codeimg = res.data}).catch(resp => {console.log(resp);});},refreshCode1() {// this.ruleForm.codeimg = codeImgUrl+"?t="+Date.now();let url = codeImgUrl1+"?t="+Date.now();axios.get(url).then(res => {this.ruleForm.codeimg1 = res.data}).catch(resp => {console.log(resp);});},refreshCode2() {// this.ruleForm.codeimg = codeImgUrl+"?t="+Date.now();let url = codeImgUrl2+"?t="+Date.now();axios.request({url: url,responseType: 'blob',method: 'get'}).then(res => {let blob = new Blob([res.data], {type: "image/png"});this.ruleForm.codeimg2 = window.URL.createObjectURL(blob);}), (error) => {this.$message({type: 'warning',message: '系统错误,请联系管理员!'});}},}}</script><style scoped></style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/738858.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

目标检测数据集:手机顶盖焊缺陷检测数据集

✨✨✨✨✨✨目标检测数据集✨✨✨✨✨✨ 本专栏提供各种场景的数据集,主要聚焦:工业缺陷检测数据集、小目标数据集、遥感数据集、红外小目标数据集,该专栏的数据集会在多个专栏进行验证,在多个数据集进行验证mAP涨点明显,尤其是小目标、遮挡物精度提升明显的数据集会在该…

std::thread 的构造-源码解析

std::thread 的构造-源码解析 我们这单章是为了专门解释一下 std::thread 是如何构造的&#xff0c;是如何创建线程传递参数的&#xff0c;让你彻底了解这个类。 我们以 MSVC 实现的 std::thread 代码进行讲解。 std::thread 的数据成员 了解一个庞大的类&#xff0c;最简单…

Anaconda环境全局环境手动配置

Anaconda环境全局环境手动配置 如图&#xff0c;在本机就有Anaconda的情况下&#xff0c;普通cmd无法直接使用conda命令&#xff0c;每次都要从Anaconda Prompt窗口操作&#xff0c;挺不方便的&#xff0c;遂决定进行全局环境配置&#xff0c;记录一下流程。 找到环境配置页面…

R语言绘制散点密度图ggdentity

使用R语言绘制二维密度图 下图是一张常见的二维核密度散点图&#xff0c;能够清晰直观的反映出数据之间的分布趋势&#xff0c;颜色越红的位置数据越集中分布。今天分享的笔记是在R语言中绘制该图的两种常见方法&#xff0c;提供过程代码。 论文中常见的这种展示两组数据之间分…

Java入门学习(1)

常用的CMD命令&#xff1a; 1.盘符名称 冒号 说明&#xff1a;盘符切换&#xff1b; 举例&#xff1a;E:回车&#xff0c;表示切换到E盘。 2.dir 说明&#xff1a;查看当前路径下的内容。 3.cd 说明&#xff1a;进入单级目录。 举例&#xff1a;cd itheima 4.cd.. 说…

上班族必备技能!轻松掌握excel文件如何批量加后缀名方法,提升工作效率!

后缀名是什么 后缀名是帮助人区分文件类型的一种手段&#xff0c;文件后缀名也叫文件扩展名&#xff0c;是用来表示某种文件格式所采用的机制。文件扩展名是加在主文件名后面的&#xff0c;用“.”分隔。不同的软件要求不同的文件格式&#xff0c;后缀名可以帮助用户了解文件是…

可以作为GC.Roots的对象有哪些?

在Java中&#xff0c;GC Roots 是一组特殊的对象&#xff0c;它们被认为是可达的&#xff0c;并且不会被垃圾收集器回收。这些对象包括但不限于以下几种&#xff1a; 虚拟机栈中引用的对象&#xff1a;活跃线程中的本地变量引用的对象&#xff0c;以及正在执行的方法中的参数对…

Python 可视化和数据缺失处理库之missingno使用详解

概要 在数据分析和数据科学的领域中,数据缺失是一个常见的问题。数据缺失可能会导致分析和建模结果的不准确性,因此了解如何处理和可视化缺失数据至关重要。Python Missingno 是一个强大的工具,可以直观地识别和处理数据中的缺失值。本文将详细介绍 Python Missingno 的功能…

从命令提示窗口使用 Visual C++ Toolkit 2003

从命令提示窗口使用 Visual C Toolkit 2003 发布日期 : 12/20/2004 | 更新日期 : 12/20/2004 Brian Johnson MSDN Visual C 内容战略家 适用于&#xff1a; Visual Studio .NET 2003 Microsoft Visual C .NET 2003 Microsoft Visual C Toolkit 2003 摘要&#xff1a;在本文中…

Threejs播放模型自带动画

现在的很多建模软件都可以制作动画效果&#xff0c;甚至可以通过各种动画效果直接做动漫&#xff0c;动漫是模型的一种属性&#xff0c;在threejs中同样可以加载此动画&#xff0c;实现动画效果&#xff0c;如果有的时候在threejs中用代码实现模型动画比较困难或者麻烦&#xf…

MongoDB聚合运算符:$denseRank

$denseRank聚合运算符返回在$setWindowFields阶段分区中文档的排名&#xff0c;排名的顺序由$setWindowFields阶段sortBy的字段值决定。 语法 { $denseRank: { } }$denseRank不需要任何参数。 使用 $rank和$denseRank的不同点在于他们处理排序字段重复值的方式不同&#xf…

嵌入式、开发板 智能音响 OpenHarmony GPT 大模型 智能硬件

一、概述 生活场景的引入: 物联网的快速发展,各种智能设备层出不穷,作为极客,家里早已安上了用 APP 控制的智能灯、智能插座,刚刚安装上的时候,还有新鲜感,久了之后,是不是会有这样的现象: 早上醒来要开灯,需要经过: 迷迷糊糊从床头柜上摸到手机手机用指纹解锁连接无…

3.11 log | 739. 每日温度,

739. 每日温度&#xff0c;496.下一个更大元素 I&#xff0c;503.下一个更大元素II&#xff0c; class Solution { public:vector<int> dailyTemperatures(vector<int>& temperatures) {stack<int> st;vector<int> result(temperatures.size(),0)…

Hadoop学习1:概述、单体搭建、伪分布式搭建

文章目录 概述基础知识Hadoop组件构成Hadoop配置文件 环境准备配置Hadoop配置下载配置环境变量 Hadoop运行模式Standalone Operation&#xff08;本地&#xff09;官方DemoWordCount单词统计Demo Pseudo-Distributed Operation&#xff08;伪分布式模式&#xff09;配置修改启动…

Bootstrap5(display显示、flex布局相关属性、浮动、定位、文本、栅格系统)

类中缀的设置技巧 1.当多个连续品目使用一个样式时&#xff0c;则给最小的设置即可。 比如&#xff1a;大屏以上内边距都是3&#xff1a;p-lh-3 2.超小屏不设置类中缀的样式 比如超小屏内边距时1&#xff0c;小屏内边距时2&#xff0c;中屏及以上内边距是3 p-1 p-sm-2 p-md-3 …

WPF 界面刷新问题 不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改

WPF 界面刷新问题 不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改 问题描述&#xff1a; 在子线程中操作界面控件的数据源出现以下错误&#xff1a;System.NotSupportedException:“该类型的 CollectionView 不支持从调度程序线程以外的线程对其 SourceCo…

【Python】新手入门学习:什么是相对路径?

【Python】新手入门学习&#xff1a;什么是相对路径&#xff1f; &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448; 希望得…

【Echarts】柱状图上方显示数字以及自定义值,标题和副标题居中,鼠标上显示信息以及自定义信息

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《前端》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握…

linux 环境安装nvm

linux 环境安装nvm 1、安装方式 # 方式1 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash # 方式2 【推荐】 wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash2、创建nvm命令目录 mkdir -p ~/.nvm3、编…

StringBuilder --java学习笔记

StringBuilder 代表可变字符串对象&#xff0c;相当于是一个容器&#xff0c;它里面装的字符串是可以改变的&#xff0c;就是用来操作字符串的StringBuilder比String更适合做字符串的修改操作&#xff0c;效率会更高&#xff0c;代码也会更简洁 StringBuilder的常用构造器和方…