当前位置: 首页 > news >正文

SpringBoot+Vue实现图片滑块和文字点击验证码

一、背景

1.1 概述

传统字符型验证码展示-填写字符-比对答案的流程,目前已可被机器暴力破解,应用程序容易被自动化脚本和机器人攻击。
在这里插入图片描述
摒弃传统字符型验证码,采用行为验证码采用嵌入式集成方式,接入方便,安全,高效。验证码展示-采集用户行为-分析用户行为流程,用户只需要产生指定的行为轨迹,不需要键盘手动输入,极大优化了传统验证码用户体验不佳的问题;同时,快速、准确的返回人机判定结果。
在这里插入图片描述

1.2 应用场景

  • 网站登录:保护用户账号免受非法登录尝试
  • 在线表单提交:避免垃圾邮件和恶意数据填充
  • 论坛或社区:防止机器人自动发帖和灌水
  • 支付验证:保障交易安全,防止欺诈行为

二、anji-plus

AJ-Captcha行为验证码,包含滑动拼图、文字点选两种方式,UI支持弹出和嵌入两种方式。后端提供Java实现,前端提供了php、angular、html、vue、uni-app、flutter、android、ios等代码示例。

代码开源地址:https://gitee.com/anji-plus/captcha
文档地址:https://ajcaptcha.beliefteam.cn/captcha-doc/

2.1 功能简介

功能描述
验证码类型滑动拼图 blockPuzzle / 文字点选 clickWord
验证用户拖动/点击一次验证码拼图即视为一次“验证”,不论拼图/点击是否正确
二次校验验证数据随表单提交到后台后,后台需要调用captchaService.verification做二次校验。目的是核实验证数据的有效性。

2.2 交互流程

① 用户访问应用页面,请求显示行为验证码
② 用户按照提示要求完成验证码拼图/点击
③ 用户提交表单,前端将第二步的输出一同提交到后台
④ 验证数据随表单提交到后台后,后台需要调用captchaService.verification做二次校验。
⑤ 第4步返回校验通过/失败到产品应用后端,再返回到前端。如下图所示。
在这里插入图片描述

三、代码实现

3.1 引入依赖

<dependency><groupId>com.anji-plus</groupId><artifactId>spring-boot-starter-captcha</artifactId><version>1.3.0</version>
</dependency>

3.2 配置

# 验证码配置
aj:captcha:########## 重点关注 ########### 验证码类型:default,blockPuzzle,clickWordtype: default# 底图路径,支持全路径、项目资源路径jigsaw: classpath:images/jigsaw# 滑动图路径,支持全路径、项目资源路径pic-click: classpath:images/pic-click# 缓存类型:local,redis,othercache-type: redis# local缓存的阈值,达到这个值,清除缓存cache-number: 1000# local定时清除过期缓存(单位秒),设置为0代表不执行timing-clear: 180# 滑块验证码的偏移量slip-offset: 5# 滑块验证码的加密坐标aes-status: true# 滑块验证码的滑块干扰项interference-options: 2# 文字验证码的文字数量【暂不可用】click-word-count: 4# 文字验证码的文字字体font-type: WenQuanZhengHei.ttf# 文字验证码的字体样式font-style: 1# 文字验证码的字体大小font-size: 25# 水印文字water-mark: 强哥软件# 水印文字字体water-font: WenQuanZhengHei.ttf########## 接口相关配置 ########### 历史数据清理是否开启history-data-clear-enable: false# 接口请求次数一分钟限制是否开启req-frequency-limit-enable: true# 验证失败5次,get接口锁定req-get-lock-limit: 5# 验证失败后,锁定时间间隔,sreq-get-lock-seconds: 360# get接口一分钟内请求数限制req-get-minute-limit: 30# check接口一分钟内请求数限制req-check-minute-limit: 60# verify接口一分钟内请求数限制req-verify-minute-limit: 60

3.3 自定义验证码存储

