springboot怎么集成easy-captcha实现图像验证码显示和登录
1、easy-captcha简介
easy-captcha是生成图形验证码的Java类库,支持gif、中文、算术等类型,可用于Java Web、JavaSE等项目。
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); //生成验证码 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) { //获取验证码 String captcha = getCache(uuid); //效验成功 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); //删除验证码 if(captcha != null){ localCache.invalidate(key); } return captcha; } }
4、开发验证码接口
创建LoginController并提供生成验证码的方法
@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); //生成验证码 captchaService.create(response, uuid); } }
5、前端vue增加如何代码显示生成的验证码
<Motion :delay="200"> <el-form-item prop="verifyCode"> <el-input clearable v-model="ruleForm.verifyCode" placeholder="验证码" :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; } }); }; /** 使用公共函数,避免`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> <h3 class="outline-none">{{ title }}</h3> </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="验证码" :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>
编译运行后端,同事运行点前端,可以看到登录页面。
以上是springboot怎么集成easy-captcha实现图像验证码显示和登录的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

Jasypt介绍Jasypt是一个java库,它允许开发员以最少的努力为他/她的项目添加基本的加密功能,并且不需要对加密工作原理有深入的了解用于单向和双向加密的高安全性、基于标准的加密技术。加密密码,文本,数字,二进制文件...适合集成到基于Spring的应用程序中,开放API,用于任何JCE提供程序...添加如下依赖:com.github.ulisesbocchiojasypt-spring-boot-starter2.1.1Jasypt好处保护我们的系统安全,即使代码泄露,也可以保证数据源的

一、Redis实现分布式锁原理为什么需要分布式锁在聊分布式锁之前,有必要先解释一下,为什么需要分布式锁。与分布式锁相对就的是单机锁,我们在写多线程程序时,避免同时操作一个共享变量产生数据问题,通常会使用一把锁来互斥以保证共享变量的正确性,其使用范围是在同一个进程中。如果换做是多个进程,需要同时操作一个共享资源,如何互斥呢?现在的业务应用通常是微服务架构,这也意味着一个应用会部署多个进程,多个进程如果需要修改MySQL中的同一行记录,为了避免操作乱序导致脏数据,此时就需要引入分布式锁了。想要实现分

使用场景1、下单成功,30分钟未支付。支付超时,自动取消订单2、订单签收,签收后7天未进行评价。订单超时未评价,系统默认好评3、下单成功,商家5分钟未接单,订单取消4、配送超时,推送短信提醒……对于延时比较长的场景、实时性不高的场景,我们可以采用任务调度的方式定时轮询处理。如:xxl-job今天我们采

springboot读取文件,打成jar包后访问不到最新开发出现一种情况,springboot打成jar包后读取不到文件,原因是打包之后,文件的虚拟路径是无效的,只能通过流去读取。文件在resources下publicvoidtest(){Listnames=newArrayList();InputStreamReaderread=null;try{ClassPathResourceresource=newClassPathResource("name.txt");Input

在Springboot+Mybatis-plus不使用SQL语句进行多表添加操作我所遇到的问题准备工作在测试环境下模拟思维分解一下:创建出一个带有参数的BrandDTO对象模拟对后台传递参数我所遇到的问题我们都知道,在我们使用Mybatis-plus中进行多表操作是极其困难的,如果你不使用Mybatis-plus-join这一类的工具,你只能去配置对应的Mapper.xml文件,配置又臭又长的ResultMap,然后再去写对应的sql语句,这种方法虽然看上去很麻烦,但具有很高的灵活性,可以让我们

SpringBoot和SpringMVC都是Java开发中常用的框架,但它们之间有一些明显的差异。本文将探究这两个框架的特点和用途,并对它们的差异进行比较。首先,我们来了解一下SpringBoot。SpringBoot是由Pivotal团队开发的,它旨在简化基于Spring框架的应用程序的创建和部署。它提供了一种快速、轻量级的方式来构建独立的、可执行

1、自定义RedisTemplate1.1、RedisAPI默认序列化机制基于API的Redis缓存实现是使用RedisTemplate模板进行数据缓存操作的,这里打开RedisTemplate类,查看该类的源码信息publicclassRedisTemplateextendsRedisAccessorimplementsRedisOperations,BeanClassLoaderAware{//声明了key、value的各种序列化方式,初始值为空@NullableprivateRedisSe

在项目中,很多时候需要用到一些配置信息,这些信息在测试环境和生产环境下可能会有不同的配置,后面根据实际业务情况有可能还需要再做修改。我们不能将这些配置在代码中写死,最好是写到配置文件中,比如可以把这些信息写到application.yml文件中。那么,怎么在代码里获取或者使用这个地址呢?有2个方法。方法一:我们可以通过@Value注解的${key}即可获取配置文件(application.yml)中和key对应的value值,这个方法适用于微服务比较少的情形方法二:在实际项目中,遇到业务繁琐,逻
