image.png
前端
<template>
<el-form
:inline="true"
ref="ruleFormRef"
:model="ruleForm"
status-icon
:rules="rules"
label-width="120px"
class="demo-ruleForm">
<!-- 驗證碼輸入框 -->
<el-form-item label="驗證碼" prop="verifiCode">
<el-input v-model="ruleForm.verifiCode" type="text" autocomplete="off" />
</el-form-item>
<!-- 驗證碼圖片 -->
<el-form-item>
<el-image style="width: 130px; height: 33px" @click="getVerifiCode" :src="url" />
</el-form-item>
<!-- 按鈕 -->
<el-form-item>
<el-button type="primary" @click="submitForm(ruleFormRef)">提交</el-button>
<el-button @click="resetForm(ruleFormRef)">重置</el-button>
</el-form-item>
</el-form>
</template>
<script setup>
import { reactive, ref } from 'vue'
import { FormInstance } from 'element-plus'
import axios from 'axios'
//前端必須設置此項,后臺session才能獲取到值
axios.defaults.withCredentials = true;
const ruleFormRef = ref(FormInstance)
//記錄前端輸入的驗證碼變量
const ruleForm = reactive({
verifiCode: '',
})
//頁面加載時獲取圖片
const url = ref('http://localhost:8089/getVerifiCode')
//點擊圖片時獲取新驗證碼
const getVerifiCode = () => {
//讓參數隨機可切換驗證碼(重新生成,避免瀏覽器緩存)
url.value = 'http://localhost:8089/getVerifiCode?' + new Date().getTime();
}
const checkVerifiCode = (rule, value, callback) => {
if (!value) {
return callback(new Error('請輸入驗證碼'))
} else {
//驗證碼不為空時去后臺驗證
axios.post('http://localhost:8089/checkVerifiCode?verifiCode=' + ruleForm.verifiCode).then((res) => {
if (res.data == "error") {
return callback(new Error('驗證碼錯誤'))
}else{
callback()
}
})
}
}
//校驗
const rules = reactive({
verifiCode: [{ validator: checkVerifiCode }]
})
//提交
const submitForm = (formEl) => {
if (!formEl) return
formEl.validate((valid) => {
if (valid) {
alert('提交成功')
} else {
alert('提交失敗')
return false
}
})
}
//重置
const resetForm = (formEl) => {
if (!formEl) return
formEl.resetFields()
}
</script>
后端依賴pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
后端controller
package com.xx.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.OutputStream;
@Controller
public class CodeController {
@ResponseBody
@RequestMapping("/checkVerifiCode")
public String checkVerifiCode(String verifiCode, HttpServletRequest request ) {
//獲取session中的驗證碼字符串
String code = (String) request.getSession().getAttribute("verificode");
if(code.equals(verifiCode)) {
return "ok" ;
}else {
return "error" ;
}
}
//獲取驗證碼
@ResponseBody
@RequestMapping("/getVerifiCode")
public String getVerifiCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
final int width = 200; // 圖片寬度
final int height = 100; // 圖片高度
final String imgType = "jpeg"; // 指定圖片格式 (不是指MIME類型)
// 獲得 當前請求 對應的 會話對象(需要在輸出流之前創(chuàng)建)
HttpSession session = request.getSession();
// 獲得可以向客戶端返回圖片的輸出流
final OutputStream output = response.getOutputStream();
// 創(chuàng)建驗證碼圖片并返回圖片上的字符串
String code = GraphicHelper.create(width, height, imgType, output);
// 存儲到當前會話對象的屬性中
session.setAttribute("verificode", code);
//返回驗證碼(字符串)
return code;
}
}
驗證碼工具類
public class GraphicHelper {
/**
* 以字符串形式返回生成的驗證碼迈喉,同時輸出一個圖片
*
* @param width 圖片的寬度
* @param height 圖片的高度
* @param imgType 圖片的類型
* @param output 圖片的輸出流(圖片將輸出到這個流中)
* @return 返回所生成的驗證碼(字符串)
*/
public static String create(final int width, final int height, final String imgType, OutputStream output) {
StringBuffer sb = new StringBuffer();
Random random = new Random();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics graphic = image.getGraphics();
graphic.setColor(Color.getColor("F8F8F8"));
graphic.fillRect(0, 0, width, height);
Color[] colors = new Color[] { Color.BLUE, Color.GRAY, Color.GREEN, Color.RED, Color.BLACK, Color.ORANGE,
Color.CYAN };
// 在 "畫板"上生成干擾線條 ( 50 是線條個數)
for (int i = 0; i < 50; i++) {
graphic.setColor(colors[random.nextInt(colors.length)]);
final int x = random.nextInt(width);
final int y = random.nextInt(height);
final int w = random.nextInt(20);
final int h = random.nextInt(20);
final int signA = random.nextBoolean() ? 1 : -1;
final int signB = random.nextBoolean() ? 1 : -1;
graphic.drawLine(x, y, x + w * signA, y + h * signB);
}
// 在 "畫板"上繪制字母
graphic.setFont(new Font("Comic Sans MS", Font.BOLD, 50));
for (int i = 0; i < 6; i++) {
final int temp = random.nextInt(26) + 97;
String s = String.valueOf((char) temp);
sb.append(s);
graphic.setColor(colors[random.nextInt(colors.length)]);
graphic.drawString(s, i * (width / 6), height - (height / 3));
}
graphic.dispose();
try {
ImageIO.write(image, imgType, output);
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
}
注意:后端配置類設置:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("*")
.allowedHeaders("*")
.maxAge(36000);
}
}
或者后端濾過器設置
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
response.setHeader("Access-Control-Allow-Credentials","true"); //這個很重要
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); //這塊不能直接寫 "*"
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH");
前端axios應設置:
axios.defaults.withCredentials=true;