使用redis存储验证码

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

实现CaptchaCacheService 接口

package com.qiangesoft.captcha.cache;import com.anji.captcha.service.CaptchaCacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;import java.util.concurrent.TimeUnit;/*** redis缓存验证码** @author qiangesoft* @date 2024-05-10*/
public class CaptchaCacheServiceRedisImpl implements CaptchaCacheService {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Overridepublic void set(String key, String value, long expiresInSeconds) {stringRedisTemplate.opsForValue().set(key, value, expiresInSeconds, TimeUnit.SECONDS);}@Overridepublic boolean exists(String key) {return stringRedisTemplate.hasKey(key);}@Overridepublic void delete(String key) {stringRedisTemplate.delete(key);}@Overridepublic String get(String key) {return stringRedisTemplate.opsForValue().get(key);}@Overridepublic Long increment(String key, long val) {return stringRedisTemplate.opsForValue().increment(key, val);}@Overridepublic String type() {return "redis";}
}

配置
在resources目录新建META-INF.services文件夹,新建文件名为com.anji.captcha.service.CaptchaCacheService,内容为com.qiangesoft.captcha.cache.CaptchaCacheServiceRedisImpl

3.4 登录验证接口

package com.qiangesoft.captcha.controller;import com.anji.captcha.model.common.ResponseModel;
import com.anji.captcha.model.vo.CaptchaVO;
import com.anji.captcha.service.CaptchaService;
import com.qiangesoft.captcha.pojo.LoginDTO;
import com.qiangesoft.captcha.pojo.ResultVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;/*** 登录接口** @author qiangesoft* @date 2024-05-10*/
@Controller
public class LoginController {@Autowiredprivate CaptchaService captchaService;@GetMapping("/")public String index() {return "login";}@ResponseBody@PostMapping("/login")public ResultVO login(@RequestBody LoginDTO loginDTO) {// 登录二次校验CaptchaVO captchaVO = new CaptchaVO();captchaVO.setCaptchaVerification(loginDTO.getCaptcha());ResponseModel response = captchaService.verification(captchaVO);if (!response.isSuccess()) {throw new RuntimeException("图片验证码校验失败");}// todo 认证逻辑return ResultVO.ok();}}

3.5 vue方式

主要代码如下:

<template><div class="login-bg"><el-form style="width: 500px;height: 40px;margin: auto"><el-form-item label="账号" prop="username"><el-input v-model="username" placeholder="账号"></el-input></el-form-item><el-form-item label="密码" prop="password"><el-input v-model="password" placeholder="密码"></el-input></el-form-item><el-form-item><el-button type="primary" @click="checkParam">登录</el-button></el-form-item></el-form><Verifyref="verify"captcha-type="blockPuzzle":img-size="{width:'400px',height:'200px'}"@success="login"/><!--    <Verify--><!--      ref="verify"--><!--      captcha-type="clickWord"--><!--      :img-size="{width:'400px',height:'200px'}"--><!--      @success="login"--><!--    />--></div>
</template><script>
import Verify from './../components/verifition/Verify'
import { Message } from 'element-ui'
import { login } from '@/api'export default {components: {Verify},data () {return {username: 'admin',password: '123456'}},beforeDestroy () {document.removeEventListener('keyup', this.handlerKeyup)},created () {document.addEventListener('keyup', this.handlerKeyup)},methods: {handlerKeyup (e) {const keycode = document.all ? event.keyCode : e.whichif (keycode === 13) {this.checkParam()}},checkParam () {if (!this.username || !this.password) {Message.error('请先输入账号密码')}this.$refs.verify.show()},login (params) {login({username: this.username,password: this.password,captcha: params.captchaVerification}).then(res => {const code = res.codeif (code === 200) {Message.success('登录成功')this.$router.push('/index')} else {Message.error(res.message)}})}}
}
</script>

3.6 html方式

引入依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

配置静态资源

package com.qiangesoft.captcha.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** 全局异常处理** @author qiangesoft* @date 2024-03-19*/
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");}
}

html代码

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta name="viewport"content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/><title>verify插件demo</title><link rel="stylesheet" type="text/css" th:href="@{/static/css/verify.css}"><script>if (!window.Promise) {document.writeln('<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/es6-promise.min.js"><' + '/' + 'script>');}</script><style>.btn {border: none;outline: none;width: 110px;height: 40px;line-height: 40px;text-align: center;cursor: pointer;background-color: #409EFF;color: #fff;font-size: 16px;}</style>
</head><body>
<div class="box"><h3>用户登录</h3>账号:<input type="text" id="username" placeholder="账号" value="admin"/> <br/><br/>密码:<input type="password" id="password" placeholder="密码" value="123456"/><br/><br/><button class="btn" id='btn'>滑块登录</button><button class="btn" id='btn1'>文字登录</button><div id="mpanel" style="margin-top:50px;"></div><div id="mpanel1" style="margin-top:50px;"></div>
</div><script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/jquery/1.9.1/jquery.js"></script>
<script th:src="@{/static/js/crypto-js.js}"></script>
<script th:src="@{/static/js/ase.js}"></script>
<script th:src="@{/static/js/verify.js}"></script><script>// 滑块$('#mpanel').slideVerify({baseUrl: 'http://localhost:8028',mode: 'pop',containerId: 'btn',imgSize: {width: '400px',height: '200px',},barSize: {width: '400px',height: '40px',},// 检验参数合法性的函数,mode ="pop"有效beforeCheck: function () {// todo 可进行参数校验return true},// 加载完毕的回调ready: function () {},// 成功的回调success: function (params) {const username = $("#username").val();const password = $('#password').val();$.ajax({url: '/login',type: 'post',contentType: 'application/json',dataType: 'json',data: JSON.stringify({"username": username,"password": password,"captcha": params.captchaVerification}),success: function (res) {if (res.code === 200) {alert("登录成功");} else {alert(res.message);}},error: function (e) {alert('请求失败')}})},// 失败的回调error: function () {}});// 文字点击$('#mpanel1').pointsVerify({baseUrl: 'http://localhost:8028',containerId: 'btn1',mode: 'pop',imgSize: {width: '400px',height: '200px',},beforeCheck: function () {return true},ready: function () {},success: function (params) {const username = $("#username").val();const password = $('#password').val();$.ajax({url: '/login',type: 'post',contentType: 'application/json',dataType: 'json',data: JSON.stringify({"username": username,"password": password,"captcha": params.captchaVerification}),success: function (res) {if (res.code === 200) {alert("登录成功");} else {alert(res.message);}},error: function (e) {alert('请求失败')}})},error: function () {}});
</script>
</body></html>

四、测试

4.1 接口调用

依赖中默认接口

功能描述请求方式
获取验证码/captcha/getpost
核对验证码/captcha/checkpost

接口调用流程
在这里插入图片描述

获取验证码接口:/captcha/get
请求参数

{"captchaType": "blockPuzzle",  // 验证码类型 clickWord"clientUid": "唯一标识"  // 客户端UI组件id,组件初始化时设置一次,UUID(非必传参数)
}

响应数据

{"repCode": "0000","repData": {"originalImageBase64": "底图base64","point": {    // 默认不返回的,校验的就是该坐标信息,允许误差范围"x": 205,"y": 5},"jigsawImageBase64": "滑块图base64","token": "71dd26999e314f9abb0c635336976635", // 一次校验唯一标识"secretKey": "16位随机字符串", // aes秘钥,开关控制,前端根据此值决定是否加密"result": false,"opAdmin": false},"success": true,"error": false
}

核对验证码接口:/captcha/check
请求参数

{"captchaType": "blockPuzzle","pointJson": "QxIVdlJoWUi04iM+65hTow==",  // aes加密坐标信息"token": "71dd26999e314f9abb0c635336976635"  // get请求返回的token
}

响应数据

{"repCode": "0000","repData": {"captchaType": "blockPuzzle","token": "71dd26999e314f9abb0c635336976635","result": true,"opAdmin": false},"success": true,"error": false
}

4.2 vue

在这里插入图片描述
在这里插入图片描述

4.3 html

在这里插入图片描述
在这里插入图片描述

五、源码地址

码云:https://gitee.com/qiangesoft/boot-business/tree/master/boot-business-captcha

方便的话博客点个小心心,码云仓库点个star呗!!!

相关文章:

SpringBoot+Vue实现图片滑块和文字点击验证码

一、背景 1.1 概述 传统字符型验证码展示-填写字符-比对答案的流程&#xff0c;目前已可被机器暴力破解&#xff0c;应用程序容易被自动化脚本和机器人攻击。 摒弃传统字符型验证码&#xff0c;采用行为验证码采用嵌入式集成方式&#xff0c;接入方便&#xff0c;安全&#…...

每日复盘-20240515

仅用于记录当天的市场情况&#xff0c;用于统计交易策略的适用情况&#xff0c;以便程序回测 短线核心&#xff1a;不参与任何级别的调整&#xff0c;采用龙空龙模式 一支股票 10%的时候可以操作&#xff0c; 90%的时间适合空仓等待 国联证券 (1)|[9:25]|[133765万]|31.12 一…...

【Android】Apk图标的提取、相同目录下相同包名提取的不同图标apk但是提取结果相同的bug解决

一般安卓提取apk图标我们有两种常用方法&#xff1a; 1、如果已经获取到 ApplicationInfo 对象&#xff08;假设名为 appInfo&#xff09;&#xff0c;那么我们获取方法为&#xff1a; appInfo.loadIcon(packageManager)// 返回一个 Drawable 对象2、 如果还没获取到 Applica…...

高校普法|基于SSM+vue的高校普法系统的设计与实现(源码+数据库+文档)

高校普法系统 目录 基于SSM&#xff0b;vue的高校普法系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2管理员功能模块 3律师功能模块 4学生功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获…...

pytest教程-47-钩子函数-pytest_sessionfinish

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 上一小节我们学习了pytest_sessionstart钩子函数的使用方法&#xff0c;本小节我们讲解一下pytest_sessionfinish钩子函数的使用方法。 pytest_sessionfinish 钩子函数在 Pytest 测试会话结束时调用&#xff0c;…...

如何使用Python下载哔哩哔哩(Bilibili)视频字幕

在本文中&#xff0c;我将向大家展示如何使用Python下载哔哩哔哩&#xff08;Bilibili&#xff09;视频的字幕。通过这个方法&#xff0c;你可以轻松地获取你喜欢的视频的字幕文件&#xff0c;方便学习和交流。 准备工作 在开始之前&#xff0c;我们需要安装一些必要的库&…...

IP代理网络协议介绍

在IP代理页面上&#xff0c;存在HTTP/HTTPS/Socks5三种协议。它们都是客户端与服务器之间交互的协议。 HTTP HTTP又称之为超文本传输协议&#xff0c;在因特网使用范围广泛。它是一种请求/响应模型&#xff0c;客户端向服务器发送请求&#xff0c;服务器解析请求后对客户端作出…...

渗透相关面试+流量分析

文章目录 简单自我介绍上一个工作的主要内容Hvv的分组和流程你在hvv/攻防演练中取得了哪些成绩&#xff1f; 二、渗透相关面试题基础端口号以及入侵方式OSI七层协议响应状态码都有哪些&#xff1f;**WAF和IPS的区别**盲注是什么&#xff1f;java内存马类型**内存马有几种类型**…...

Shell之高效文本处理命令

目录 一、排序命令—sort 基本语法 常用选项 二、去重命令—uniq 基本语法 常用选项 三、替换命令—tr 基本语法&#xff1a; 常用选项 四、裁剪命令—cut 基本语法&#xff1a; 常用选项 字符串分片 五、拆分命令—split 基本语法&#xff1a; 六、 文件…...

u3d的ab文件注意事项

//----------------LoadAllAB.cs--------------------- using System.Collections;using UnityEngine;namespace System.IO{public class LoadAllAB : MonoBehaviour{ //读取本地string path "Assets/Actors/lznh/ab/animation/t_bl/";// Use this for initiali…...

Go微服务开源框架kratos的依赖注入关系总结

该文章为学习开源微服务框架kratos的学习笔记&#xff01;官方文档见&#xff1a;简介 | Kratos Kratos 一套轻量级 Go 微服务框架&#xff0c;包含大量微服务相关框架及工具。 一、Kratos 项目结构简介 通过 Kratos 工具生成的 Go工程化项目模板如下&#xff1a; applicati…...

Linux 第三十二章

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…...

手机号码的正则表达式

手机号码的正则表达式会根据不同的国家/地区有所不同&#xff0c;因为每个国家/地区都有自己特定的手机号码格式。但是&#xff0c;我可以为你提供一个通用的正则表达式模板&#xff0c;并给出一些具体国家/地区的例子。 通用模板 一个基本的手机号码正则表达式模板可能如下所…...

机器学习入门介绍

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 目录 三大方向机器学习产生的原因机器如何学习…...

一文说通用户故事点数是什么?

一文说通用户故事点数是什么&#xff1f; 第26期&#xff1a;一文说通用户故事点数是什么&#xff1f; 用户故事点数是一种采用相对估算法进行估算的一种工具&#xff0c;一般采用斐波那契数列表征用户故事里说的大小&#xff0c;采用0 1 2 3 5 8 13这样的一些数字来表征用户…...

GAME101-Lecture07学习

前言 今天主要讲shading&#xff08;着色&#xff09;。在讲着色前&#xff0c;要先讲图形中三角形出现遮挡问题的方法&#xff08;深度缓存或缓冲&#xff09;。 先采样再模糊错误&#xff1a;对信号的频谱进行翻译&#xff08;在这期间会有频谱的混叠&#xff09;&#xff…...

【一步一步了解Java系列】:了解Java与C语言的运算符的“大同小异”

看到这句话的时候证明&#xff1a;此刻你我都在努力~ 加油陌生人~ 个人主页&#xff1a; Gu Gu Study ​​ 专栏&#xff1a;一步一步了解Java 喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努…...

ICSE docker related research

ICSE 2024 Empirical Study of the Docker Smells Impact on the Image Size Docker 气味对镜像大小影响的实证研究 Docker 是一种广泛采用的打包和部署应用程序的工具&#xff0c;它利用 Dockerfile 来构建镜像。然而&#xff0c;创建最佳的 Dockerfile 可能具有挑战性&…...

【C++】学习笔记——多态_1

文章目录 十二、继承8. 继承和组合 十三、多态1. 多态的概念2. 多态的定义和实现虚函数重写的两个特殊情况override 和 final 3. 多态的原理1. 虚函数表 未完待续 十二、继承 8. 继承和组合 我们已经知道了什么是继承&#xff0c;那组合又是什么&#xff1f;下面这种情况就是…...

C++map容器关联式容器

Cmap 1. 关联式容器 vector、list、deque、forward_list(C11)等STL容器&#xff0c;其底层为线性序列的数据结构&#xff0c;里面存储的是元素本身&#xff0c;这样的容器被统称为序列式容器。而map、set是一种关联式容器&#xff0c;关联式容器也是用来存储数据的&#xff0…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

elementUI点击浏览table所选行数据查看文档

项目场景&#xff1a; table按照要求特定的数据变成按钮可以点击 解决方案&#xff1a; <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...

Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解

文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一&#xff1a;HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二&#xff1a;Floyd 快慢指针法&#xff08;…...