• 微信公众号:美女很有趣。 工作之余,放松一下,关注即送10G+美女照片!

【前后端分离】Springboot+Vue实现Kaptcha生成验证码、Graphics 2D随机验证码(两种样式) | 通过Vue显示到前端页面

互联网 diligentman 1周前 (06-11) 15次浏览

阅读目录

  • 一、kaptcha实现代码
    • 1. 引入坐标依赖
    • 2. CaptchaConfig
    • 3. CaptchaController
    • 4. 配置端口
    • 5. 应用程序启动入口
  • 二、Graphics 2D实现
    • CaptchaConfig2
    • Captcha2Controller
  • 三、前端 Vue项目
    • Login.vue
    • vue.config.js
  • 四、源码下载


效果图:

通过Graphics 2D实现:
【前后端分离】Springboot+Vue实现Kaptcha生成验证码、Graphics 2D随机验证码(两种样式) | 通过Vue显示到前端页面

通过kaptcha实现:
【前后端分离】Springboot+Vue实现Kaptcha生成验证码、Graphics 2D随机验证码(两种样式) | 通过Vue显示到前端页面

一、kaptcha实现代码

1. 引入坐标依赖

首先在Springboot项目下的pom下加入依赖坐标:

  <!-- 验证码 -->
   <dependency>
       <groupId>com.github.axet</groupId>
       <artifactId>kaptcha</artifactId>
       <version>0.0.9</version>
   </dependency>     

2. CaptchaConfig

CaptchaConfig 用来配置验证码信息:

package com.example.demo.util;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Description: 通过开源kaptcha配置验证码
 * @Author: liyingxia
 * @CreateDate: 2021/6/08 12:58
 */

import java.util.Properties;

@Configuration
public class CaptchaConfig {
    @Bean
    public DefaultKaptcha getDefaultCaptcha() {
        //验证码生成器
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        //配置
        Properties properties = new Properties();
        //是否有边框
        properties.setProperty("kaptcha.border", "yes");
        //设置边框颜色
        properties.setProperty("kaptcha.border.color", "105,179,90");
        //验证码
        properties.setProperty("kaptcha.session.key", "code");
        //验证码文本字符颜色 默认为黑色
        properties.setProperty("kaptcha.textproducer.font.color", "blue");
        //设置字体样式
        properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑");
        //字体大小 默认40
        properties.setProperty("kaptcha.textproducer.font.size", "30");
        //验证码文本字符内容范围 默认为abced23456789gfynmnpwx
        properties.setProperty("kaptcha.textproducer.char.string", "");
        //字符长度 默认为5
        properties.setProperty("kaptcha.textproducer.char.length", "4");
        //字符间距 默认为2
        properties.setProperty("kaptcha.textproducer.char.space", "4");
        //验证码图片宽度 默认为200
        properties.setProperty("kaptcha.image.width", "100");
        //验证码图片高度 默认为40
        properties.setProperty("kaptcha.image.height", "40");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}

3. CaptchaController

contoller层控制页面访问

package com.example.demo.controller;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;

/**
 * @Description: 验证码类型1
 * @Author: liyingxia
 * @CreateDate: 2021/6/08 12:58
 */


@RestController
public class CaptchaController {
    @Autowired
    private DefaultKaptcha defaultKaptcha;

