「youlai-boot」进阶篇:Java & Spring Boot 企业级权限管理系统实战指南(全功能详解)

「youlai-boot」进阶篇:Java & Spring Boot 企业级权限管理系统实战指南(全功能详解)
🚀 作者主页: 有来技术
🔥 开源项目: youlai-mall vue3-element-adminyoulai-bootvue-uniapp-template
🌺 仓库主页: GitCodeGiteeGithub
💖 欢迎点赞 👍 收藏 ⭐评论 📝 如有错误敬请纠正!

目录

前言

本文档旨在为开发者提供全面的 youlai-boot 项目使用指南,涵盖项目介绍、快速启动、环境配置、功能操作和扩展实现等多方面内容。youlai-boot 是一款基于 Java 17 和 Spring Boot 3 的企业级权限管理系统,集成了多种主流技术栈,适用于复杂的企业业务场景。通过本手册,开发者可以快速上手项目,并深入掌握各模块的实现细节和最佳实践。

项目介绍

youlai-boot 是一个企业级 RBAC 权限管理系统,采用 Java 17Spring Boot 3Spring Security 6MyBatis-PlusRedisXXL-Job 等主流后端技术栈构建,作为 vue3-element-admin(Web 端)和 vue-uniapp-template(移动端)的后端服务,支持用户、角色、权限、部门、字典、配置等多种功能,满足企业级权限管理需求。

项目特色

  • 完善的权限管理:支持精细化的用户、角色、菜单和数据权限控制。
  • 高效的开发工具:内置前后端代码生成器,快速搭建业务模块。
  • 实时通信支持:基于 WebSocket 实现在线用户统计与消息推送。
  • 系统安全机制:提供防重提交、分布式锁等保障数据安全的能力。
  • 灵活的定时任务:集成 XXL-Job,支持复杂的任务调度场景。

启动项目

以下是快速启动 youlai-boot 项目 的完整步骤,从克隆项目到运行服务,帮助您快速上手。

克隆代码

打开 IntelliJ IDEA,依次点击:File → New → Project from Version Control

在弹出的窗口中输入项目地址:https://gitee.com/youlaiorg/youlai-boot.git ,然后点击 Clone。

在这里插入图片描述

稍等片刻,等待项目加载完成后,项目结构将如下所示:

在这里插入图片描述

配置环境

启动项目前,需要确保开发环境满足以下条件:已安装并配置 JDK 和 Maven

配置 JDK

打开项目结构配置面板 File → Project Structure(快捷键 Ctrl + Alt + Shift + S)打开项目结构配置面板,确保 SDK 设置为安装的 JDK 17

在这里插入图片描述

配置 Maven

打开 IDE 设置面板:File → Settings(快捷键 Ctrl + Alt + S),在 Build, Execution, Deployment → Build Tools → Maven 中,配置 Maven 使用本地安装的版本。

在这里插入图片描述

验证 Maven 配置:打开 IDEA 终端,执行以下命令,确保 Maven 使用的是 JDK 17

mvn -v

正确输出示例:

在这里插入图片描述

启动项目

打开项目的主启动类 YouLaiBootApplication。右键点击 main 方法,选择 Debug YouLaiBootApplication.main() 启动项目。

测试启动

项目启动成功后,可通过访问接口文档验证服务是否正常运行:

访问 Knife4j 接口文档:http://localhost:8989/doc.html

访问 Swagger 接口文档: http://localhost:8989/swagger-ui.html

在这里插入图片描述

切换本地环境

安装 Docker

项目中的 MySQL、Redis、MinIO 等中间件默认使用线上环境,一般情况下禁止增删改操作。如果需要更好地体验系统,建议在本地搭建 MySQL、Redis 等中间件,并切换到本地环境。

手动搭建 MySQL、Redis 等中间件及初始化数据库脚本可能较为耗时。推荐使用 Docker 和 Docker Compose,通过项目提供的 docker-compose 脚本一键搭建 MySQL、Redis 并初始化数据库。

首先,确保已安装 Docker,安装教程如下:

安装中间件

安装好 Docker 和 Docker Compose 后,查看项目根目录中的 docker-compose.yml 脚本内容。

进入项目目录,运行docker/run.md 完成 MySQL、Redis、MinIO 和 XXL-Job 的安装与配置。

在这里插入图片描述

运行后,打开 Docker Desktop,确认中间件已成功安装:

在这里插入图片描述

