Compare commits
12 Commits
c23abf1b96
...
c2a6edbcef
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2a6edbcef | ||
|
|
0e0fe9ca0f | ||
|
|
1fcdc90a2b | ||
|
|
959c4dd6ec | ||
|
|
b5515bdda8 | ||
|
|
533217aa10 | ||
|
|
ed914a5562 | ||
|
|
3f6c7c177c | ||
|
|
734f86d4de | ||
|
|
d2a37b48d6 | ||
|
|
f243a8d69e | ||
|
|
fa0ab86445 |
255
README.md
255
README.md
@@ -1,175 +1,172 @@
|
|||||||
<div align="center">
|
<p align="center">
|
||||||
<img alt="logo" width="100" height="100" src="https://foruda.gitee.com/images/1733417239320800627/3c5290fe_716974.png">
|
<img alt="youlai-boot" width="120" src="https://foruda.gitee.com/images/1733417239320800627/3c5290fe_716974.png">
|
||||||
<h2>youlai-boot</h2>
|
</p>
|
||||||
<p><b>Spring Boot 4 权限管理系统</b></p>
|
|
||||||
<img alt="Java" src="https://img.shields.io/badge/Java-17-brightgreen.svg"/>
|
<h1 align="center">youlai-boot</h1>
|
||||||
<img alt="Spring Boot" src="https://img.shields.io/badge/SpringBoot-4.0.1-green.svg"/>
|
|
||||||
<img alt="License" src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"/>
|
|
||||||
<a href="https://gitee.com/youlaiorg/youlai-boot" target="_blank">
|
|
||||||
<img alt="Gitee" src="https://gitee.com/youlaiorg/youlai-boot/badge/star.svg"/>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/haoxianrui/youlai-boot" target="_blank">
|
|
||||||
<img alt="GitHub" src="https://img.shields.io/github/stars/haoxianrui/youlai-boot.svg?style=social&label=Stars"/>
|
|
||||||
</a>
|
|
||||||
<a href="https://gitcode.com/youlai/youlai-boot" target="_blank">
|
|
||||||
<img alt="GitCode" src="https://gitcode.com/youlai/youlai-boot/star/badge.svg"/>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a target="_blank" href="https://vue.youlai.tech/">🖥️ 在线预览</a>
|
<strong>Spring Boot 4 企业级权限管理系统后端</strong>
|
||||||
<span> | </span>
|
</p>
|
||||||
<a target="_blank" href="https://www.youlai.tech/youlai-boot">📑 官方文档</a>
|
|
||||||
<span> | </span>
|
<p align="center">
|
||||||
<a target="_blank" href="https://www.youlai.tech">🌐 官网</a>
|
<a href="https://www.youlai.tech/docs/admin/backend/java/"><img src="https://img.shields.io/badge/文档-youlai.tech-blue?style=flat-square&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTYgMjU2Ij48cGF0aCBmaWxsPSIjMzc4M2E0IiBkPSJNMjQ4IDExMUwzMSAxNDljMTQuNSA0LjkgMjkuNiAyMi41IDQ0LjIgMS44IDguNyAzLjEgMTcuNCAxIDEyLjhjLTIuOSA3LjItNi43IDEzLjUtMTIuOCAxNy40eiIvPjwvc3ZnPg==" alt="Documentation"></a>
|
||||||
|
<a href="https://vue.youlai.tech"><img src="https://img.shields.io/badge/在线预览-vue.youlai.tech-10B981?style=flat-square&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTYgMjU2Ij48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMjQ4IDExMUwzMSAxNDljMTQuNSA0LjkgMjkuNiAyMi41IDQ0LjIgMS44IDguNyAzLjEgMTcuNCAxIDEyLjhjLTIuOSA3LjItNi43IDEzLjUtMTIuOCAxNy40eiIvPjwvc3ZnPg==" alt="Demo"></a>
|
||||||
|
<a href="LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue?style=flat-square"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://gitee.com/youlaiorg/youlai-boot/stargazers"><img src="https://gitee.com/youlaiorg/youlai-boot/badge/star.svg?style=flat-square"></a>
|
||||||
|
<a href="https://github.com/haoxianrui/youlai-boot"><img src="https://img.shields.io/github/stars/haoxianrui/youlai-boot?style=social&label=Star"></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📢 项目简介
|
> [English](#) | 简体中文
|
||||||
|
|
||||||
基于 **JDK 17 + Spring Boot 4 + Spring Security** 构建的前后端分离权限管理系统,是 [**vue3-element-admin**](https://gitee.com/youlaiorg/vue3-element-admin) 的 Java 后端实现。
|
|
||||||
|
|
||||||
### 为什么选择 youlai-boot?
|
|
||||||
|
|
||||||
| 特性 | 说明 |
|
|
||||||
| ----------------- | ----------------------------------------------------- |
|
|
||||||
| 🚀 **最新技术栈** | Spring Boot 4 + JDK 17,持续跟进最新版本 |
|
|
||||||
| 🔐 **企业级认证** | Spring Security + JWT + Redis,支持令牌续期、多端互斥 |
|
|
||||||
| 🔑 **细粒度权限** | RBAC 模型,接口级 + 按钮级权限控制 |
|
|
||||||
| 🛠️ **开箱即用** | 用户、角色、菜单、部门、字典等核心模块 |
|
|
||||||
| 📦 **代码生成** | 内置代码生成器,快速构建 CRUD 功能 |
|
|
||||||
| 🌐 **完整生态** | Web 管理前端 + 移动端配套项目,多语言后端支持 |
|
|
||||||
|
|
||||||
## 🌈 相关项目
|
|
||||||
|
|
||||||
| 项目 | 技术栈 | 说明 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| [vue3-element-admin](https://gitee.com/youlaiorg/vue3-element-admin) | Vue 3 + Element Plus | 配套前端 |
|
|
||||||
| [vue3-element-template](https://gitee.com/youlaiorg/vue3-element-template) | Vue 3 + Element Plus | 前端精简模板 |
|
|
||||||
| [youlai-boot-tenant](https://gitee.com/youlaiorg/youlai-boot-tenant) | Spring Boot 4 | 多租户 SaaS 版 |
|
|
||||||
| [youlai-boot-flex](https://gitee.com/youlaiorg/youlai-boot-flex) | Spring Boot 3 + MyBatis-Flex | MyBatis-Flex 版 |
|
|
||||||
| [youlai-app](https://gitee.com/youlaiorg/youlai-app) | Vue 3 + uni-app | 移动端应用 |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 🎯 项目定位
|
||||||
|
|
||||||
|
一套 **Spring Boot 4 后端权限管理系统**,配套前端 [vue3-element-admin](https://gitee.com/youlaiorg/vue3-element-admin),并提供 **6 种语言实现**(Java / Node.js / Go / Python / PHP / C#),共享同一套 API 规范与数据库结构。
|
||||||
|
|
||||||
|
**适合场景**:企业中后台管理系统的后端学习参考、二次开发基础脚手架。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✨ 核心能力
|
||||||
|
|
||||||
|
| 能力 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 🔐 **安全体系** | Spring Security + JWT + Redis 多端互斥、令牌续期、验证码防刷 |
|
||||||
|
| 🛡️ **细粒度权限** | RBAC 五级:数据权限 → 菜单 → 按钮 → 接口 → 字段级 |
|
||||||
|
| ⚡ **代码生成器** | 可视化配置表单,一键生成 Entity/VO/Controller/Service/CRUD 前后端代码 |
|
||||||
|
| 📦 **模块齐全** | 用户、角色、菜单、部门、字典、文件、定时任务、消息中心、操作日志 |
|
||||||
|
| 🌐 **多租户 SaaS** | 数据隔离 + 租户配置,独立 [youlai-boot-tenant](https://gitee.com/youlaiorg/youlai-boot-tenant) 版本 |
|
||||||
|
| 🔌 **实时通信** | 内置 SSE 推送服务(在线用户数、字典同步、通知广播) |
|
||||||
|
| 📱 **生态完整** | 配套移动端 [youlai-app](https://gitee.com/youlaiorg/youlai-app)(UniApp)+ 完整[技术文档](https://www.youlai.tech/docs/admin/) |
|
||||||
|
|
||||||
|
## 📸 系统预览
|
||||||
|
|
||||||
|
|
||||||
|
<table align="center">
|
||||||
|
<tr>
|
||||||
|
<td><img alt="系统预览1" width="400" src="https://www.youlai.tech/storage/blog/2026/04/12/admin_preview.jpeg"></td>
|
||||||
|
<td><img alt="系统预览2" width="400" src="https://www.youlai.tech/storage/blog/2026/04/12/441_1x_shots_so.jpeg"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
## 🚀 快速开始
|
## 🚀 快速开始
|
||||||
|
|
||||||
### 环境要求
|
### 环境要求
|
||||||
|
|
||||||
- JDK 17+
|
| 组件 | 版本 |
|
||||||
- MySQL 5.7+/8.0+
|
|------|------|
|
||||||
- Redis 6.0+
|
| JDK | 17+ |
|
||||||
|
| MySQL | 8.0+ / 5.7+ |
|
||||||
|
| Redis | 6.0+ |
|
||||||
|
|
||||||
### 启动步骤
|
### 本地启动
|
||||||
|
|
||||||
**1. 克隆项目**
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# 1. 克隆项目
|
||||||
git clone https://gitee.com/youlaiorg/youlai-boot.git
|
git clone https://gitee.com/youlaiorg/youlai-boot.git
|
||||||
|
|
||||||
|
# 2. 导入数据库脚本 sql/mysql/youlai_admin.sql
|
||||||
|
|
||||||
|
# 3. 修改 application-dev.yml 配置 MySQL 和 Redis 连接信息
|
||||||
|
# 💡 默认已配置线上只读数据源,可直接启动体验
|
||||||
|
|
||||||
|
# 4. 运行 YouLaiBootApplication.java,访问 http://localhost:8000/doc.html
|
||||||
```
|
```
|
||||||
|
|
||||||
**2. 初始化数据库**
|
默认账号:`admin` / `123456`
|
||||||
|
|
||||||
执行 [youlai_admin.sql](sql/mysql/youlai_admin.sql) 创建数据库和基础数据。
|
### Docker 部署
|
||||||
|
|
||||||
**3. 修改配置**
|
```bash
|
||||||
|
cd docker && docker-compose up -d
|
||||||
编辑 [application-dev.yml](src/main/resources/application-dev.yml),配置 MySQL 和 Redis:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
spring:
|
|
||||||
datasource:
|
|
||||||
url: jdbc:mysql://localhost:3306/youlai_admin # 数据库连接地址
|
|
||||||
username: root # 数据库用户名
|
|
||||||
password: 123456 # 数据库密码
|
|
||||||
data:
|
|
||||||
redis:
|
|
||||||
host: localhost # Redis 地址
|
|
||||||
port: 6379 # Redis 端口
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> 💡 默认连接线上环境(仅读权限),可直接启动体验。
|
详细指南:[部署文档](https://www.youlai.tech/docs/admin/backends/java/deploy) · [开发规范](https://www.youlai.tech/docs/admin/backends/java/dev-standards)
|
||||||
|
|
||||||
**4. 启动项目**
|
|
||||||
|
|
||||||
运行 [YoulaiBootApplication.java](src/main/java/com/youlai/boot/YouLaiBootApplication.java),访问 http://localhost:8000/doc.html 查看接口文档。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📁 目录结构
|
## 📁 目录结构
|
||||||
|
|
||||||
```
|
```
|
||||||
youlai-boot
|
youlai-boot/
|
||||||
├── docker/ # Docker 部署
|
├── docker/ # Docker 部署编排
|
||||||
├── sql/ # 数据库脚本
|
├── sql/ # 数据库初始化脚本
|
||||||
├── src/
|
├── src/main/java/com/youlai/boot/
|
||||||
│ ├── auth/ # 认证授权业务
|
│ ├── YouLaiBootApplication # 启动类
|
||||||
|
│ ├── auth/ # 认证授权(登录/登出/令牌)
|
||||||
│ ├── codegen/ # 代码生成器
|
│ ├── codegen/ # 代码生成器
|
||||||
│ ├── common/ # 全局通用(常量、枚举、工具类、统一响应结果)
|
│ ├── common/ # 公共模块(常量/枚举/统一响应)
|
||||||
│ ├── framework/ # 底层技术基座(缓存/验证码/安全/Web等)
|
│ ├── file/ # 文件服务(MinIO/本地存储)
|
||||||
│ │ ├── apidoc/ # OpenAPI/Swagger 文档
|
│ ├── framework/ # 技术基座
|
||||||
|
│ │ ├── apidoc/ # OpenAPI/Swagger
|
||||||
│ │ ├── cache/ # Redis/Caffeine 缓存
|
│ │ ├── cache/ # Redis/Caffeine 缓存
|
||||||
│ │ ├── captcha/ # 验证码
|
│ │ ├── captcha/ # 图形验证码
|
||||||
│ │ ├── integration/ # SMS/Mail/WxMa 集成
|
│ │ ├── integration/ # 短信/邮件/微信
|
||||||
│ │ ├── job/ # XxlJob 定时任务
|
│ │ ├── job/ # XXL-Job 定时任务
|
||||||
│ │ ├── mybatis/ # 数据库/MP配置/拦截器
|
│ │ ├── mybatis/ # MyBatis Plus 配置
|
||||||
│ │ ├── security/ # 鉴权过滤器/Token机制
|
│ │ ├── security/ # 安全过滤器/Token机制
|
||||||
│ │ └── web/ # 跨域/全局异常/限流/Jackson
|
│ │ └── web/ # 全局异常/跨域/限流
|
||||||
│ ├── message/ # 消息中心
|
│ ├── message/ # SSE 消息推送
|
||||||
│ ├── file/ # 文件中心
|
│ └── system/ # 业务模块(用户/角色/菜单/部门)
|
||||||
│ ├── system/ # 核心系统模块(用户/角色/菜单/部门)
|
└── pom.xml # Maven 依赖
|
||||||
│ └── YouLaiBootApplication.java # 启动类
|
|
||||||
└── pom.xml # Maven 配置
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
## 🌐 相关生态
|
||||||
|
|
||||||
## 🐳 Docker 部署
|
| 项目 | 技术栈 | 定位 |
|
||||||
|
|------|--------|------|
|
||||||
|
| [**vue3-element-admin**](https://gitee.com/youlaiorg/vue3-element-admin) | Vue 3 + Element Plus | **PC 管理前端**(主推) |
|
||||||
|
| [**youlai-app**](https://gitee.com/youlaiorg/youlai-app) | Vue 3 + UniApp | **移动端 App** |
|
||||||
|
| [**youlai-boot-tenant**](https://gitee.com/youlaiorg/youlai-boot-tenant) | Spring Boot 4 | **SaaS 多租户版本** |
|
||||||
|
| [**youlai-boot-flex**](https://gitee.com/youlaiorg/youlai-boot-flex) | Spring Boot 3 + MyBatis-Flex | MyBatis-Flex 版 |
|
||||||
|
| [**youlai-nest**](https://gitee.com/youlaiorg/youlai-nest) | NestJS + TypeORM | **Node.js 后端** |
|
||||||
|
| [**youlai-gin**](https://gitee.com/youlaiorg/youlai-gin) | Go + Gorm | **Go 后端** |
|
||||||
|
| [**youlai-django**](https://gitee.com/youlaiorg/youlai-django) | Django + DRF | **Python 后端** |
|
||||||
|
| [**youlai-thinkphp**](https://gitee.com/youlaiorg/youlai-thinkphp) | ThinkPHP 8 | **PHP 后端** |
|
||||||
|
| [**youlai-aspnet**](https://gitee.com/youlaiorg/youlai-aspnet) | ASP.NET Core | **C# 后端** |
|
||||||
|
|
||||||
```bash
|
> 六种后端共享同一套 **RESTful API 规范** 和 **数据库结构**,前端可无缝切换。
|
||||||
cd docker
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
详细文档:[部署指南](https://www.youlai.tech/docs/admin/backend/java/deploy.html)
|
## 📘 文档资源
|
||||||
|
|
||||||
---
|
| 资源 | 地址 |
|
||||||
|
|------|------|
|
||||||
|
| **📖 完整文档站** | [docs.youlai.tech](https://www.youlai.tech/docs/admin/) |
|
||||||
|
| **🖥️ 在线预览(前端)** | [vue.youlai.tech](https://vue.youlai.tech) |
|
||||||
|
| **📱 在线预览(移动端)** | [app.youlai.tech](https://app.youlai.tech) |
|
||||||
|
| **🔗 接口文档** | 启动后访问 [http://localhost:8000/doc.html](http://localhost:8000/doc.html) |
|
||||||
|
|
||||||
## 📚 技术文档
|
## 📊 项目统计
|
||||||
|
|
||||||
| 文档 | 地址 |
|

|
||||||
| -------- | ---------------------------------------------------------------------------------- |
|
|
||||||
| 官方文档 | [youlai.tech](https://www.youlai.tech/youlai-boot/) |
|
|
||||||
| 入门指南 | [CSDN 博客](https://youlai.blog.csdn.net/article/details/145177011) |
|
|
||||||
| 接口文档 | [Apifox](https://www.apifox.cn/apidoc/shared-195e783f-4d85-4235-a038-eec696de4ea5) |
|
|
||||||
|
|
||||||
---
|
## 🤝 参与贡献
|
||||||
|
|
||||||
|
欢迎 Issue、PR 和 Star!详见 [贡献指南](https://www.youlai.tech/docs/admin/faq/help)。
|
||||||
|
|
||||||
|
[](https://github.com/haoxianrui/youlai-boot/graphs/contributors)
|
||||||
|
|
||||||
## 📄 开源协议
|
## 📄 开源协议
|
||||||
|
|
||||||
本项目基于 [Apache 2.0](LICENSE) 协议开源,可免费用于商业项目。
|
本项目基于 [Apache License 2.0](LICENSE) 开源,可免费用于商业项目。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ✅ 项目统计
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🤝 贡献者
|
|
||||||
|
|
||||||
[](https://github.com/haoxianrui/youlai-boot/graphs/contributors)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 💖 技术交流
|
|
||||||
|
|
||||||
关注「有来技术」公众号,点击菜单【交流群】获取微信群二维码(为防营销广告,实属无奈,望理解):
|
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="https://foruda.gitee.com/images/1737108820762592766/3390ed0d_716974.png" width="280">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
> 二维码过期?添加微信 **`haoxianrui`**,备注「前端/后端/全栈」即可拉你入群。
|
**关注「有来技术」,获取最新动态与技术分享**
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<img src="https://foruda.gitee.com/images/1737108820762592766/3390ed0d_716974.png" width="220">
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
*微信搜索「有来技术」或扫码关注*
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -323,6 +323,7 @@ public class CodegenServiceImpl implements CodegenService {
|
|||||||
bindMap.put("entityKebab", entityKebab);
|
bindMap.put("entityKebab", entityKebab);
|
||||||
bindMap.put("entityUpperSnake", entityUpperSnake);
|
bindMap.put("entityUpperSnake", entityUpperSnake);
|
||||||
bindMap.put("businessName", genTable.getBusinessName());
|
bindMap.put("businessName", genTable.getBusinessName());
|
||||||
|
bindMap.put("entityComment", genTable.getBusinessName());
|
||||||
bindMap.put("fieldConfigs", fieldConfigs);
|
bindMap.put("fieldConfigs", fieldConfigs);
|
||||||
|
|
||||||
boolean hasLocalDateTime = false;
|
boolean hasLocalDateTime = false;
|
||||||
|
|||||||
@@ -168,18 +168,18 @@ public class RedisTokenManager implements TokenManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使访问令牌失效
|
* Make access token invalid
|
||||||
|
* <p>
|
||||||
|
* Only deletes the current token, not all sessions for the user.
|
||||||
|
* This ensures single-device logout doesn't affect other devices when allowMultiLogin=true.
|
||||||
*
|
*
|
||||||
* @param token 访问令牌
|
* @param token Access token
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void invalidateToken(String token) {
|
public void invalidateToken(String token) {
|
||||||
String cleanToken = cleanBearerPrefix(token);
|
String cleanToken = cleanBearerPrefix(token);
|
||||||
Object value = redisTemplate.opsForValue().get(formatTokenKey(cleanToken));
|
// Only delete the current token, not all user sessions
|
||||||
if (value instanceof UserSession userSession) {
|
redisTemplate.delete(formatTokenKey(cleanToken));
|
||||||
Long userId = userSession.getUserId();
|
|
||||||
invalidateUserSessions(userId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.youlai.boot.system.model.vo.CurrentUserVO;
|
|||||||
import com.youlai.boot.system.model.vo.UserPageVO;
|
import com.youlai.boot.system.model.vo.UserPageVO;
|
||||||
import com.youlai.boot.system.model.vo.UserProfileVO;
|
import com.youlai.boot.system.model.vo.UserProfileVO;
|
||||||
import com.youlai.boot.system.service.UserService;
|
import com.youlai.boot.system.service.UserService;
|
||||||
|
import com.youlai.boot.framework.security.token.TokenManager;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
@@ -54,6 +55,8 @@ import java.util.List;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class UserController {
|
public class UserController {
|
||||||
|
|
||||||
|
private final TokenManager tokenManager;
|
||||||
|
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
|
||||||
@Operation(summary = "用户列表")
|
@Operation(summary = "用户列表")
|
||||||
@@ -122,6 +125,10 @@ public class UserController {
|
|||||||
.eq(SysUser::getId, userId)
|
.eq(SysUser::getId, userId)
|
||||||
.set(SysUser::getStatus, status)
|
.set(SysUser::getStatus, status)
|
||||||
);
|
);
|
||||||
|
// 用户禁用时立即失效其会话
|
||||||
|
if (result && status == 0) {
|
||||||
|
tokenManager.invalidateUserSessions(userId);
|
||||||
|
}
|
||||||
return Result.judge(result);
|
return Result.judge(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -187,7 +188,31 @@ public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements De
|
|||||||
.eq(Dept::getCode, code)
|
.eq(Dept::getCode, code)
|
||||||
);
|
);
|
||||||
Assert.isTrue(count == 0, "部门编号已存在");
|
Assert.isTrue(count == 0, "部门编号已存在");
|
||||||
|
Dept dept = this.getOne(
|
||||||
|
new LambdaQueryWrapper<Dept>()
|
||||||
|
.eq(Dept::getId, deptId)
|
||||||
|
.select(Dept::getParentId,Dept::getTreePath)
|
||||||
|
);
|
||||||
|
Assert.notNull(dept, "部门不存在");
|
||||||
|
|
||||||
|
Long parentId = formData.getParentId();
|
||||||
|
// 检查不能修改自己节点和子节点作为当前节点的父节点
|
||||||
|
Assert.isFalse(Objects.equals(deptId,parentId),"上级部门不能为自己");
|
||||||
|
|
||||||
|
// 检查是否修改了部门父节点
|
||||||
|
if (!Objects.equals(dept.getParentId(),parentId)){
|
||||||
|
// 获取当前节点的子节点的ID
|
||||||
|
List<Dept> childrenDeptList = this.list(
|
||||||
|
new LambdaQueryWrapper<Dept>()
|
||||||
|
.apply("FIND_IN_SET({0}, tree_path)", deptId)
|
||||||
|
.select(Dept::getId)
|
||||||
|
);
|
||||||
|
if(!childrenDeptList.isEmpty()) {
|
||||||
|
Set<Long> childrenIds = childrenDeptList.stream().map(Dept::getId).collect(Collectors.toSet());
|
||||||
|
Assert.isFalse(childrenIds.contains(parentId),"上级部门不能为当前子部门");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// form->entity
|
// form->entity
|
||||||
Dept entity = deptConverter.toEntity(formData);
|
Dept entity = deptConverter.toEntity(formData);
|
||||||
|
|||||||
@@ -215,6 +215,14 @@ public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements Ro
|
|||||||
if (result) {
|
if (result) {
|
||||||
// 刷新角色的权限缓存
|
// 刷新角色的权限缓存
|
||||||
roleMenuService.refreshRolePermsCache(role.getCode());
|
roleMenuService.refreshRolePermsCache(role.getCode());
|
||||||
|
|
||||||
|
// When role is disabled, invalidate sessions of all users with this role
|
||||||
|
if (status == 0) {
|
||||||
|
List<Long> userIds = userRoleService.listUserIdsByRoleId(roleId);
|
||||||
|
for (Long userId : userIds) {
|
||||||
|
tokenManager.invalidateUserSessions(userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import ${packageName}.${moduleName}.model.form.${entityName}Form;
|
|||||||
import ${packageName}.${moduleName}.model.query.${entityName}Query;
|
import ${packageName}.${moduleName}.model.query.${entityName}Query;
|
||||||
import ${packageName}.${moduleName}.model.vo.${entityName}Vo;
|
import ${packageName}.${moduleName}.model.vo.${entityName}Vo;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.youlai.boot.core.web.PageResult;
|
import ${packageName}.common.result.PageResult;
|
||||||
import com.youlai.boot.core.web.Result;
|
import ${packageName}.common.result.Result;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import java.time.LocalDateTime;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
#end
|
#end
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.youlai.boot.common.base.BaseEntity;
|
import ${packageName}.common.base.BaseEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* $!{businessName}实体对象
|
* $!{businessName}实体对象
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package ${packageName}.${moduleName}.model.vo;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const ${entityName}API = {
|
|||||||
/** 获取${businessName}分页数据 */
|
/** 获取${businessName}分页数据 */
|
||||||
getPage(queryParams?: ${entityName}QueryParams) {
|
getPage(queryParams?: ${entityName}QueryParams) {
|
||||||
return request<any, PageResult<${entityName}Item>>({
|
return request<any, PageResult<${entityName}Item>>({
|
||||||
url: \`\${${entityUpperSnake}_BASE_URL}\`,
|
url: `${${entityUpperSnake}_BASE_URL}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
});
|
});
|
||||||
@@ -21,7 +21,7 @@ const ${entityName}API = {
|
|||||||
*/
|
*/
|
||||||
getFormData(id: string) {
|
getFormData(id: string) {
|
||||||
return request<any, ${entityName}Form>({
|
return request<any, ${entityName}Form>({
|
||||||
url: \`\${${entityUpperSnake}_BASE_URL}/\${id}/form\`,
|
url: `${${entityUpperSnake}_BASE_URL}/${id}/form`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -33,7 +33,7 @@ const ${entityName}API = {
|
|||||||
*/
|
*/
|
||||||
create(data: ${entityName}Form) {
|
create(data: ${entityName}Form) {
|
||||||
return request({
|
return request({
|
||||||
url: \`\${${entityUpperSnake}_BASE_URL}\`,
|
url: `${${entityUpperSnake}_BASE_URL}`,
|
||||||
method: "post",
|
method: "post",
|
||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
@@ -47,7 +47,7 @@ const ${entityName}API = {
|
|||||||
*/
|
*/
|
||||||
update(id: string, data: ${entityName}Form) {
|
update(id: string, data: ${entityName}Form) {
|
||||||
return request({
|
return request({
|
||||||
url: \`\${${entityUpperSnake}_BASE_URL}/\${id}\`,
|
url: `${${entityUpperSnake}_BASE_URL}/${id}`,
|
||||||
method: "put",
|
method: "put",
|
||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
@@ -60,7 +60,7 @@ const ${entityName}API = {
|
|||||||
*/
|
*/
|
||||||
deleteByIds(ids: string) {
|
deleteByIds(ids: string) {
|
||||||
return request({
|
return request({
|
||||||
url: \`\${${entityUpperSnake}_BASE_URL}/\${ids}\`,
|
url: `${${entityUpperSnake}_BASE_URL}/${ids}`,
|
||||||
method: "delete",
|
method: "delete",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user