引入依赖包
com.github.penggle kaptcha2.3.2
配置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 { @Bean public 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_"; @Autowired public RedisTemplate redisTemplate; @Resource private 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 jpeg response.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() ,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 jpeg response.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 jpeg response.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 text BufferedImage bi = captchaProducer.createImage(capText); ServletOutputStream out = response.getOutputStream(); // write the data out ImageIO.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 text BufferedImage 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\n return 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
生成验证码图片转 base64,用于方法请求后,将结果赋值到img标签src属性 生成验证码图片转 base64,用于方法请求后,将结果赋值到img标签src属性 生成验证码图片转 base64,用于方法请求后,将结果赋值到img标签src属性