使用数据库可视化工具(如 Navicat),可以看到 youlai-boot 数据库已成功创建。这是因为 docker-compose.yml 指定了初始化 SQL 脚本的路径:

- ../sql/mysql8:/docker-entrypoint-initdb.d 

以下是中间件的默认配置。如果端口号与本地应用冲突,请修改 docker-compose.yml 中对应的端口设置:

中间件端口用户名密码控制台
MySQL3306root123456/
Redis6379/123456/
MinIO9000minioadminminioadminhttp://lcalhost:9090
xxl-job-admin8080adminadminhttp://lcalhost:8080

修改本地配置

配置 MySQL

application-dev.yml 文件中,将 MySQL 的连接信息替换为本地环境配置,例如数据库地址、用户名和密码。默认端口是 3306,默认用户名和密码是 root/123456,请根据实际情况修改。


配置 Redis

application-dev.yml 文件中,将 Redis 的地址和密码替换为本地环境配置。如果本地 Redis 没有设置密码,直接删除或注释掉 password 配置,避免连接失败。

配置 MinIO (可选)

如果项目中使用了文件上传服务,请在 application-dev.yml 文件中修改 MinIO 的连接信息为本地环境配置,包括地址、用户名和密码。例如,默认端口为 9000,默认用户名和密码为 minioadmin/minioadmin,请根据实际情况调整。

在这里插入图片描述

配置 Xxl-Job (可选)

如果项目中需要使用 XXL-Job,请在 application-dev.yml 文件中开启配置:

在这里插入图片描述

操作指南

修改包名

默认包名为 com.youlai.boot,如需修改为 com.wuhui.boot,需要做以下改动:

  • 修改启动类名称将启动类从 YoulaiBootApplication 改为 WuhuiBootApplication
  • 修改应用名称在 application.yml 中将 spring.application.name 的值从 youlai-boot 修改为 wuhui-boot;在 pom.xml 中将 <groupId> 值从 com.youlai 改为 com.wuhui
  • 代码生成的项目名称codegen.yml 里修改后端项目名称 codegen.backendAppName 替换 youlai-boot 为 wuhui-boot

修改接口文档包路径,否则接口文档不显示接口描述application-*.yml 修改接口文档扫描包路径

代码生成

这里以会员管理模块为例,来讲解如何生成前后端代码以及在项目中新增一个模块时自动生成菜单路由。

创建数据表

在数据库中执行以下 SQL 脚本以创建 会员信息表

