- <dependency>
- <groupId>com.github.pengglegroupId>
- <artifactId>kaptchaartifactId>
- <version>2.3.2version>
- dependency>
类方法配置了验证码的生成格式和规则,并返回一个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;
- }
- }
- 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());
-
- }
-
- }
- 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
- <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>