springboot?集成easy-captcha實(shí)現(xiàn)圖像驗(yàn)證碼顯示和登錄
1、easy-captcha簡介
easy-captcha是生成圖形驗(yàn)證碼的Java類庫,支持gif、中文、算術(shù)等類型,可用于Java Web、JavaSE等項(xiàng)目。參考地址:[https://github.com/whvcse/EasyCaptcha]

2、添加依賴
<guava.version>20.0</guava.version>
<captcha.version>1.6.2</captcha.version>
<dependency>
? ? <groupId>com.google.guava</groupId>
? ? <artifactId>guava</artifactId>
? ? <version>${guava.version}</version>
</dependency>
<dependency>
? ? <groupId>com.github.whvcse</groupId>
? ? <artifactId>easy-captcha</artifactId>
? ? <version>${captcha.version}</version>
</dependency>3、編寫service層代碼
@Service
public class CaptchaServiceImpl implements CaptchaService {
? ? /**
? ? ?* Local Cache ?5分鐘過期
? ? ?*/
? ? Cache<String, String> localCache = CacheBuilder.newBuilder().maximumSize(1000).expireAfterAccess(5, TimeUnit.MINUTES).build();
? ? @Override
? ? public void create(HttpServletResponse response, String uuid) throws IOException {
? ? ? ? response.setContentType("image/gif");
? ? ? ? response.setHeader("Pragma", "No-cache");
? ? ? ? response.setHeader("Cache-Control", "no-cache");
? ? ? ? response.setDateHeader("Expires", 0);
? ? ? ? //生成驗(yàn)證碼
? ? ? ? SpecCaptcha captcha = new SpecCaptcha(150, 40);
? ? ? ? captcha.setLen(5);
? ? ? ? captcha.setCharType(Captcha.TYPE_DEFAULT);
? ? ? ? captcha.out(response.getOutputStream());
? ? ? ? //保存到緩存
? ? ? ? setCache(uuid, captcha.text());
? ? }
? ? @Override
? ? public boolean validate(String uuid, String code) {
? ? ? ? //獲取驗(yàn)證碼
? ? ? ? String captcha = getCache(uuid);
? ? ? ? //效驗(yàn)成功
? ? ? ? if(code.equalsIgnoreCase(captcha)){
? ? ? ? ? ? return true;
? ? ? ? }
? ? ? ? return false;
? ? }
? ? private void setCache(String key, String value){
? ? ? ? localCache.put(key, value);
? ? }
? ? private String getCache(String key){
? ? ? ? String captcha = localCache.getIfPresent(key);
? ? ? ? //刪除驗(yàn)證碼
? ? ? ? if(captcha != null){
? ? ? ? ? ? localCache.invalidate(key);
? ? ? ? }
? ? ? ? return captcha;
? ? }
}4、開發(fā)驗(yàn)證碼接口
創(chuàng)建LoginController并提供生成驗(yàn)證碼的方法
@Controller
@AllArgsConstructor
public class CaptchaController {
? ? private CaptchaService captchaService;
? ? @GetMapping("/captcha")
? ? public void captcha(HttpServletResponse response, String uuid)throws IOException {
? ? ? ? //uuid不能為空
? ? ? ? AssertUtils.isBlank(uuid, ErrorCode.IDENTIFIER_NOT_NULL);
? ? ? ? //生成驗(yàn)證碼
? ? ? ? captchaService.create(response, uuid);
? ? }
}5、前端vue增加如何代碼顯示生成的驗(yàn)證碼
<Motion :delay="200">
<el-form-item prop="verifyCode">
<el-input
clearable
v-model="ruleForm.verifyCode"
placeholder="驗(yàn)證碼"
:prefix-icon="useRenderIcon(Line)"
>
<template v-slot:append>
<img
style="
vertical-align: middle;
height: 40px;
width: 100px;
cursor: pointer;
"
:src="captchaUrl"
@click="onRefreshCode"
alt=""
/>
</template>
</el-input>
</el-form-item>
</Motion>完整的登錄頁代碼如下
<script setup lang="ts">
import Motion from "./utils/motion";
import { useRouter } from "vue-router";
import { message } from "@/utils/message";
import { loginRules } from "./utils/rule";
import { useNav } from "@/layout/hooks/useNav";
import type { FormInstance } from "element-plus";
import { useLayout } from "@/layout/hooks/useLayout";
import { useUserStoreHook } from "@/store/modules/user";
import { bg, avatar, illustration } from "./utils/static";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { ref, reactive, toRaw, onMounted, onBeforeUnmount } from "vue";
import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
import { initRouter } from "@/router/utils";
import { getUuid } from "@/utils/utils";
import dayIcon from "@/assets/svg/day.svg?component";
import darkIcon from "@/assets/svg/dark.svg?component";
import Lock from "@iconify-icons/ri/lock-fill";
import User from "@iconify-icons/ri/user-3-fill";
import Line from "@iconify-icons/ri/shield-keyhole-line";
import { getConfig } from "@/config";
defineOptions({
? name: "Login"
});
const router = useRouter();
const loading = ref(false);
const ruleFormRef = ref<FormInstance>();
const captchaUrl = ref("");
const { Api } = getConfig();
const { initStorage } = useLayout();
initStorage();
const { dataTheme, dataThemeChange } = useDataThemeChange();
dataThemeChange();
const { title } = useNav();
const ruleForm = reactive({
? username: "admin",
? password: "admin123",
? verifyCode: "",
? uuid: ""
});
const onLogin = async (formEl: FormInstance | undefined) => {
? loading.value = true;
? if (!formEl) return;
? await formEl.validate((valid, fields) => {
? ? if (valid) {
? ? ? useUserStoreHook()
? ? ? ? .loginByUsername({ username: ruleForm.username, password: "admin123" })
? ? ? ? .then(res => {
? ? ? ? ? if (res.code == 200) {
? ? ? ? ? ? // 獲取后端路由
? ? ? ? ? ? initRouter().then(() => {
? ? ? ? ? ? ? router.push("/");
? ? ? ? ? ? ? message("登錄成功", { type: "success" });
? ? ? ? ? ? });
? ? ? ? ? }
? ? ? ? });
? ? } else {
? ? ? loading.value = false;
? ? ? return fields;
? ? }
? });
};
/** 使用公共函數(shù),避免`removeEventListener`失效 */
function onkeypress({ code }: KeyboardEvent) {
? if (code === "Enter") {
? ? onLogin(ruleFormRef.value);
? }
}
function getCaptchaUrl() {
? ruleForm.uuid = getUuid();
? captchaUrl.value = `${Api}/captcha?uuid=${ruleForm.uuid}`;
}
function onRefreshCode() {
? getCaptchaUrl();
}
onMounted(() => {
? window.document.addEventListener("keypress", onkeypress);
? getCaptchaUrl();
});
onBeforeUnmount(() => {
? window.document.removeEventListener("keypress", onkeypress);
});
</script>
<template>
? <div class="select-none">
? ? <img :src="bg" class="wave" />
? ? <div class="flex-c absolute right-5 top-3">
? ? ? <!-- 主題 -->
? ? ? <el-switch
? ? ? ? v-model="dataTheme"
? ? ? ? inline-prompt
? ? ? ? :active-icon="dayIcon"
? ? ? ? :inactive-icon="darkIcon"
? ? ? ? @change="dataThemeChange"
? ? ? />
? ? </div>
? ? <div class="login-container">
? ? ? <div class="img">
? ? ? ? <component :is="toRaw(illustration)" />
? ? ? </div>
? ? ? <div class="login-box">
? ? ? ? <div class="login-form">
? ? ? ? ? <avatar class="avatar" />
? ? ? ? ? <Motion>
? ? ? ? ? ? <h2 class="outline-none">{{ title }}</h2>
? ? ? ? ? </Motion>
? ? ? ? ? <el-form
? ? ? ? ? ? ref="ruleFormRef"
? ? ? ? ? ? :model="ruleForm"
? ? ? ? ? ? :rules="loginRules"
? ? ? ? ? ? size="large"
? ? ? ? ? >
? ? ? ? ? ? <Motion :delay="100">
? ? ? ? ? ? ? <el-form-item
? ? ? ? ? ? ? ? :rules="[
? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? required: true,
? ? ? ? ? ? ? ? ? ? message: '請輸入賬號',
? ? ? ? ? ? ? ? ? ? trigger: 'blur'
? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ]"
? ? ? ? ? ? ? ? prop="username"
? ? ? ? ? ? ? >
? ? ? ? ? ? ? ? <el-input
? ? ? ? ? ? ? ? ? clearable
? ? ? ? ? ? ? ? ? v-model="ruleForm.username"
? ? ? ? ? ? ? ? ? placeholder="賬號"
? ? ? ? ? ? ? ? ? :prefix-icon="useRenderIcon(User)"
? ? ? ? ? ? ? ? />
? ? ? ? ? ? ? </el-form-item>
? ? ? ? ? ? </Motion>
? ? ? ? ? ? <Motion :delay="150">
? ? ? ? ? ? ? <el-form-item prop="password">
? ? ? ? ? ? ? ? <el-input
? ? ? ? ? ? ? ? ? clearable
? ? ? ? ? ? ? ? ? show-password
? ? ? ? ? ? ? ? ? v-model="ruleForm.password"
? ? ? ? ? ? ? ? ? placeholder="密碼"
? ? ? ? ? ? ? ? ? :prefix-icon="useRenderIcon(Lock)"
? ? ? ? ? ? ? ? />
? ? ? ? ? ? ? </el-form-item>
? ? ? ? ? ? </Motion>
? ? ? ? ? ? <Motion :delay="200">
? ? ? ? ? ? ? <el-form-item prop="verifyCode">
? ? ? ? ? ? ? ? <el-input
? ? ? ? ? ? ? ? ? clearable
? ? ? ? ? ? ? ? ? v-model="ruleForm.verifyCode"
? ? ? ? ? ? ? ? ? placeholder="驗(yàn)證碼"
? ? ? ? ? ? ? ? ? :prefix-icon="useRenderIcon(Line)"
? ? ? ? ? ? ? ? >
? ? ? ? ? ? ? ? ? <template v-slot:append>
? ? ? ? ? ? ? ? ? ? <img
? ? ? ? ? ? ? ? ? ? ? style="
? ? ? ? ? ? ? ? ? ? ? ? vertical-align: middle;
? ? ? ? ? ? ? ? ? ? ? ? height: 40px;
? ? ? ? ? ? ? ? ? ? ? ? width: 100px;
? ? ? ? ? ? ? ? ? ? ? ? cursor: pointer;
? ? ? ? ? ? ? ? ? ? ? "
? ? ? ? ? ? ? ? ? ? ? :src="captchaUrl"
? ? ? ? ? ? ? ? ? ? ? @click="onRefreshCode"
? ? ? ? ? ? ? ? ? ? ? alt=""
? ? ? ? ? ? ? ? ? ? />
? ? ? ? ? ? ? ? ? </template>
? ? ? ? ? ? ? ? </el-input>
? ? ? ? ? ? ? </el-form-item>
? ? ? ? ? ? </Motion>
? ? ? ? ? ? <Motion :delay="250">
? ? ? ? ? ? ? <el-button
? ? ? ? ? ? ? ? class="w-full mt-4"
? ? ? ? ? ? ? ? size="default"
? ? ? ? ? ? ? ? type="primary"
? ? ? ? ? ? ? ? :loading="loading"
? ? ? ? ? ? ? ? @click="onLogin(ruleFormRef)"
? ? ? ? ? ? ? >
? ? ? ? ? ? ? ? 登錄
? ? ? ? ? ? ? </el-button>
? ? ? ? ? ? </Motion>
? ? ? ? ? </el-form>
? ? ? ? </div>
? ? ? </div>
? ? </div>
? </div>
</template>
<style scoped>
@import url("@/style/login.css");
</style>
<style lang="scss" scoped>
:deep(.el-input-group__append, .el-input-group__prepend) {
? padding: 0;
}
</style>編譯運(yùn)行后端,同事運(yùn)行點(diǎn)前端,可以看到登錄頁面。
到此這篇關(guān)于springboot 集成easy-captcha實(shí)現(xiàn)圖像驗(yàn)證碼顯示和登錄的文章就介紹到這了,更多相關(guān)springboot easy-captcha驗(yàn)證碼內(nèi)容請搜索腳本之家以前
相關(guān)文章
Spring Boot security 默認(rèn)攔截靜態(tài)資源的解決方法
這篇文章主要介紹了Spring Boot security 默認(rèn)攔截靜態(tài)資源,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03
SpringBoot?項(xiàng)目的創(chuàng)建與啟動步驟詳解
這篇文章主要介紹了SpringBoot?項(xiàng)目的創(chuàng)建與啟動,本文分步驟給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03
優(yōu)化Java虛擬機(jī)總結(jié)(jvm調(diào)優(yōu))
這篇文章主要介紹了優(yōu)化Java虛擬機(jī)總結(jié)(jvm調(diào)優(yōu)),具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
spring boot+spring cache實(shí)現(xiàn)兩級緩存(redis+caffeine)
這篇文章主要介紹了spring boot+spring cache實(shí)現(xiàn)兩級緩存(redis+caffeine),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-02-02
Java實(shí)現(xiàn)FTP批量大文件上傳下載篇1
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)FTP批量大文件上傳下載的基礎(chǔ)篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08
idea如何debug看springsecurity的過濾器順序
這篇文章主要介紹了idea如何debug看springsecurity的過濾器順序,文中通過圖文結(jié)合的方式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-04-04
解決RestTemplate加@Autowired注入不了的問題
這篇文章主要介紹了解決RestTemplate加@Autowired注入不了的問題,具有很好的參考價(jià)值,希望對大家有所幫助。2021-08-08
Spring如何通過注解引入外部資源(PropertySource?Value)
這篇文章主要為大家介紹了Spring通過注解@PropertySource和@Value引入外部資源的方法實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07