CREATETABLE`member`(`id`intNOTNULLAUTO_INCREMENTCOMMENT'会员编号',`name`varchar(50)DEFAULTNULLCOMMENT'会员姓名',`mobile`varchar(20)DEFAULTNULLCOMMENT'会员手机号',`gender`tinyintDEFAULTNULLCOMMENT'性别',`age`intDEFAULTNULLCOMMENT'会员年龄',`create_time`timestampNULLDEFAULTNULLCOMMENT'创建时间',`update_time`timestampNULLDEFAULTNULLCOMMENT'更新时间',`is_deleted`tinyint(1)DEFAULT'0'COMMENT'是否删除(1:已删除;0:未删除)',PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='会员信息表';

启动项目

  • 启动后端项目youlai-boot
  • 启动前端项目vue3-element-admin
    • 在启动前端项目之前,需要修改 .env.development 文件中的接口地址为本地开发环境的后端服务地址。

生成代码

进入前端页面的代码生成器 在前端项目中找到 代码生成 菜单,选择 member 表,点击生成代码。

在这里插入图片描述

填写基础配置信息

  • 业务名:会员信息
  • 主包名:com.youlai.boot
  • 模块名:member
  • 实体名:Member
  • 如果需要自动生成会员模块的菜单和按钮权限,请选择对应的上级菜单。
在这里插入图片描述

配置字段信息

  • 配置筛选、列表和表单的字段。
  • 可选择字段类型,例如文本框、下拉框等。
  • 如果字段需要字典支持,可以配置字典信息。
在这里插入图片描述

在线预览和下载代码

  • 配置完成后,可以在线预览生成的前后端代码。
  • 下载生成的代码压缩包到本地。
在这里插入图片描述

集成代码

下载代码,解压得到前后端代码

后端代码集成

  • 解压下载的代码包,将后端代码复制到 youlai-boot 项目对应的目录中。
  • 确保项目重新加载新代码,并进行必要的构建和启动操作。
在这里插入图片描述

前端代码集成

  • 同样将前端代码复制到前端项目中对应的目录。

功能测试

进入 角色管理 模块,为当前用户的角色分配新生成的 会员管理 菜单权限。

勾选菜单中的 会员信息 选项。完成权限分配后,刷新页面。如果左侧菜单栏未显示 会员信息 菜单,请尝试重新登录。

在这里插入图片描述

进入 会员管理 模块,新增会员信息。

在这里插入图片描述

新增成功后,在会员列表中可以查看到刚添加的会员数据。

在这里插入图片描述

接口文档

接口文档的访问路径为 应用地址/doc.html。在本地环境中,youai-boot 项目的接口文档地址为:http://localhost:8989/doc.html

登录接口

由于大部分接口需要访问令牌(Token)进行身份认证,登录接口是使用接口文档的基础。通过登录接口获取成功返回的访问令牌后,可以将其设置到接口文档的全局变量中,方便后续接口的测试。

登录接口

设置全局 Token

将登录接口返回的访问令牌设置为全局变量,步骤如下:在接口文档右上角找到全局变量配置选项,输入令牌值后保存。

在这里插入图片描述

接口测试

设置好全局访问令牌后,打开其他接口时会发现令牌已自动填充,无需手动为每个接口单独设置令牌,极大简化了测试流程。

在这里插入图片描述

定时任务

在之前的 切换本地环境安装中间件 部分中,我们通过 Docker Compose 一键安装了 XXL-JOB。本节主要介绍如何配置和使用 XXL-JOB。如果您尚未安装 XXL-JOB,或者需要从零开始了解安装过程,请参考这篇文章:Spring Boot 3 整合 XXL-JOB 实现分布式定时任务调度

XXL-JOB 包含两个主要角色:调度器执行器。调度器是服务端,用于管理任务调度;执行器是应用端,用于执行任务的具体逻辑。

XXL-JOB 控制台

修改配置

XXL-JOB 的定时任务默认是关闭的。请根据下图修改配置:

  1. xxl.job.enabled 设置为 true
  2. 调整调度中心地址为实际安装地址,其它配置可保持默认。

添加执行器

application-dev.yml 中,执行器的应用名称 (xxl.job.executor.appname) 默认配置为:
xxl-job-executor-${spring.application.name},其中 ${spring.application.name} 会解析为当前应用名称。例如,在 youlai-boot 项目中,appname 将解析为 xxl-job-executor-youlai-boot

操作步骤

因为采用的是自动注册方式,重启 youlai-boot 应用后,再刷新执行器列表,可以看到机器已成功注册。

在 XXL-JOB 控制台中,添加执行器,appname 配置为 xxl-job-executor-youlai-boot

在这里插入图片描述

添加任务

youlai-boot 应用中,添加任务执行逻辑。以下是示例代码:

packagecom.youlai.boot.system.handler;/** * xxl-job 测试示例(Bean模式) */@Component@Slf4jpublicclassXxlJobSampleHandler{@XxlJob("demoJobHandler")publicvoiddemoJobHandler(){ log.info("XXL-JOB, Hello World.");}}

配置任务

  1. 在 XXL-JOB 控制台中,进入“任务管理”页面,选择新增任务。
  2. 选择刚刚创建的 youlai-boot 应用对应的执行器
  3. 配置 Cron 表达式来设定任务执行时间和频率。
  4. 设置任务模式为 Bean 模式,调用 Spring 容器中的 Bean,其中 Bean 名称为 @XxlJob("demoJobHandler") 中定义的 demoJobHandler
在这里插入图片描述

定时任务测试

任务创建完成后,可以在“操作”列中选择启动进行测试。

注意事项
调度器和执行器需要在网络上互通。如果调度器部署在云服务器上,而执行器运行在本地,则无法正常运行。建议将应用也部署到云服务器。

启动任务后,可以查看应用控制台日志,验证任务是否正确执行。

文件上传

youlai-boot 目前支持 MinIO、阿里云以及本地文件存储方式。以下以常用的 MinIO 为例,演示如何进行文件上传。

创建存储桶

在上一章节 切换本地环境安装中间件 中,我们已通过 Docker Compose 快速安装了 MinIO。如果尚未安装,可参考:Docker 部署 MinIO 对象存储系统

登录控制台,访问 http://localhost:9090/buckets/add-bucket 页面,创建一个名为 youlai 的存储桶。

在这里插入图片描述

设置存储桶的访问权限(Access Policy)为 public

youlai minio bucket access policy

修改应用配置

打开项目的 application-dev.yml 文件,配置文件存储相关参数:

  • 指定 oss.typeminio
  • 设置服务地址为 http://localhost:9000
  • 使用默认访问凭据:用户名 minioadmin,访问密钥 minioadmin
  • 存储桶名称为 youlai(前文创建的存储桶)

配置示例:

文件上传测试

启动项目后,访问接口文档 http://localhost:8989/doc.html。选择文件上传接口,上传文件后会返回对应的文件 URL。将返回的 URL 粘贴到浏览器中,即可预览上传的文件。

在这里插入图片描述

项目功能

数据权限

为了实现多租户和权限控制,我们可以通过 MyBatis-Plus 自定义数据权限注解和处理器,动态过滤数据。以下是实现方式:

实现原理

通过自定义拦截器实现 DataPermissionHandler 接口。在 youlai-boot 中,MyDataPermissionHandler 是其具体实现类,用于在 SQL 执行前动态拼接权限过滤条件。
处理逻辑如下:

  • 获取用户权限范围(如部门或用户)。
  • 动态生成筛选条件:如部门及以下的 dept_id IN (...) 或个人创建的 create_by = ...
  • 将条件追加到原始 SQL 的 WHERE 子句。

使用示例

在数据持久层的方法中,如果需要实现数据权限控制,可以直接在方法上添加 @DataPermission 注解。

UserMapper.java

@MapperpublicinterfaceUserMapper{@DataPermission( deptAlias ="u",// 部门字段的表别名,用于标记 SQL 中部门字段的来源表 deptIdColumnName ="dept_id",// 部门字段的列名,默认为 dept_id userAlias ="u",// 用户字段的表别名,用于标记 SQL 中用户字段的来源表 userIdColumnName ="create_by"// 用户字段的列名,默认为 create_by)Page<UserBO>getUserPage(Page<UserBO> page,UserPageQuery queryParams);}

UserMapper.xml

<selectid="getUserPage"> SELECT u.id, u.username, u.nickname, u.dept_id FROM sys_user u WHERE u.is_deleted = 0 </select>

动态 SQL 示例:

权限范围:本人创建

SELECT u.id, u.username, u.nickname, u.dept_id FROM sys_user u WHERE u.is_deleted =0AND u.create_by =2;

其中:AND u.create_by = 2MyDataPermissionHandler 根据用户权限为“本人创建”动态追加的筛选条件。

权限范围:部门及以下

SELECT u.id, u.username, u.nickname, u.dept_id FROM sys_user u WHERE u.is_deleted =0AND u.dept_id IN(SELECT id FROM sys_dept WHERE id =3OR FIND_IN_SET(3, tree_path));

其中AND u.dept_id IN (SELECT id FROM sys_dept WHERE id = 3 OR FIND_IN_SET(3, tree_path))MyDataPermissionHandler 根据用户权限为“部门及以下”动态追加的筛选条件。

防重提交

为防止用户在短时间内多次提交相同请求,系统提供了防重复提交功能。通过简单的注解配置,即可实现此功能。

使用防重提交

在需要防重复提交的接口上添加 @RepeatSubmit 注解即可。通过注解参数 expire,可以灵活控制重复提交的时间间隔(单位:秒)。如果不设置,默认时间为 5 秒。

示例:

@Operation(summary ="新增用户")@PostMapping@RepeatSubmit(expire =3)// 3 秒内禁止重复提交publicResult<?>saveUser(@RequestBody@ValidUserForm userForm ){// TODO 新增用户逻辑returnResult.success();}

测试防重提交

模拟短时间内的多次请求来验证防重复提交效果。例如,频繁调用新增用户接口。

以下是测试请求的效果演示:

通过简单配置,即可有效防止重复提交,确保接口的安全性和稳定性。

IP 限流

为防止接口被恶意刷取,系统内置了 IP 限流机制。当同一 IP 在单位时间内的请求次数超过限制时,系统将对该 IP 进行访问限制。

配置 QPS

可通过访问管理后台的 系统管理 → 系统配置 菜单设置 QPS 阈值(单位时间最大请求数)。

  • 若未配置或禁用该选项,则表示关闭 IP 限流功能。
在这里插入图片描述

限流测试

以下为模拟测试:20 个线程同时发起请求,当 QPS 配置为 10 时,部分请求将因限流而失败。

部分失败的请求如下所示:

在这里插入图片描述

项目扩展

多数据源支持

随着业务的复杂性增加,单一数据源可能无法满足需求,例如读写分离、多租户独立数据库或独立 Schema 模式等。本节介绍如何基于 youlai-boot 使用 dynamic-datasource 轻松实现多数据源支持。详细内容请参考:Spring Boot3 多数据源。https://youlai.blog.ZEEKLOG.net/article/details/134888348)

添加依赖

pom.xml 中添加如下依赖:

<dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot3-starter</artifactId><version>4.3.1</version></dependency>

配置多数据源

修改 application-dev.yml 文件,配置主库和从库的数据源:

spring:datasource:dynamic:primary: master # 设置默认数据源strict:false# 数据源找不到时是否抛出异常datasource:master:# 主库type: com.alibaba.druid.pool.DruidDataSource url: jdbc:mysql://localhost:3306/youlai_boot?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&allowMultiQueries=trueusername: root password:123456slave:# 从库type: com.alibaba.druid.pool.DruidDataSource url: jdbc:mysql://localhost:3306/youlai_boot_salve?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&allowMultiQueries=trueusername: root password:123456

多数据源测试

示例代码:

  • Mapper 层:通过注解 @DS 指定使用的数据源。
/** * 主库查询 */@DS("master")@Select("select * from sys_user where id = #{userId}")SysUsergetUserFromMaster(Long userId);/** * 从库查询 */@DS("slave")@Select("select * from sys_user where id = #{userId}")SysUsergetUserFromSlave(Long userId);
  • 单元测试类
@SpringBootTest@Slf4jclassSysUserMapperTest{@AutowiredprivateSysUserMapper userMapper;privatefinalLong userId =1L;@TestvoidtestSwitchDataSourceByAnnotation(){SysUser masterUser = userMapper.getUserFromMaster(userId); log.info("用户ID:{} 主库姓名:{}", userId, masterUser.getNickname());SysUser slaveUser = userMapper.getUserFromSlave(userId); log.info("用户ID:{} 从库姓名:{}", userId, slaveUser.getNickname());}}

测试结果如下图所示:

扩展登录方式

以下将以短信验证码登录这个常见场景为例,详细说明如何扩展 Spring Security 的认证机制。

自定义认证 Token

SmsAuthenticationToken 继承自 AbstractAuthenticationToken,通过策略模式由 AuthenticationManager 根据该 token 类型匹配相应的 Provider 进行认证,其中 Provider 负责具体的验证逻辑。

/** * 短信验证码认证 Token * * @author youlai */publicclassSmsAuthenticationTokenextendsAbstractAuthenticationToken{@Serialprivatestaticfinallong serialVersionUID =621L;/** * 认证信息 (手机号) */privatefinalObject principal;/** * 凭证信息 (短信验证码) */privatefinalObject credentials;/** * 短信验证码认证 Token (未认证) * * @param principal 微信用户信息 */publicSmsAuthenticationToken(Object principal,Object credentials){super(null);this.principal = principal;this.credentials = credentials;this.setAuthenticated(false);}/** * 短信验证码认证 Token (已认证) * * @param principal 用户信息 * @param authorities 授权信息 */publicSmsAuthenticationToken(Object principal,Collection<?extendsGrantedAuthority> authorities){super(authorities);this.principal = principal;this.credentials =null;// 认证通过super.setAuthenticated(true);}/** * 认证通过 * * @param principal 用户信息 * @param authorities 授权信息 * @return SmsAuthenticationToken */publicstaticSmsAuthenticationTokenauthenticated(Object principal,Collection<?extendsGrantedAuthority> authorities){returnnewSmsAuthenticationToken(principal, authorities);}@OverridepublicObjectgetCredentials(){returnthis.credentials;}@OverridepublicObjectgetPrincipal(){returnthis.principal;}}

自定义认证 Provider

Provider 的主要功能是执行验证逻辑。在短信验证码登录中,核心任务是校验验证码是否正确。SmsAuthenticationProvider 专门负责处理短信验证码的校验逻辑,确保登录流程的安全性和准确性。

/** * 短信验证码认证 Provider * * @author youlai */@Slf4jpublicclassSmsAuthenticationProviderimplementsAuthenticationProvider{privatefinalUserService userService;privatefinalRedisTemplate<String,Object> redisTemplate;publicSmsAuthenticationProvider(UserService userService,RedisTemplate<String,Object> redisTemplate){this.userService = userService;this.redisTemplate = redisTemplate;}/** * 短信验证码认证逻辑,参考 Spring Security 认证密码校验流程 * * @param authentication 认证对象 * @return 认证后的 Authentication 对象 * @throws AuthenticationException 认证异常 * @see org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider#authenticate(Authentication) */@OverridepublicAuthenticationauthenticate(Authentication authentication)throwsAuthenticationException{String mobile =(String) authentication.getPrincipal();String inputVerifyCode =(String) authentication.getCredentials();// 根据手机号获取用户信息UserAuthInfo userAuthInfo = userService.getUserAuthInfoByMobile(mobile);if(userAuthInfo ==null){thrownewUsernameNotFoundException("用户不存在");}// 检查用户状态是否有效if(ObjectUtil.notEqual(userAuthInfo.getStatus(),1)){thrownewDisabledException("用户已被禁用");}// 校验发送短信验证码的手机号是否与当前登录用户一致String cachedVerifyCode =(String) redisTemplate.opsForValue().get(RedisConstants.SMS_LOGIN_CODE_PREFIX+ mobile);if(!StrUtil.equals(inputVerifyCode, cachedVerifyCode)){thrownewBadCredentialsException("验证码错误");}else{// 验证成功后删除验证码 redisTemplate.delete(RedisConstants.SMS_LOGIN_CODE_PREFIX+ mobile);}// 构建认证后的用户详情信息SysUserDetails userDetails =newSysUserDetails(userAuthInfo);// 创建已认证的 SmsAuthenticationTokenreturnSmsAuthenticationToken.authenticated( userDetails, userDetails.getAuthorities());}@Overridepublicbooleansupports(Class<?> authentication){returnSmsAuthenticationToken.class.isAssignableFrom(authentication);}}

Spring Security 配置

SecurityConfig 中注册自定义的 SmsAuthenticationProvider,实现短信验证码登录认证逻辑:

/** * Spring Security 配置类 * * @author youlai */@Configuration@EnableWebSecurity@EnableMethodSecurity@RequiredArgsConstructorpublicclassSecurityConfig{privatefinalRedisTemplate<String,Object> redisTemplate;privatefinalUserService userService;// ..../** * 默认账号密码认证的 Provider */@BeanpublicDaoAuthenticationProviderdaoAuthenticationProvider(){DaoAuthenticationProvider daoAuthenticationProvider =newDaoAuthenticationProvider(); daoAuthenticationProvider.setPasswordEncoder(passwordEncoder); daoAuthenticationProvider.setUserDetailsService(userDetailsService);return daoAuthenticationProvider;}/** * 短信验证码认证 Provider */@BeanpublicSmsAuthenticationProvidersmsAuthenticationProvider(){returnnewSmsAuthenticationProvider(userService, redisTemplate);}/** * 认证管理器 */@BeanpublicAuthenticationManagerauthenticationManager(DaoAuthenticationProvider daoAuthenticationProvider,SmsAuthenticationProvider smsAuthenticationProvider ){returnnewProviderManager( daoAuthenticationProvider, smsAuthenticationProvider );}}

发送验证码

控制层实现

@Operation(summary ="发送登录短信验证码")@PostMapping("/login/sms/code")publicResult<?>sendLoginVerifyCode(@Parameter(description ="手机号", example ="18812345678")@RequestParamString mobile ){ authService.sendSmsLoginCode(mobile);returnResult.success();}

服务层实现

@Service@RequiredArgsConstructor@Slf4jpublicclassAuthServiceImplimplementsAuthService{privatefinalSmsService smsService;privatefinalRedisTemplate<String,Object> redisTemplate;/** * 发送登录短信验证码 * * @param mobile 手机号 */@OverridepublicvoidsendSmsLoginCode(String mobile){// 随机生成4位验证码// String code = String.valueOf((int) ((Math.random() * 9 + 1) * 1000));// TODO 为了方便测试,验证码固定为 1234,实际开发中在配置了厂商短信服务后,可以使用上面的随机验证码String code ="1234";// 发送短信验证码Map<String,String> templateParams =newHashMap<>(); templateParams.put("code", code);try{ smsService.sendSms(mobile,SmsTypeEnum.LOGIN, templateParams);}catch(Exception e){ log.error("发送短信验证码失败", e);}// 缓存验证码至Redis,用于登录校验 redisTemplate.opsForValue().set(RedisConstants.SMS_LOGIN_CODE_PREFIX+ mobile, code,5,TimeUnit.MINUTES);}}

登录接口

控制层实现

/** * 认证控制层 * * @author youlai */@RestController@RequestMapping("/api/v1/auth")@RequiredArgsConstructorpublicclassAuthController{privatefinalAuthService authService;// ...@Operation(summary ="短信验证码登录")@PostMapping("/login/sms")@Log(value ="短信验证码登录",module=LogModuleEnum.LOGIN)publicResult<AuthenticationToken>loginBySms(@Parameter(description ="手机号", example ="18812345678")@RequestParamString mobile,@Parameter(description ="验证码", example ="1234")@RequestParamString code ){AuthenticationToken loginResult = authService.loginBySms(mobile, code);returnResult.success(loginResult);}}

服务层实现

/** * 认证服务实现类 * * @author youlai */@Service@RequiredArgsConstructor@Slf4jpublicclassAuthServiceImplimplementsAuthService{privatefinalSmsService smsService;privatefinalRedisTemplate<String,Object> redisTemplate;/** * 短信验证码登录 * * @param mobile 手机号 * @param code 验证码 * @return 访问令牌 */@OverridepublicAuthenticationTokenloginBySms(String mobile,String code){// 1. 创建用户短信验证码认证的令牌(未认证)SmsAuthenticationToken smsAuthenticationToken =newSmsAuthenticationToken(mobile, code);// 2. 执行认证(认证中)Authentication authentication = authenticationManager.authenticate(smsAuthenticationToken);// 3. 认证成功后生成 JWT 令牌,并存入 Security 上下文,供登录日志 AOP 使用(已认证)AuthenticationToken authenticationToken = tokenManager.generateToken(authentication);SecurityContextHolder.getContext().setAuthentication(authentication);return authenticationToken;}}

接口测试

访问接口文档 http://localhost:8989/doc.html,调用发送短信验证码接口,输入手机号。

在这里插入图片描述

模拟接收短信验证码(固定为 1234),调用短信验证码登录接口,输入手机号和验证码即可成功登录并返回访问令牌。

在这里插入图片描述

项目部署

安装虚拟机

如果没有云服务器,可在本地安装虚拟机,参考:VMware 搭建 Linux 虚拟机环境 (CentOS 7.9)

安装并启动 FinalShell: 下载地址。新建连接,连接到已安装的虚拟机。

在这里插入图片描述

安装 Docker

参考文档:Linux (CentOS) 安装 Docker 和 Docker Compose

安装中间件

上传脚本

将项目的 dockersql 目录复制到服务器的 /opt 目录下:

授予执行权限

sudochmod +x /opt/docker/docker-compose.yml 

启动服务

切换到 /opt/docker 目录,执行以下命令启动容器:

cd /opt/docker # 启动服务docker-compose up -d

等待片刻,容器启动完成后如下:

在这里插入图片描述

验证安装

**MySQL **

启动脚本会自动创建数据库:

在这里插入图片描述

Redis

Redis 启动正常:

MinIO

打开浏览器访问 http://192.168.179.21:9090(根据实际 IP 修改),使用默认用户名密码 minioadmin/minioadmin 登录。

在这里插入图片描述

XXL-JOB

打开浏览器访问 http://192.168.179.21:8080/xxl-job-admin(根据实际 IP 修改),输入默认用户名密码 admin/123456 登录。

部署应用

安装插件

在 IDEA 菜单栏选择 File → Settings → Plugins,搜索 Docker 插件并安装,安装后重启 IDEA。

在这里插入图片描述

配置服务器

在 IDEA 菜单栏选择 File → Settings → Build, Execution, Deployment → Docker,添加远程服务器的连接信息:

在这里插入图片描述

连接成功后,显示 Connection successful

image-20250106113054626

部署配置

在 IDEA 顶部菜单选择 Edit Configurations 打开配置界面:

在这里插入图片描述

选择 Dockerfile,设置部署相关参数:

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

一键部署

配置完成后,选择对应配置点击启动,将自动完成编译、打包、镜像构建、镜像推送和容器启动。

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

启动成功后如下:

在这里插入图片描述

浏览器访问 http://192.168.179.21:8989/doc.html(根据实际 IP 修改)查看接口文档,验证部署是否成功。

结语

感谢您阅读本文档,youlai-boot 项目提供高效、灵活且可扩展的企业级权限管理解决方案。本手册从基础到扩展,为开发者提供了详细的参考指南,帮助您快速搭建项目并应对复杂业务需求。如有问题,欢迎添加微信(微信号:haoxianrui)交流或访问开源项目:https://gitee.com/youlaiorg

Read more

MySQL 慢查询 debug:索引没生效的三重陷阱

MySQL 慢查询 debug:索引没生效的三重陷阱

MySQL 慢查询 debug:索引没生效的三重陷阱 🌟 Hello,我是摘星! 🌈 在彩虹般绚烂的技术栈中,我是那个永不停歇的色彩收集者。 🦋 每一个优化都是我培育的花朵,每一个特性都是我放飞的蝴蝶。 🔬 每一次代码审查都是我的显微镜观察,每一次重构都是我的化学实验。 🎵 在编程的交响乐中,我既是指挥家也是演奏者。让我们一起,在技术的音乐厅里,奏响属于程序员的华美乐章。 目录 MySQL 慢查询 debug:索引没生效的三重陷阱 摘要 1. 慢查询问题的发现与定位 1.1 慢查询日志分析 1.2 性能监控体系搭建 2. 陷阱一:隐式类型转换的索引杀手 2.1 问题现象与案例分析 2.2 类型转换规则与影响 2.3 检测与预防策略 3. 陷阱二:函数包装导致的索引失效 3.1 函数使用的常见误区 3.

By Ne0inhk
[Java EE 进阶] 一文吃透 Spring IoC&DI:核心概念 + 实战用法 + 面试考点

[Java EE 进阶] 一文吃透 Spring IoC&DI:核心概念 + 实战用法 + 面试考点

摘要 :  本文深入解析了Spring框架的核心机制IoC(控制反转)和DI(依赖注入)。通过汽车制造案例,对比传统高耦合开发与Spring解耦方案,阐释IoC将对象创建权交给容器、DI实现依赖注入的核心思想。详细介绍了Bean存储的五种类注解(@Controller/@Service等)和@Bean方法注解,以及三种依赖注入方式(属性/构造方法/Setter注入)。针对多Bean注入问题,提出@Primary、@Qualifier和@Resource三种解决方案。最后总结IoC与DI的关系,指出这是理解Spring框架设计思想的基础,也是学习AOP、事务管理等高级特性的前提。文章系统性地讲解了Spring IoC&DI的核心概念和实战应用 在 Spring 体系的学习中,IoC(控制反转)和 DI(依赖注入)是贯穿始终的核心,也是 Spring 框架的灵魂。掌握 IoC&DI 不仅能理解 Spring 的设计思想,

By Ne0inhk
Hive数据仓库:架构原理与实践指南

Hive数据仓库:架构原理与实践指南

Hive数据仓库:架构原理与实践指南 🌟 你好,我是 励志成为糕手 ! 🌌 在代码的宇宙中,我是那个追逐优雅与性能的星际旅人。 ✨ 每一行代码都是我种下的星光,在逻辑的土壤里生长成璀璨的银河; 🛠️ 每一个算法都是我绘制的星图,指引着数据流动的最短路径; 🔍 每一次调试都是星际对话,用耐心和智慧解开宇宙的谜题。 🚀 准备好开始我们的星际编码之旅了吗? 目录 * Hive数据仓库:架构原理与实践指南 * 摘要 * 一、Hive基础概述 * 1.1 Hive是什么 * 1.2 Hive的发展历程 * 二、Hive架构设计 * 2.1 Hive整体架构 * 2.2 Hive核心组件 * 三、Hive数据类型与表结构 * 3.1 基本数据类型 * 3.2 表的类型 * 四、Hive查询语言HQL * 4.1 数据定义语言(DDL) * 4.2

By Ne0inhk
MySQL - 30 分钟搞定常用函数:字符串、日期、聚合函数实操

MySQL - 30 分钟搞定常用函数:字符串、日期、聚合函数实操

👋 大家好,欢迎来到我的技术博客! 💻 作为一名热爱 Java 与软件开发的程序员,我始终相信:清晰的逻辑 + 持续的积累 = 稳健的成长。 📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。 🎯 本文将围绕MySQL这个话题展开,希望能为你带来一些启发或实用的参考。 🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获! 文章目录 * MySQL - 30 分钟搞定常用函数:字符串、日期、聚合函数实操 🧠 * 一、字符串函数 🧾 * 1. 字符串长度函数 `LENGTH()` 和 `CHAR_LENGTH()` * 示例: * Java 代码示例: * 代码解释 * 2. 字符串截取函数 `SUBSTRING()` / `SUBSTR()` 和 `LEFT()` / `RIGHT()` * 示例: * Java 代码示例: * 代码解释 * 3.

By Ne0inhk