    /*--------------获取验证码-------------*/
    @GetMapping(value = "/captcha", produces = "image/jpeg")
    public void captcha(HttpServletRequest request, HttpServletResponse response) {
        // 定义response输出类型为image/jpeg
        response.setDateHeader("Expires", 0);
        // 设置http标准
        response.setHeader("Cache-Control", "no-store,no-cache,must-revalidate");
        // 设置请求头
        response.addHeader("Cache-Control", "post-check=0,pre-check=0");
        response.setHeader("Pragma", "no-cache");
        // 响应返回的是image/jpeg类型
        response.setContentType("image/jpeg");


        /*--------------生成验证码-------------*/
        String text = defaultKaptcha.createText();  // 获取验证码文本内容
        System.out.println("验证码为" + text);
        // 将验证码文本内容放入session
        request.getSession().setAttribute("captcha", text);
        // 根据文本验证码内容创建图形验证码
        BufferedImage image = defaultKaptcha.createImage(text);
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            // 输出流输出文件格式为jpg
            ImageIO.write(image, "jpg", outputStream);
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4. 配置端口

# 端口
server.port=8008

# 数据库
spring.datasource.url=jdbc:mysql://localhost:3306/my-sys?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

5. 应用程序启动入口

CaptchaApplication:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CaptchaApplication {

    public static void main(String[] args) {
        SpringApplication.run(CaptchaApplication.class, args);
        System.out.println("=========项目启动成功=========");
    }
}

启动运行CaptchaApplication,成功运行后,通过postman测试验证码,输入http://localhost:8008/captcha,即可获取返回的验证码:
【前后端分离】Springboot+Vue实现Kaptcha生成验证码、Graphics 2D随机验证码(两种样式) | 通过Vue显示到前端页面

二、Graphics 2D实现

CaptchaConfig2

package com.example.demo.util;


import java.awt.*;
import java.util.Random;

/**
 * @Description: Graphics2D配置验证码
 * @Author: liyingxia
 * @CreateDate: 2021/6/08 13:58
 */

public class CaptchaConfig2 {
    public static final int WIDTH = 150;//生成的图片的宽度
    public static final int HEIGHT = 38;//生成的图片的高度

    /**
     * 设置字体
     */
    public static Font font[] = {
            new Font("宋体", Font.BOLD, 24),
            new Font("宋体", Font.BOLD, 24)
    };

    /**
     * 设置背景颜色
     * @param g
     */
    public static void setBackGround(Graphics g) {
        // 设置颜色
        g.setColor(Color.WHITE);
        // 填充区域
        g.fillRect(0, 0, WIDTH, HEIGHT);
    }

    /**
     * 设置图片的边框
     * @param g
     */
    public static void setBorder(Graphics g) {
        // 设置边框颜色
        g.setColor(Color.WHITE);
        // 边框区域
        g.drawRect(1, 1, WIDTH - 2, HEIGHT - 2);
    }

    /**
     * 设置随机干扰线条
     * @param g
     */
    public static void drawRandomLine(Graphics g) {
        // 设置线条个数并画线
        for (int i = 0; i < 3; i++) {
            // 设置颜色
            g.setColor(getRandColorCode());
            int x1 = new Random().nextInt(WIDTH / 2);
            int y1 = new Random().nextInt(HEIGHT / 2);
            int x2 = new Random().nextInt(WIDTH) + WIDTH / 2;
            int y2 = new Random().nextInt(HEIGHT) + HEIGHT / 2;
            Graphics2D g2 = (Graphics2D) g;
            // 设置笔画的属性,设置线条的粗细
            g2.setStroke(new BasicStroke(2.5f));
            g2.drawLine(x1, y1, x2, y2);
        }
    }

    /**
     * 生成随机字符
     *
     * @param g
     * @param baseChar
     * @return 随机字符
     */
    public static String createRandomChar(Graphics2D g, String baseChar) {
        StringBuffer stringBuffer = new StringBuffer();
        int x = 15;
        String ch = "";
        // 设置生成字数
        for (int i = 0; i < 4; i++) {
            g.setFont(font[new Random().nextInt(font.length - 1)]);
            g.setColor(getRandColorCode());
            // 设置字体旋转角度
            int degree = new Random().nextInt() % 30;
            ch = baseChar.charAt(new Random().nextInt(baseChar.length())) + "";
            stringBuffer.append(ch);
            // 正向角度
            g.rotate(degree * Math.PI / 180, x, 33);
            g.drawString(ch, x, 33);
            // 反向角度
            g.rotate(-degree * Math.PI / 180, x, 33);
            x += 25;
        }
        return stringBuffer.toString();
    }

    /**
     * 随机颜色
     * @return
     */
    public static Color getRandColorCode() {
        int r, g, b;
        Random random = new Random();
        r = random.nextInt(256);
        g = random.nextInt(256);
        b = random.nextInt(256);
        Color color = new Color(r, g, b);
        return color;
    }

    /**
     * 画随机字符
     * @param g
     * @param createTypeFlag
     * @return String
     */
    public static String drawRandomNum(Graphics2D g, String... createTypeFlag) {
        // 设置颜色
        g.setColor(Color.RED);
        // 设置字体
        g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 24));
        // 常用的中国汉字
        String baseChineseChar = "u7684u4e00u4e86u662fu6211u4e0du5728u4ebau4eecu6709u6765u4ed6u8fd9u4e0au7740u4e2au5730u5230u5927u91ccu8bf4u5c31u53bbu5b50u5f97u4e5fu548cu90a3u8981u4e0bu770bu5929u65f6u8fc7u51fau5c0fu4e48u8d77u4f60u90fdu628au597du8fd8u591au6ca1u4e3au53c8u53efu5bb6u5b66u53eau4ee5u4e3bu4f1au6837u5e74u60f3u751fu540cu8001u4e2du5341u4eceu81eau9762u524du5934u9053u5b83u540eu7136u8d70u5f88u50cfu89c1u4e24u7528u5979u56fdu52a8u8fdbu6210u56deu4ec0u8fb9u4f5cu5bf9u5f00u800cu5df1u4e9bu73b0u5c71u6c11u5019u7ecfu53d1u5de5u5411u4e8bu547du7ed9u957fu6c34u51e0u4e49u4e09u58f0u4e8eu9ad8u624bu77e5u7406u773cu5fd7u70b9u5fc3u6218u4e8cu95eeu4f46u8eabu65b9u5b9eu5403u505au53ebu5f53u4f4fu542cu9769u6253u5462u771fu5168u624du56dbu5df2u6240u654cu4e4bu6700u5149u4ea7u60c5u8defu5206u603bu6761u767du8bddu4e1cu5e2du6b21u4eb2u5982u88abu82b1u53e3u653eu513fu5e38u6c14u4e94u7b2cu4f7fu5199u519bu5427u6587u8fd0u518du679cu600eu5b9au8bb8u5febu660eu884cu56e0u522bu98deu5916u6811u7269u6d3bu90e8u95e8u65e0u5f80u8239u671bu65b0u5e26u961fu5148u529bu5b8cu5374u7ad9u4ee3u5458u673au66f4u4e5du60a8u6bcfu98ceu7ea7u8ddfu7b11u554au5b69u4e07u5c11u76f4u610fu591cu6bd4u9636u8fdeu8f66u91cdu4fbfu6597u9a6cu54eau5316u592au6307u53d8u793eu4f3cu58ebu8005u5e72u77f3u6ee1u65e5u51b3u767eu539fu62ffu7fa4u7a76u5404u516du672cu601du89e3u7acbu6cb3u6751u516bu96beu65e9u8bbau5417u6839u5171u8ba9u76f8u7814u4ecau5176u4e66u5750u63a5u5e94u5173u4fe1u89c9u6b65u53cdu5904u8bb0u5c06u5343u627eu4e89u9886u6216u5e08u7ed3u5757u8dd1u8c01u8349u8d8au5b57u52a0u811au7d27u7231u7b49u4e60u9635u6015u6708u9752u534au706bu6cd5u9898u5efau8d76u4f4du5531u6d77u4e03u5973u4efbu4ef6u611fu51c6u5f20u56e2u5c4bu79bbu8272u8138u7247u79d1u5012u775bu5229u4e16u521au4e14u7531u9001u5207u661fu5bfcu665au8868u591fu6574u8ba4u54cdu96eau6d41u672au573au8be5u5e76u5e95u6df1u523bu5e73u4f1fu5fd9u63d0u786eu8fd1u4eaeu8f7bu8bb2u519cu53e4u9ed1u544au754cu62c9u540du5440u571fu6e05u9633u7167u529eu53f2u6539u5386u8f6cu753bu9020u5634u6b64u6cbbu5317u5fc5u670du96e8u7a7fu5185u8bc6u9a8cu4f20u4e1au83dcu722cu7761u5174u5f62u91cfu54b1u89c2u82e6u4f53u4f17u901au51b2u5408u7834u53cbu5ea6u672fu996du516cu65c1u623fu6781u5357u67aau8bfbu6c99u5c81u7ebfu91ceu575au7a7au6536u7b97u81f3u653fu57ceu52b3u843du94b1u7279u56f4u5f1fu80dcu6559u70edu5c55u5305u6b4cu7c7bu6e10u5f3au6570u4e61u547cu6027u97f3u7b54u54e5u9645u65e7u795eu5ea7u7ae0u5e2eu5566u53d7u7cfbu4ee4u8df3u975eu4f55u725bu53d6u5165u5cb8u6562u6389u5ffdu79cdu88c5u9876u6025u6797u505cu606fu53e5u533au8863u822cu62a5u53f6u538bu6162u53d4u80ccu7ec6";
        //数字和字母的组合
        String baseNumLetter = "0123456789ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        //纯数字
        String baseNum = "0123456789";
        //纯字母
        String baseLetter = "ABCDEFGHJKLMNOPQRSTUVWXYZ";
        if (createTypeFlag.length > 0 && null != createTypeFlag[0]) {
            if (createTypeFlag[0].equals("ch")) {
                // 截取汉字
                return createRandomChar(g, baseChineseChar);
            } else if (createTypeFlag[0].equals("nl")) {
                // 截取数字和字母的组合
                return createRandomChar(g, baseNumLetter);
            } else if (createTypeFlag[0].equals("n")) {
                // 截取数字
                return createRandomChar(g, baseNum);
            } else if (createTypeFlag[0].equals("l")) {
                // 截取字母
                return createRandomChar(g, baseLetter);
            }
        } else {
            // 默认截取数字和字母的组合
            return createRandomChar(g, baseNumLetter);
        }
        return "";
    }

}

Captcha2Controller

package com.example.demo.controller;


import com.example.demo.util.CaptchaConfig2;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;

/**
 * @Description: 验证码类型2
 * @Author: liyingxia
 * @CreateDate: 2021/6/08 12:58
 */

@Controller
public class Captcha2Controller {
    @RequestMapping(value = "/captcha2", method = RequestMethod.GET)
    public void identifyPicture(HttpServletResponse response) {
        //1.创建一张图片
        BufferedImage bi = new BufferedImage(CaptchaConfig2.WIDTH, CaptchaConfig2.HEIGHT, BufferedImage.TYPE_INT_RGB);
        //2.获取图片
        Graphics g = bi.getGraphics();
        //3.设置图片的背影色
        CaptchaConfig2.setBackGround(g);
        //4.设置图片的边框
        CaptchaConfig2.setBorder(g);
        //5.设置图片画干扰线
        CaptchaConfig2.drawRandomLine(g);
        //6.设置图片上的随机数
        //根据客户端传递的 createTypeFlag标识生成验证码图片 createTypeFlag = ch /n1 /n /1
        String random = CaptchaConfig2.drawRandomNum((Graphics2D) g, "nl");
        System.out.println(random);

        /* ---------将随机数存在session中------------- */
        //8.设置响应头通知浏览器以图片的形式打开
        response.setContentType("image/jpeg");
        //9.设置响应头控制浏览器不要缓存
        response.setDateHeader("expries", -1);
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");
        //10.将图片写给浏览器
        try {
            ImageIO.write(bi, "jpg", response.getOutputStream());
        } catch (Exception e) {
        }
    }
}

接下来测试访问:http://localhost:8008/captcha2,如下:
【前后端分离】Springboot+Vue实现Kaptcha生成验证码、Graphics 2D随机验证码(两种样式) | 通过Vue显示到前端页面
至此,验证码的逻辑就实现了,接下来我们把它显示到前端页面上

三、前端 Vue项目

没有就自己创建一个,这里通过vue-cli搭建:

Login.vue

<template>
  <div class="formBg">
    <el-form :rules="rules" ref="loginForm" :model="loginForm" class="loginContainer">
      <h3 class="formTitle">系统登陆</h3>
      <el-form-item prop="username">
        <el-input type="text" auto-complete="false" v-model="loginForm.username" placeholder="请输入用户名"></el-input>
      </el-form-item>
      <el-form-item prop="password">
        <el-input type="password" auto-complete="false" v-model="loginForm.password" placeholder="请输入密码"></el-input>
      </el-form-item>
      <el-form-item prop="code" class="el-form-item__content">
        <el-input style="width: 250px" type="text" auto-complete="false" v-model="loginForm.code" placeholder="点击图片更换验证码"></el-input>
        <img :src="captchaUrl" @click="getCaptcha" title="点击更换">
      </el-form-item>
      <el-checkbox v-model="checked" class="formCheck">记住我</el-checkbox>
      <el-button type="primary" style="width: 100%" @click="submitForm">登录</el-button>
    </el-form>
  </div>
</template>

<script>
  import {getCodeImg, postRequest,getRequest} from '../utils/api'

export default {
  name: 'Login',
  data () {
    return {//'/captcha?time='+new Date(),
      captchaUrl: 'http://localhost:8008/captcha',
      captchaLoad: true,
      loginForm: {
        username: 'admin',
        password: '123',
        code: '',
        uuid: ''
      },
      checked: true,
      //整个页面加载
      loading: false,
      rules: {
        username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
        password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
        code: [{ required: true, message: '请输入验证码', trigger: 'blur' }]
      }
    }
  },
  mounted() {
    // 加载验证码
    this.getCaptcha();
  },
  methods: {
    // 获取验证码
    getCaptcha() {
      this.getRequest('/captcha2?time=' + new Date()).then(resp => {
        if (resp) {
          this.captchaUrl = resp.captcha2;
        }
      })
    },
    submitForm() {
     this.$refs.loginForm.validate((valid) => {
        if (valid) {
          postRequest('/login',this.loginForm).then(resp => {
            if (resp) {
              const tokenStr = resp.obj.tokenHead + resp.obj.token;
              window.sessionStorage.getItem('tokenStr',tokenStr);
              // 跳转首页
              this.$router.replace('/home');
            }
          })
        } else {
          this.$message.error('请输入正确的信息!')
          return false
        }
      })
    }
  }
}
</script>
<style scoped>
  .formBg{
    height: 900px;
    width: 100%;
    display: flex;
    justify-content: center;
    background: url('../assets/images/y1.jpg');
  }
  .loginContainer{
    border-radius: 15px;
    background-clip: padding-box;
    margin: 180px auto;
    width: 440px;
    height: 380px;
    padding: 15px 35px 15px 35px;
    background: #fff;
    border: 1px solid #eaeaea;
    box-shadow: 0 0 25px #cac6c6;
  }
  .formTitle{
    margin: 0px auto 40px auto;
  }
  .formCheck{
    margin: 5px 0px 15px 0px;
  }
  .el-form-item__content{
    display: flex;
    align-items: center;
  }
</style>

vue.config.js

跨域代理:

let proxyObj = {}

proxyObj['/'] = {
    // websocket
    ws: false,
    // 后端目标地址
    target:'http://localhost:8008',
    // 发送请求头host会被设置成target
    changeOrigin:true,
    // 不重写请求地址
    pathRewrite:{
        '^/':'/'
    }
}

module.export={
    devServer:{
        host:'localhost',
        port:8080,
        proxy:proxyObj
    }
}

四、源码下载

链接:https://pan.baidu.com/s/17KAtO5Ox_QfF_i70f09JCg
提取码:suej


喜欢 (0)