chore: init repo

This commit is contained in:
root 2026-03-25 10:02:19 +08:00
commit cc5b16673c
528 changed files with 34188 additions and 0 deletions

42
.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
.DS_Store
Thumbs.db
.idea/
*.iml
.classpath
.project
.settings/
*.log
logs/
**/target/
.m2repo/
backend/.m2repo/
backend/tmp-libscan/
node_modules/
**/node_modules/
dist/
**/dist/
dist-ssr/
**/.vite/
.pnpm-store/
**/.pnpm-store/
coverage/
**/coverage/
npm-debug.log*
pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
npminstall-debug.log
.env.local
.env.*.local

32
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,32 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Backend (dev)",
"request": "launch",
"mainClass": "com.yfd.platform.PlatformApplication",
"cwd": "${workspaceFolder}/backend",
"preLaunchTask": "backend:prepare-classpath",
"classPaths": [
"${workspaceFolder}/backend/target/classes",
"${workspaceFolder}/backend/target/dependency/*"
],
"args": [
"--spring.profiles.active=dev"
],
"vmArgs": "-Dfile.encoding=UTF-8"
},
{
"type": "java",
"name": "Attach (5005)",
"request": "attach",
"hostName": "localhost",
"port": 5005
}
]
}

24
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,24 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "backend:prepare-classpath",
"type": "shell",
"command": "mvn",
"args": [
"-f",
"${workspaceFolder}/backend/pom.xml",
"-DskipTests",
"compile",
"dependency:copy-dependencies",
"-DincludeScope=runtime",
"-DoutputDirectory=target/dependency"
],
"options": {
"cwd": "${workspaceFolder}/backend"
},
"problemMatcher": "$javac",
"group": "build"
}
]
}

View File

@ -0,0 +1 @@
-Dmaven.repo.local=.m2repo

View File

@ -0,0 +1,8 @@
# db-init 目录说明
- `sql/base-schema.sql`:数据库结构(表、索引、约束),由 mysqldump 导出或手写维护。
- `sql/base-data.sql`:初始化数据(字典、角色、菜单、管理员等),由 mysqldump 导出或手写维护。
- `scripts/export.ps1`Windows 导出脚本;将当前库结构与指定白名单数据导出到 sql 目录。
- `scripts/import.ps1`Windows 导入脚本;将 sql 中的结构与数据导入到目标库。
请参考 `../docs/数据库初始方案.md` 获取完整流程与约束。

View File

@ -0,0 +1,100 @@
param(
[string]$DB_HOST = '43.138.168.68',
[int]$DB_PORT = 3306,
[string]$DB_NAME = 'frameworkdb2023',
[string]$DB_USER = 'root',
[string]$DB_PASSWORD = 'ylfw20230626@'
)
# 确保输出目录存在
$outputDir = Join-Path $PSScriptRoot '..\sql'
if (!(Test-Path $outputDir)) {
New-Item -ItemType Directory -Path $outputDir | Out-Null
}
# 构建输出文件路径
$schemaFile = Join-Path $outputDir "base-schema.sql"
$dataFile = Join-Path $outputDir "base-data.sql"
# 构建 mysqldump 命令参数
$commonArgs = @(
"--host=$hostName",
"--port=$port",
"--user=$user",
"--routines",
"--triggers",
"--single-transaction",
"--set-charset",
"--default-character-set=utf8mb4"
)
if ($password) {
$commonArgs += "--password=$password"
}
Write-Host "开始导出数据库结构和数据..."
Write-Host "数据库: $database"
Write-Host "主机: $hostName:$port"
Write-Host "用户: $user"
Write-Host "输出目录: $outputDir"
Write-Host ""
# 导出数据库结构(仅结构,不包含数据)
Write-Host "正在导出数据库结构到: $schemaFile"
try {
$schemaArgs = $commonArgs + @(
"--no-data",
"--result-file=$schemaFile",
$database
)
& mysqldump @schemaArgs
if ($LASTEXITCODE -eq 0) {
Write-Host "✓ 数据库结构导出成功" -ForegroundColor Green
} else {
throw "mysqldump 返回错误代码: $LASTEXITCODE"
}
} catch {
Write-Error "导出数据库结构失败: $_"
exit 1
}
# 导出数据(仅数据,不包含结构)
Write-Host ""
Write-Host "正在导出数据到: $dataFile"
try {
$dataArgs = $commonArgs + @(
"--no-create-info",
"--skip-triggers",
"--result-file=$dataFile",
$database
)
& mysqldump @dataArgs
if ($LASTEXITCODE -eq 0) {
Write-Host "✓ 数据导出成功" -ForegroundColor Green
} else {
throw "mysqldump 返回错误代码: $LASTEXITCODE"
}
} catch {
Write-Error "导出数据失败: $_"
exit 1
}
Write-Host ""
Write-Host "数据库导出完成!" -ForegroundColor Green
Write-Host "结构文件: $schemaFile"
Write-Host "数据文件: $dataFile"
# 显示文件大小
if (Test-Path $schemaFile) {
$schemaSize = (Get-Item $schemaFile).Length
Write-Host "结构文件大小: $([math]::Round($schemaSize/1KB, 2)) KB"
}
if (Test-Path $dataFile) {
$dataSize = (Get-Item $dataFile).Length
Write-Host "数据文件大小: $([math]::Round($dataSize/1KB, 2)) KB"
}

View File

@ -0,0 +1,46 @@
param(
[string]$DB_HOST = '43.138.168.68',
[int]$DB_PORT = 3306,
[string]$DB_NAME = 'frameworkdb2025',
[string]$DB_USER = 'root',
[string]$DB_PASSWORD = 'ylfw20230626@'
)
$ErrorActionPreference = 'Stop'
$env:MYSQL_PWD = $DB_PASSWORD
$schemaPath = Join-Path $PSScriptRoot '..\sql\base-schema.sql'
$dataPath = Join-Path $PSScriptRoot '..\sql\base-data.sql'
function Invoke-MySqlFile([string]$filePath) {
Write-Host ("Processing SQL file: {0}" -f $filePath)
$sql = Get-Content -Raw $filePath
# Strip UTF-8 BOM if present
$bom = [char]0xFEFF
if ($sql.StartsWith($bom)) { $sql = $sql.Substring(1) }
# Sanitize dump headers and environment-specific statements
$lines = $sql -split "`r?`n"
$cleanLines = $lines | Where-Object {
$t = $_.Trim()
if ($t -eq '') { return $false }
if ($t -match '^(--|/\*|\*/|/\*!|[-]+$)') { return $false }
if ($t -match '^USE\s+') { return $false }
if ($t -match '^CREATE\s+DATABASE') { return $false }
return $true
}
$cleanSql = ($cleanLines -join "`n")
if ([string]::IsNullOrWhiteSpace($cleanSql)) {
Write-Warning ("Sanitized script is empty, skipping: {0}" -f $filePath)
return
}
Write-Host ("Importing via mysql from: {0}" -f $filePath)
$cleanSql | & mysql -h $DB_HOST -P $DB_PORT -u $DB_USER $DB_NAME
if ($LASTEXITCODE -ne 0) {
throw ("Import failed for {0} with exit code {1}" -f $filePath, $LASTEXITCODE)
}
}
Invoke-MySqlFile $schemaPath
Invoke-MySqlFile $dataPath
Write-Host 'Import completed'

View File

@ -0,0 +1,141 @@
# 项目技术文档framework 模块)
> 运行环境WindowsJava 21JDK 21Spring Boot 4.0.3
## 概述
- 平台型后端服务,采用 `Spring Boot 4.0.3`,区分 `dev` / `server` 两种运行配置。
- 数据访问:`MyBatis-Plus 3.5.16` + `MyBatis 3.5.16`;连接池:`Druid 1.2.20`。
- 任务调度:`Quartz 2.3.2`API 文档:`springdoc-openapi`Swagger UI
- 缓存与基础设施:`Redis`、`WebSocket`、`Actuator`、验证码(`easy-captcha`)、加密(`jasypt`)、`ip2region`、`hutool` 等。
- 打包方式:可执行 `JAR`(已启用 `spring-boot-maven-plugin``repackage`)。默认开发端口 `8093``server` 可使用 `8090`)。
## 目录结构
- 仓库根(当前工作目录):`D:\Trae_space\WholeProcessPlatform`
- 主要结构:
```
WholeProcessPlatform/
├── frontend/ # 前端源码Vite + TypeScript + Tailwind
└── backend/ # 后端服务Spring Boot 4.0.3
├── pom.xml # Maven 构建管理
└── src/
├── main/
│ ├── java/ # 业务代码(入口类在 com.yfd.platform.*
│ └── resources/ # 配置与静态资源static、配置 YAML、日志
└── test/
└── java/ # 测试代码
```
## 快速开始
- 前置要求:
- 安装 `JDK 21`、`Maven 3.6.3+`(建议 `3.9+`)、`Git`、`Node.js 18+`(前端构建)。
- Windows 终端建议执行 `chcp 65001`,确保 UTF-8 编码输出。
- 构建后端:
- `cd backend && mvn clean package -DskipTests`
- 本地运行dev
- `cd backend && java -jar target/platform-1.0.jar --spring.profiles.active=dev`
- 运行server
- `cd backend && java -jar target/platform-1.0.jar --spring.profiles.active=server`
- API 文档:
- 访问 `http://localhost:8093/swagger-ui.html`(以实际配置为准)
## 前端集成
- 自动构建Maven 在 `generate-resources` 阶段调用 `npm install``npm run build:mvn`,产物输出到 `frontend/dist`
- 静态资源复制:可通过 `maven-resources-plugin``frontend/dist` 复制至 `src/main/resources/static`,如需开启请将 POM 中该插件的 `<skip>` 设置为 `false` 或按需配置 Profile。
- 单独构建:在 `framework/frontend` 目录手动执行 `npm install && npm run build`,然后复制 `dist/` 到后端静态目录。
## 配置说明
- Profile 切换:通过 `--spring.profiles.active=<dev|server>` 激活环境。
- 关键属性:
- `file-space.system`:文件根路径,需在激活的 profile 中配置。
- `spring.datasource.druid.*`:数据库连接与池化参数。
- `server.port`:端口(`dev` 默认 8093`server` 可使用 8090
- 编码与 JVM 参数:
- 统一 JVM 编码:`-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8`POM 已配置)。
- PowerShell 输出建议设为 UTF-8`chcp 65001`。
- Maven 本地仓库:
- 为避免某些 IDE/沙箱环境写入受限,后端已配置 Maven 本地仓库为项目内目录(`backend/.m2repo`),配置文件:`backend/.mvn/maven.config`。
## 依赖与版本
- Spring`spring-boot-starter-web`、`security`、`cache`、`websocket`、`actuator`Spring Boot 4.0.3 / Spring Framework 7
- 数据访问:`mybatis-spring-boot-starter 4.0.1`、`mybatis-plus-spring-boot4-starter 3.5.16`、`druid 1.2.20`、`mysql-connector-j`、`sqlite-jdbc`。
- 工具与增强:`hutool-all`、`poi` / `poi-ooxml`、`fastjson`、`freemarker`、`jsoup`、`jasypt`、`ip2region`、`easy-captcha`、`UserAgentUtils`、`nashorn-core`。
- 文档:`springdoc-openapi-starter-webmvc-ui 3.0.2`Swagger UI
- 构建管控:`maven-enforcer-plugin`JDK≥17、Maven≥3.6.3)。
## 数据库配置示例
- MySQL 连接:
```yaml
spring:
datasource:
druid:
master:
url: jdbc:mysql://<host>:3306/<db>?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&useSSL=false&allowPublicKeyRetrieval=true
username: <user>
password: <password>
```
- 授权建议:
```sql
CREATE USER 'appuser'@'%' IDENTIFIED BY 'StrongPassword!';
GRANT ALL PRIVILEGES ON <db>.* TO 'appuser'@'%';
FLUSH PRIVILEGES;
```
- Druid 健壮性:
```yaml
spring:
datasource:
druid:
initial-size: 0
test-on-borrow: false
test-while-idle: true
validation-query: SELECT 1
```
## 日志与监控
- 日志LogbackUTF-8 输出),推荐格式:`%d [%thread] %-5level %logger{50} - %msg%n`。
- 监控:启用 Actuator健康检查路径`/actuator/health`。
- 建议接入集中日志与指标采集ELK / Vector监控数据库与线程池Druid / Quartz
## 定时任务
- 默认 `RAMJobStore`(非集群、内存存储)。
- 如需持久化与集群,改用 `JdbcJobStore` 并配置数据源与表结构。
## 安全与鉴权
- 采用 JWT 进行鉴权(如 `jwtAuthenticationTokenFilter`,按实际代码启用)。
- 敏感配置(`jwt.secret`、数据库密码)通过环境变量或外部密钥管理。
- 生产环境建议启用 HTTPS 并使用强密钥。
## Docker 部署
- 端口:默认暴露 `8093`dev可在 `server` profile 使用 `8090`
- 基本流程:
- 构建镜像:`docker build -t projectframework-app:latest .`
- 运行(开发环境):`docker run -d --name platform-app -p 8093:8093 -e SPRING_PROFILES_ACTIVE=dev projectframework-app:latest`
- 运行(服务器环境):`docker run -d --name platform-app -p 8090:8090 -e SPRING_PROFILES_ACTIVE=server projectframework-app:latest`
- 文件空间挂载示例:`-v D:/data/file-space:/data/file-space -e FILE_SPACE_SYSTEM=/data/file-space`
## Git 使用(框架分支)
- 远程仓库:根据实际仓库地址配置(示例:`http://121.37.111.42:3000/ThbTech/JavaProjectRepo.git`)。
- 分支建议:`main-framework`(稳定分支)、`develop-framework`(开发分支)。
- 常用命令:`git pull`、`git add .`、`git commit -m "<message>"`、`git push`。
- 提交署名:`git config user.name "<Your Name>"``git config user.email "<your@email>"`。
## CI/CD 建议
- CI 阶段:`mvn -B -DskipTests clean package`,配合单元测试与安全扫描(依赖检查、代码质量)。
- CD 阶段:推送镜像到私有仓库,使用环境变量注入敏感信息。
## 常见问题
- 中文乱码:执行 `chcp 65001`,确保 `logback-spring.xml` 使用 UTF-8。
- `NoSuchMethodError`MyBatis升级到 `MyBatis 3.5.16+` 并与 MP 版本匹配。
- 数据库 `Access denied`:校验账户密码与远程授权;必要时新建业务账户并放开 `3306`
- 端口占用/启动失败:检查 `server.port` 与冲突端口;查看应用日志定位根因。
- 前端构建问题:如遇 npm 依赖警告或复制冲突,可先独立构建并手动复制 `dist/`
## 变更日志(模板)
- `feat:` 新增功能说明
- `fix:` 缺陷修复说明
- `docs:` 文档更新说明
- `refactor:` 重构说明
- `perf:` 性能优化说明
---
如需扩展专题文档(接口规范、部署拓扑、参数字典等),请在 `docs/` 目录继续维护并与版本管理同步。

View File

@ -0,0 +1,134 @@
# 数据库初始方案framework
## 目标
- 在 `framework` 目录下建立 `db-init` 初始化目录,保存基础结构与基础数据。
- 支持从 MySQL 导出一份“初始化用”的基线数据,并在应用启动时自动检测是否已初始化;若未初始化,自动导入。
- 过程可重复、可审计、可在 `dev``server` 环境下安全运行。
## 目录结构规划
- `framework/db-init/`
- `sql/`
- `base-schema.sql`:基础库结构(表、索引、约束);可由 `mysqldump --no-data` 导出。
- `base-data.sql`:初始化数据(字典、默认角色、管理员等);可由 `mysqldump --no-create-info` 导出或手写。
- `scripts/`
- `export.ps1`Windows 导出脚本PowerShell
- `import.ps1`Windows 导入脚本PowerShell
- `export.sh`Linux/Mac 导出脚本(可选)。
- `import.sh`Linux/Mac 导入脚本(可选)。
- `README.md`:说明如何导出/导入、注意事项与环境变量。
## MySQL 导出策略
- 推荐使用 `mysqldump` 分离结构与数据,以便初始化时灵活控制:
- 结构:`mysqldump -h$DB_HOST -P$DB_PORT -u$DB_USER -p$DB_PASSWORD --no-data --databases $DB_NAME > sql/base-schema.sql`
- 数据:`mysqldump -h$DB_HOST -P$DB_PORT -u$DB_USER -p$DB_PASSWORD --no-create-info --databases $DB_NAME --tables <白名单表> > sql/base-data.sql`
- 数据白名单建议包含:
- 字典/配置表(如 `sys_dict`, `sys_config`
- 权限/角色/菜单(如 `sys_user`(仅管理员)、`sys_role`, `sys_menu`, `sys_user_role`, `sys_role_menu`
- 地区或静态映射表(如有)
- 机密信息与动态数据不导出:
- 排除审计日志、任务运行记录、业务动态表等。
## 导入策略
- 应用启动时进行“初始化检测”:
- 建议引入标记表:`app_init`(单行),字段 `initialized boolean`, `version varchar`,或在 `sys_config` 中维护 `init_done` 键。
- 检测逻辑:
- 若标记不存在或值为 `false`,视为未初始化。
- 若存在且为 `true`,跳过初始化。
- 导入步骤(未初始化时):
- 执行 `base-schema.sql`(若目标库为空或需校正结构时)。
- 执行 `base-data.sql`(插入/更新缺失的基线数据,注意幂等性)。
- 更新标记为已初始化,并记录版本与时间戳。
- 幂等性建议:
- 数据插入使用“存在则跳过/更新”策略(`INSERT ... ON DUPLICATE KEY UPDATE` 或先查询再写入)。
- 避免覆盖已有业务数据;仅在缺失时补充。
## Spring Boot 集成方案
- 方案 A轻量在后端增加初始化 Runner
- 新增一个 `@Component` 实现 `ApplicationRunner``CommandLineRunner``DataInitializer`
- 启动时:检查标记 → 未初始化则依次执行 `sql/base-schema.sql``sql/base-data.sql`
- SQL 执行方式:
- 直接通过 JDBC 读取并执行 SQL 文件(分号切分、事务包裹、失败回滚)。
- 或调用外部 `mysql` 命令(需服务器已安装 `mysql` 客户端,适合运维环境)。
- Profile 控制:默认仅在 `server``dev` 首次运行时启用;可通过配置 `app.init.enabled=true/false` 控制。
- 方案 B推荐中长期引入数据库版本管理工具
- `Flyway``Liquibase` 管理结构与数据变更;将初始化作为 `V1__base.sql` 脚本。
- 优点:变更有版本与校验,部署一致性更强;缺点:需要改造现有 SQL 并纳入流水线。
## 配置示例
- `application-server.yml` 中添加:
```
app:
init:
enabled: true
schema: classpath:db-init/sql/base-schema.sql
data: classpath:db-init/sql/base-data.sql
marker-table: app_init
marker-version: v1.0.0
```
- 路径策略:
- 若以资源方式打包,建议将 `db-init/sql` 复制到 `src/main/resources/db-init/sql`
- 或保留在项目根并通过绝对/相对路径访问(需考虑部署路径与权限)。
## 脚本示例Windows PowerShell
- `framework/db-init/scripts/export.ps1`
```
param(
[string]$DB_HOST = "43.138.168.68",
[int]$DB_PORT = 3306,
[string]$DB_NAME = "frameworkdb2025",
[string]$DB_USER = "root",
[string]$DB_PASSWORD = "ylfw20230626@"
)
$env:MYSQL_PWD = $DB_PASSWORD
# 导出结构
mysqldump -h $DB_HOST -P $DB_PORT -u $DB_USER --no-data --databases $DB_NAME > ../sql/base-schema.sql
# 按需导出数据(示例表名可调整)
mysqldump -h $DB_HOST -P $DB_PORT -u $DB_USER --no-create-info $DB_NAME sys_dict sys_config sys_role sys_menu sys_user sys_user_role sys_role_menu > ../sql/base-data.sql
Write-Host "Export completed: base-schema.sql & base-data.sql"
```
- `framework/db-init/scripts/import.ps1`
```
param(
[string]$DB_HOST = "127.0.0.1",
[int]$DB_PORT = 3306,
[string]$DB_NAME = "platform",
[string]$DB_USER = "root",
[string]$DB_PASSWORD = "root"
)
$env:MYSQL_PWD = $DB_PASSWORD
mysql -h $DB_HOST -P $DB_PORT -u $DB_USER $DB_NAME < ../sql/base-schema.sql
mysql -h $DB_HOST -P $DB_PORT -u $DB_USER $DB_NAME < ../sql/base-data.sql
Write-Host "Import completed"
```
## 启动时自动初始化的实现建议(代码思路)
- 创建 `DataInitializer`
- 读取 `app.init.enabled`;若为 `false` 则直接返回。
- 使用 `JdbcTemplate``EntityManager` 查询 `marker-table` 状态。
- 若未初始化:
- 读取并执行 `schema`、`data` 指定的 SQL 文件;分批执行并开启事务。
- 写入标记表 `initialized=true, version=marker-version, ts=now()`
- 并发保护:
- 使用数据库锁或单例启动(例如基于 `SELECT ... FOR UPDATE` 或分布式锁)避免多实例重复初始化。
- 失败回滚与告警:
- 执行失败时回滚事务并记录日志,提示人工介入;避免部分写入。
## 运维与审计
- 对 `sql/base-data.sql` 的修改应评审并走 PR避免带入敏感数据。
- CI 提示:
- 在 `server` 构建流水线中,可增加“初始化脚本语法检查”(如用 `mysql --dry-run` 或解析器)。
- 版本管理:
- 在 `db-init/README.md` 中记录每次更新目的与影响;或使用 `Flyway` 版本号管理。
## 下一步落地
- 我可以为你:
- 搭建 `framework/db-init` 目录与示例脚本、README。
- 在后端新增 `DataInitializer` 组件与配置项,支持 `dev/server` 下自动初始化。
- 可选集成 `Flyway`,将初始化脚本迁移为 `V1__base.sql` 并接入 CI。

422
backend/pom.xml Normal file
View File

@ -0,0 +1,422 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.yfd</groupId>
<artifactId>platform</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>platform</name>
<description>springboot 项目基础框架4.0.3</description>
<properties>
<java.version>21</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-boot.version>4.0.3</spring-boot.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<maven.compiler.release>21</maven.compiler.release>
<mybatis.version>3.5.16</mybatis.version>
<mybatis-plus.version>3.5.16</mybatis-plus.version>
<!-- dependency versions -->
<guava.version>30.0-jre</guava.version>
<mybatis.spring.boot.starter.version>4.0.1</mybatis.spring.boot.starter.version>
<druid.version>1.2.20</druid.version>
<druid.starter.version>1.2.20</druid.starter.version>
<sqlite-jdbc.version>3.32.3.2</sqlite-jdbc.version>
<hutool.version>5.8.8</hutool.version>
<poi.version>4.1.2</poi.version>
<poi.ooxml.version>4.1.2</poi.ooxml.version>
<fastjson.version>1.2.70</fastjson.version>
<springdoc.version>3.0.2</springdoc.version>
<freemarker.version>2.3.28</freemarker.version>
<jsoup.version>1.11.3</jsoup.version>
<jasypt.version>1.16</jasypt.version>
<ip2region.version>1.7.2</ip2region.version>
<easy.captcha.version>1.6.2</easy.captcha.version>
<useragentutils.version>1.21</useragentutils.version>
</properties>
<!-- 统一管理 MyBatis 相关版本,解决依赖收敛冲突 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.3</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- spring-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring-security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--Spring boot Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- WebSocket依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!--Spring 缓存-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--Guava是一种基于开源的Java库高性能数据缓存-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- 对于 jar 包spring-boot-starter-web 已包含嵌入式 Tomcat无需显式 provided -->
<!-- spring-quartz任务-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!-- spring-elasticsearch搜素-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-data-elasticsearch</artifactId>-->
<!-- </dependency>-->
<!-- spring-Mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.boot.starter.version}</version>
</dependency>
<!-- 显式固定 MyBatis 版本,避免与 MyBatis-Plus 不兼容的方法签名问题 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!--数据库连接-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- mysql数据库 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- sqlite-jdbc数据库 -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>${sqlite-jdbc.version}</version>
</dependency>
<!-- mybatis-plus 数据库扩展插件-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot4-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-jsqlparser</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!--apache.commons -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!--lombok bean注解 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 日志相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aspectj</artifactId>
</dependency>
<!-- 胡图工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.ooxml.version}</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- Springdoc OpenAPI 替换 Springfox -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.version}</version>
</dependency>
<!-- Micrometer Prometheus 导出器 -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<!-- 删除重复的 WebSocket 依赖(上方已声明一次) -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>${freemarker.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>${jsoup.version}</version>
</dependency>
<!-- 数据库密码加密 -->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>${jasypt.version}</version>
</dependency>
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>${ip2region.version}</version>
</dependency>
<!-- Java图形验证码 -->
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>${easy.captcha.version}</version>
</dependency>
<!-- 解析客户端操作系统、浏览器信息 -->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>${useragentutils.version}</version>
</dependency>
<!-- Restore JavaScript engine on JDK 15+ for ArithmeticCaptcha -->
<dependency>
<groupId>org.openjdk.nashorn</groupId>
<artifactId>nashorn-core</artifactId>
<version>15.4</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.*</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.42</version> <!-- 匹配spring boot管理的版本 -->
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>1.5.8</version>
<executions>
<execution>
<id>generate-docs</id>
<phase>prepare-package</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<skip>true</skip>
<backend>html</backend>
<doctype>book</doctype>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- 统一设置 JVM 编码为 UTF-8避免控制台中文乱码 -->
<jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
<!-- 以独立 JVM 运行,从而应用 jvmArguments -->
<!-- <fork>true</fork>-->
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 固化构建规则Maven Enforcer -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<id>enforce-rules</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<!-- 推荐升级 Maven 到 3.8+;临时放宽版本以便构建 -->
<requireMavenVersion>
<version>[3.6.3,)</version>
</requireMavenVersion>
<requireJavaVersion>
<version>[21,)</version>
</requireJavaVersion>
<dependencyConvergence/>
<!-- 如需严格校验插件版本,可在升级 Maven 后再启用 -->
</rules>
</configuration>
</execution>
</executions>
</plugin>
<!-- 额外生成 classes JAR便于其他业务工程作为依赖引用 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>attach-jar</id>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>plain</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,46 @@
package com.yfd.platform;
import com.yfd.platform.annotation.rest.AnonymousGetMapping;
import com.yfd.platform.datasource.DynamicDataSourceConfig;
import com.yfd.platform.utils.SpringContextHolder;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration;
import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
import org.springframework.boot.web.server.servlet.context.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.bind.annotation.RestController;
//@SpringBootApplication
@RestController
@EnableTransactionManagement
@ServletComponentScan("com.yfd.platform.config")
@MapperScan(basePackages = "com.yfd.platform.*.mapper")
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class, DataRedisAutoConfiguration.class})
@Import({DynamicDataSourceConfig.class})
@EnableCaching
public class PlatformApplication {
public static void main(String[] args) {
SpringApplication.run(PlatformApplication.class, args);
}
@Bean
public SpringContextHolder springContextHolder() {
return new SpringContextHolder();
}
/**
* 访问首页提示
*
* @return /
*/
@AnonymousGetMapping("/")
public String index() {
return "Backend service started successfully";
}
}

View File

@ -0,0 +1,13 @@
package com.yfd.platform;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(PlatformApplication.class);
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.annotation;
import java.lang.annotation.*;
/**
* @author jacky
* 用于标记匿名访问方法
*/
@Inherited
@Documented
@Target({ElementType.METHOD,ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnonymousAccess {
}

View File

@ -0,0 +1,20 @@
package com.yfd.platform.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author TangWei
* @date 2018-11-24
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value() default "";
String module() default "";
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.annotation.rest;
import com.yfd.platform.annotation.AnonymousAccess;
import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.lang.annotation.*;
/**
* Annotation for mapping HTTP {@code GET} requests onto specific handler
* methods.
* <p>
* 支持匿名访问 GetMapping
*
* @author liaojinlong
* @see RequestMapping
*/
@AnonymousAccess
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface AnonymousGetMapping {
/**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class)
String name() default "";
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] value() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] path() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] params() default {};
/**
* Alias for {@link RequestMapping#headers}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] headers() default {};
/**
* Alias for {@link RequestMapping#consumes}.
*
* @since 4.3.5
*/
@AliasFor(annotation = RequestMapping.class)
String[] consumes() default {};
/**
* Alias for {@link RequestMapping#produces}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] produces() default {};
}

View File

@ -0,0 +1,93 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.aspect;
import com.yfd.platform.system.domain.SysLog;
import com.yfd.platform.system.mapper.SysUserMapper;
import com.yfd.platform.system.service.ISysLogService;
import com.yfd.platform.system.service.IUserService;
import com.yfd.platform.utils.RequestHolder;
import com.yfd.platform.utils.SecurityUtils;
import com.yfd.platform.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* @author
* @date 2018-11-24
*/
@Component
@Aspect
@Slf4j
public class LogAspect {
@Resource
private final ISysLogService sysLogService;
@Resource
private IUserService userService;
ThreadLocal<Long> currentTime = new ThreadLocal<>();
public LogAspect(ISysLogService sysLogService) {
this.sysLogService = sysLogService;
}
/**
* 配置切入点
*/
@Pointcut("@annotation(com.yfd.platform.annotation.Log)")
public void logPointcut() {
// 该方法无方法体,主要为了让同类中其他方法使用此切入点
}
/**
* 配置环绕通知,使用在方法logPointcut()上注册的切入点
*
* @param joinPoint join point for advice
*/
@Around("logPointcut()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object result;
currentTime.set(System.currentTimeMillis());
result = joinPoint.proceed();
SysLog log = new SysLog("INFO");
currentTime.remove();
HttpServletRequest request = RequestHolder.getHttpServletRequest();
Map<String, String> nameInfo = userService.getNameInfo();
String nickname = nameInfo.get("nickname");
String username = nameInfo.get("username");
sysLogService.save(nickname, username, StringUtils.getBrowser(request),
StringUtils.getIp(request), joinPoint, log);
return result;
}
public String getUsername() {
try {
return SecurityUtils.getCurrentUsername();
} catch (Exception e) {
return "";
}
}
}

View File

@ -0,0 +1,147 @@
package com.yfd.platform.component;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
/**
* @author Huhailong
* SSE Server send Event 服务器推送服务
*/
@Slf4j
public class ServerSendEventServer {
/**
* 当前连接数
*/
private static AtomicInteger count = new AtomicInteger(0);
private static Map<String, SseEmitter> sseEmitterMap =
new ConcurrentHashMap<>();
public static SseEmitter connect(String userId) {
//设置超时时间0表示不过期默认是30秒超过时间未完成会抛出异常
SseEmitter sseEmitter = new SseEmitter(0L);
//SseEmitter sseEmitter = new SseEmitter();
//注册回调
sseEmitter.onCompletion(completionCallBack(userId));
sseEmitter.onError(errorCallBack(userId));
sseEmitter.onTimeout(timeOutCallBack(userId));
sseEmitterMap.put(userId, sseEmitter);
//数量+1
count.getAndIncrement();
log.info("create new sse connect ,current user:{}", userId);
return sseEmitter;
}
/**
* 给指定用户发消息
*/
public static void sendMessage(String userId, String message) {
if (sseEmitterMap.containsKey(userId)) {
try {
sseEmitterMap.get(userId).send(message);
} catch (IOException e) {
log.error("user id:{}, send message error:{}", userId,
e.getMessage());
e.printStackTrace();
}
}
}
/**
* 给所有用户发消息
*/
public static void sendMessage(String message) {
if (sseEmitterMap != null && !sseEmitterMap.isEmpty()) {
sseEmitterMap.forEach((k, v) -> {
// 发送消息
sendMessage(k, message);
});
}
}
/**
* 想多人发送消息组播
*/
public static void groupSendMessage(String groupId, String message) {
if (sseEmitterMap != null && !sseEmitterMap.isEmpty()) {
sseEmitterMap.forEach((k, v) -> {
try {
if (k.startsWith(groupId)) {
v.send(message, MediaType.APPLICATION_JSON);
}
} catch (IOException e) {
log.error("user id:{}, send message error:{}", groupId,
message);
removeUser(k);
}
});
}
}
public static void batchSendMessage(String message) {
sseEmitterMap.forEach((k, v) -> {
try {
v.send(message, MediaType.APPLICATION_JSON);
} catch (IOException e) {
log.error("user id:{}, send message error:{}", k,
e.getMessage());
removeUser(k);
}
});
}
/**
* 群发消息
*/
public static void batchSendMessage(String message, Set<String> userIds) {
userIds.forEach(userId -> sendMessage(userId, message));
}
public static void removeUser(String userId) {
sseEmitterMap.remove(userId);
//数量-1
count.getAndDecrement();
log.info("remove user id:{}", userId);
}
public static List<String> getIds() {
return new ArrayList<>(sseEmitterMap.keySet());
}
public static int getUserCount() {
return count.intValue();
}
private static Runnable completionCallBack(String userId) {
return () -> {
log.info("结束连接,{}", userId);
removeUser(userId);
};
}
private static Runnable timeOutCallBack(String userId) {
return () -> {
log.info("连接超时,{}", userId);
removeUser(userId);
};
}
private static Consumer<Throwable> errorCallBack(String userId) {
return throwable -> {
log.error("连接异常,{}", userId);
removeUser(userId);
};
}
}

View File

@ -0,0 +1,106 @@
package com.yfd.platform.component;
import org.springframework.stereotype.Component;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArrayList;
@ServerEndpoint("/websocket/{token}")
@Component
public class WebSocketServer {
private static int onlineCount=0;//在线人数
private static CopyOnWriteArrayList<WebSocketServer> webSocketSet=new CopyOnWriteArrayList<WebSocketServer>();//在线用户集合
private Session session;//与某个客户端的连接会话
private String currentUser;
@OnOpen
public void onOpen(@PathParam("token") String token, Session session){
this.currentUser = token;
this.session=session;
webSocketSet.add(this);//加入set中
addOnlineCount();
System.out.println("有新连接加入!当前在线人数为"+getOnlineCount());
allCurrentOnline();
}
@OnClose
public void onClose(){
webSocketSet.remove(this);
subOnlineCount();
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
allCurrentOnline();
}
@OnMessage
public void onMessage(String message, Session session){
System.out.println("来自客户端的消息:"+message);
for (WebSocketServer item:webSocketSet){
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
continue;
}
}
}
@OnError
public void onError(Session session, Throwable throwable){
System.out.println("发生错误!");
throwable.printStackTrace();
}
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 获取当前所有在线用户名
*/
public static void allCurrentOnline(){
for (WebSocketServer item : webSocketSet) {
System.out.println(item.currentUser);
}
}
/**
* 发送给指定用户
*/
public static void sendMessageTo(String message,String token) throws IOException {
for (WebSocketServer item : webSocketSet) {
if(item.currentUser.equals(token)){
item.session.getBasicRemote().sendText(message);
}
}
}
/**
* 群发自定义消息
*/
public static void sendInfo(String message) throws IOException {
System.out.println(message);
for (WebSocketServer item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
continue;
}
}
}
public static synchronized int getOnlineCount(){
return onlineCount;
}
public static synchronized void addOnlineCount(){
WebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount(){
WebSocketServer.onlineCount--;
}
}

View File

@ -0,0 +1,17 @@
package com.yfd.platform.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "app.init")
public class AppInitProperties {
private boolean enabled = false;
private String schema;
private String data;
// 用于判断是否已初始化默认检查是否存在核心表
private String markerTable = "sys_user";
private String markerVersion = "v1.0.0";
}

View File

@ -0,0 +1,129 @@
package com.yfd.platform.config;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.jdbc.datasource.init.ScriptUtils;
import org.springframework.jdbc.datasource.init.ScriptException;
import org.springframework.jdbc.datasource.init.ScriptStatementFailedException;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;
import org.springframework.util.StreamUtils;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
@Slf4j
@Component
@Profile({"dev","server"})
@RequiredArgsConstructor
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DataInitializer implements ApplicationRunner {
private final DataSource dataSource;
private final AppInitProperties properties;
private final ResourceLoader resourceLoader;
@Override
public void run(ApplicationArguments args) throws Exception {
if (!properties.isEnabled()) {
log.info("[DataInit] 自动初始化已关闭 app.init.enabled=false");
return;
}
try (Connection conn = dataSource.getConnection()) {
boolean initialized = tableExists(conn, properties.getMarkerTable());
if (initialized) {
log.info("[DataInit] 检测到标记表已存在: {},跳过初始化", properties.getMarkerTable());
return;
}
log.info("[DataInit] 未检测到标记表: {},开始导入 schema 与 data", properties.getMarkerTable());
executeIfPresent(conn, properties.getSchema());
executeIfPresent(conn, properties.getData());
log.info("[DataInit] 导入完成。marker={} version={}", properties.getMarkerTable(), properties.getMarkerVersion());
} catch (Exception ex) {
log.error("[DataInit] 初始化失败: {}", ex.getMessage(), ex);
throw ex;
}
}
private boolean tableExists(Connection conn, String tableName) {
if (tableName == null || tableName.isEmpty()) return false;
try {
DatabaseMetaData meta = conn.getMetaData();
try (ResultSet rs = meta.getTables(conn.getCatalog(), null, tableName, null)) {
return rs.next();
}
} catch (Exception e) {
log.warn("[DataInit] 检查表存在异常: {}", e.getMessage());
return false;
}
}
private void executeIfPresent(Connection conn, String location) throws Exception {
if (location == null || location.isEmpty()) return;
Resource resource = resourceLoader.getResource(location);
if (!resource.exists()) {
log.warn("[DataInit] 资源不存在: {}", location);
return;
}
log.info("[DataInit] 执行脚本: {}", location);
// 读取并清理脚本首部的 BOM 和危险语句CREATE DATABASE / USE schema
String sql = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
if (sql != null && !sql.isEmpty()) {
// 移除 UTF-8 BOM\uFEFF
if (sql.charAt(0) == '\uFEFF') {
sql = sql.substring(1);
}
// 移除 "USE xxx;" "CREATE DATABASE" 等与连接无关的语句
sql = sql.lines()
.filter(line -> {
String raw = line;
String t = raw.trim();
String u = t.toUpperCase();
// 过滤与连接无关或可能引发解析问题的语句/注释
if (u.startsWith("USE ")) return false;
if (u.startsWith("CREATE DATABASE")) return false;
if (t.startsWith("--")) return false; // 单行注释
if (t.startsWith("/*") || t.startsWith("*/")) return false; // 多行注释行
if (t.startsWith("/*!")) return false; // MySQL 版本注释
if (t.matches("^-+$")) return false; // 分隔线
return true;
})
.collect(Collectors.joining("\n"));
}
if (sql != null && !sql.trim().isEmpty()) {
try {
ScriptUtils.executeSqlScript(conn, new EncodedResource(new ByteArrayResource(sql.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8));
} catch (ScriptStatementFailedException e) {
String preview = sql.lines()
.filter(s -> !s.trim().isEmpty())
.limit(10)
.collect(Collectors.joining("\n"));
log.error("[DataInit] SQL语句执行失败: {}\n前10行预览:\n{}", e.getMessage(), preview);
throw e;
} catch (ScriptException e) {
String preview = sql.lines()
.filter(s -> !s.trim().isEmpty())
.limit(10)
.collect(Collectors.joining("\n"));
log.error("[DataInit] 脚本执行失败: {}\n前10行预览:\n{}", e.getMessage(), preview);
throw e;
}
} else {
log.warn("[DataInit] 脚本在清理后为空,跳过执行: {}", location);
}
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @author
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "file")
public class FileProperties {
/** 文件大小限制 */
private Long maxSize;
/** 头像大小限制 */
private Long avatarMaxSize;
private ElPath mac;
private ElPath linux;
private ElPath windows;
public ElPath getPath(){
String os = System.getProperty("os.name");
if(os.toLowerCase().startsWith("win")) {
return windows;
} else if(os.toLowerCase().startsWith("mac")){
return mac;
}
return linux;
}
@Data
public static class ElPath{
private String path;
private String avatar;
}
}

View File

@ -0,0 +1,17 @@
package com.yfd.platform.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* 文件空间相关配置替换 @Value("${file-space.system}") 用法
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "file-space")
public class FileSpaceProperties {
/** 基础目录,例如 D:/data/platform/ */
private String system;
}

View File

@ -0,0 +1,24 @@
package com.yfd.platform.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author TangWei
* @Date: 2023/3/27 18:07
* @Description:
*/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
@ResponseBody
@ExceptionHandler(value = Throwable.class)
public ResponseResult handleException(Throwable e) {
log.error("message:{}", e.getMessage());
return ResponseResult.error(e.getMessage());
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yfd.platform.system.domain.QuartzJob;
import com.yfd.platform.system.mapper.QuartzJobMapper;
import com.yfd.platform.utils.QuartzManage;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author
* @date 2019-01-07
*/
@Component
@RequiredArgsConstructor
@Order(Ordered.LOWEST_PRECEDENCE)
public class JobRunner implements ApplicationRunner {
private static final Logger log = LoggerFactory.getLogger(JobRunner.class);
private final QuartzJobMapper quartzJobMapper;
private final QuartzManage quartzManage;
/**
* 项目启动时重新激活启用的定时任务
*
* @param applicationArguments /
*/
@Override
public void run(ApplicationArguments applicationArguments) {
log.info("--------------------注入定时任务---------------------");
List<QuartzJob> quartzJobs =
quartzJobMapper.selectList(new LambdaQueryWrapper<QuartzJob>().eq(QuartzJob::getStatus, "1"));
quartzJobs.forEach(quartzManage::addJob);
log.info("--------------------定时任务注入完成---------------------");
}
}

View File

@ -0,0 +1,83 @@
package com.yfd.platform.config;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yfd.platform.component.ServerSendEventServer;
import com.yfd.platform.constant.Constant;
import com.yfd.platform.system.domain.LoginUser;
import com.yfd.platform.system.domain.Message;
import com.yfd.platform.system.service.IMessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private WebConfig webConfig;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
FilterChain filterChain) throws ServletException, IOException {
//获取token
String uri = httpServletRequest.getRequestURI();
String token = httpServletRequest.getHeader("token");
if (StrUtil.isEmpty(token) || "/user/login".equals(uri)) {
filterChain.doFilter(httpServletRequest, httpServletResponse);
return;
}
//解析token
boolean isok = JWTUtil.verify(token, "12345678".getBytes());
String userid = "";
if (isok) {
final JWT jwt = JWTUtil.parseToken(token);
userid = jwt.getPayload("userid").toString();
//从cachekey中获取用户信息失效时间
String cachekey = "expire_time:" + userid;
if(StrUtil.isNotEmpty(webConfig.loginuserCache().get(cachekey))){
long expire_time =Long.parseLong(webConfig.loginuserCache().get(cachekey));
if (System.currentTimeMillis() > expire_time) {
httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Token超过期限");
return;
}
}
}
//从cachekey中获取用户信息
String cachekey = "login:" + userid;
String jsonstr = webConfig.loginuserCache().get(cachekey);
LoginUser loginUser = JSON.parseObject(jsonstr, LoginUser.class);
if (ObjectUtil.isEmpty(loginUser)) {
httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN,
"登录用户已失效!");
return;
}
//存入SecurityContextHolder
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginUser, null,
loginUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
webConfig.loginuserCache().put(Constant.TOKEN + userid, token);
//更新了超期时间
long expireTime =System.currentTimeMillis() + ( 30L * 60L * 1000L);
webConfig.loginuserCache().put("expire_time:" + userid, String.valueOf(expireTime));
//放行过滤器
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}

View File

@ -0,0 +1,50 @@
package com.yfd.platform.config;
import cn.hutool.cache.Cache;
import cn.hutool.cache.impl.CacheObj;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yfd.platform.component.ServerSendEventServer;
import com.yfd.platform.constant.Constant;
import com.yfd.platform.system.domain.Message;
import com.yfd.platform.system.domain.SysUser;
import com.yfd.platform.system.service.IMessageService;
import com.yfd.platform.system.service.IUserService;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import java.util.Iterator;
/**
* @author TangWei
* @Date: 2023/3/24 15:56
* @Description:
*/
@Component
public class MessageConfig {
@Resource
private IMessageService messageService;
@Resource
private IUserService userService;
@Resource
private WebConfig webConfig;
public void sendMessage() {
long count =
messageService.count(new LambdaQueryWrapper<Message>().eq(Message::getStatus, "1"));
String userId = userService.getUserInfo().getId();
String token = webConfig.loginuserCache().get(Constant.TOKEN + userId);
ServerSendEventServer.sendMessage(token, count + "");
}
public void addMessage(Message message) {
messageService.save(message);
long count =
messageService.count(new LambdaQueryWrapper<Message>().eq(Message::getStatus, "1"));
ServerSendEventServer.sendMessage(count + "");
}
}

View File

@ -0,0 +1,24 @@
package com.yfd.platform.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/******************************
* 用途说明:
* 作者姓名: pcj
* 创建时间: 2022/10/24 10:50
******************************/
@Configuration
public class MybitsPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return mybatisPlusInterceptor;
}
}

View File

@ -0,0 +1,44 @@
package com.yfd.platform.config;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 将以 /prod-api/ 开头的请求转发到去掉前缀的真实后端接口路径
* 例如/prod-api/user/code -> /user/code
* 这样可以兼容前端生产环境仍使用 /prod-api 作为网关前缀的情况
*/
@WebFilter(urlPatterns = "/prod-api/*", filterName = "prodApiPrefixFilter")
public class ProdApiPrefixFilter implements Filter {
private static final String PREFIX = "/prod-api";
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
if (!(req instanceof HttpServletRequest) || !(res instanceof HttpServletResponse)) {
chain.doFilter(req, res);
return;
}
HttpServletRequest request = (HttpServletRequest) req;
String uri = request.getRequestURI();
// 仅拦截 /prod-api/* 的接口请求并进行内部 forward
if (uri.startsWith(PREFIX + "/")) {
String forwardUri = uri.substring(PREFIX.length());
RequestDispatcher dispatcher = request.getRequestDispatcher(forwardUri);
dispatcher.forward(req, res);
return;
}
chain.doFilter(req, res);
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config;
import org.quartz.Scheduler;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/**
* 定时任务配置
*
* @author /
* @date 2019-01-07
*/
@Configuration
public class QuartzConfig {
/**
* 解决Job中注入Spring Bean为null的问题
*/
@Component("quartzJobFactory")
public static class QuartzJobFactory extends AdaptableJobFactory {
private final AutowireCapableBeanFactory capableBeanFactory;
public QuartzJobFactory(AutowireCapableBeanFactory capableBeanFactory) {
this.capableBeanFactory = capableBeanFactory;
}
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
/**
* 注入scheduler到spring
*
* @param quartzJobFactory /
* @return Scheduler
* @throws Exception /
*/
@Bean(name = "scheduler")
public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception {
SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
factoryBean.setJobFactory(quartzJobFactory);
factoryBean.afterPropertiesSet();
Scheduler scheduler = factoryBean.getScheduler();
scheduler.start();
return scheduler;
}
}

View File

@ -0,0 +1,57 @@
package com.yfd.platform.config;
import java.util.HashMap;
public class ResponseResult extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
public ResponseResult() {
}
public static ResponseResult unlogin() {
return message("401", "未登录");
}
public static ResponseResult error() {
return error("操作失败");
}
public static ResponseResult success() {
return success("操作成功");
}
public static ResponseResult error(String msg) {
ResponseResult json = new ResponseResult();
json.put((String)"code", "1");//错误
json.put((String)"msg", msg);
return json;
}
public static ResponseResult message(String code, String msg) {
ResponseResult json = new ResponseResult();
json.put((String)"code", code);
json.put((String)"msg", msg);
return json;
}
public static ResponseResult success(String msg) {
ResponseResult json = new ResponseResult();
json.put((String)"code", "0");//正常
json.put((String)"msg", msg);
return json;
}
public static ResponseResult successData(Object obj) {
ResponseResult json = new ResponseResult();
json.put((String)"code", "0");//正常
json.put((String)"msg", "操作成功");
json.put("data", obj);
return json;
}
public ResponseResult put(String key, Object value) {
super.put(key, value);
return this;
}
}

View File

@ -0,0 +1,90 @@
package com.yfd.platform.config;
import com.yfd.platform.config.bean.LoginProperties;
import com.yfd.platform.exception.AccessDeniedHandExcetion;
import com.yfd.platform.exception.AuthenticationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@ConfigurationProperties(prefix = "login", ignoreUnknownFields = true)
public LoginProperties loginProperties() {
return new LoginProperties();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Autowired
private AuthenticationException authenticationException;
@Autowired
private AccessDeniedHandExcetion accessDeniedHandExcetion;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/user/login").anonymous()
.requestMatchers("/user/code").permitAll()
.requestMatchers(HttpMethod.GET, "/").permitAll()
.requestMatchers(HttpMethod.GET,
"/*.html",
"/webSocket/**",
"/assets/**",
"/icon/**").permitAll()
.requestMatchers(
"/swagger-ui.html",
"/swagger-ui/**",
"/v3/api-docs/**",
"/v3/api-docs.yaml",
"/swagger-resources/**",
"/webjars/**",
"/*/api-docs").permitAll()
.requestMatchers(
"/report/**",
"/images/**",
"/pageimage/**",
"/avatar/**",
"/systemurl/**",
"/api/imageserver/upload").permitAll()
.anyRequest().authenticated()
)
.cors(cors -> {});
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
http.exceptionHandling(ex -> ex
.authenticationEntryPoint(authenticationException)
.accessDeniedHandler(accessDeniedHandExcetion)
);
return http.build();
}
}

View File

@ -0,0 +1,49 @@
package com.yfd.platform.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springdoc.core.models.GroupedOpenApi;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.Contact;
/**
* Springdoc OpenAPI 配置
*/
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI projectOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("项目API 接口文档")
.version("3.0")
.description("")
.contact(new Contact().name("郑顺利").email("13910913995@163.com"))
);
}
@Bean
public GroupedOpenApi groupWebsiteApi() {
return GroupedOpenApi.builder()
.group("1. 平台模块")
.packagesToScan("com.yfd.platform.modules.platformdb.controller")
.build();
}
@Bean
public GroupedOpenApi groupQuartzApi() {
return GroupedOpenApi.builder()
.group("2. 定时任务")
.packagesToScan("com.yfd.platform.modules.quartz.controller")
.build();
}
@Bean
public GroupedOpenApi groupSystemApi() {
return GroupedOpenApi.builder()
.group("3. 系统管理")
.packagesToScan("com.yfd.platform.system.controller")
.build();
}
}

View File

@ -0,0 +1,61 @@
package com.yfd.platform.config;
import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import lombok.SneakyThrows;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Resource
private FileSpaceProperties fileSpaceProperties;
@Bean
public Cache<String, String> loginuserCache() {
return CacheUtil.newLRUCache(200);//用户登录缓存数 缺省200
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOriginPattern("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.setMaxAge(3600L);
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
@SneakyThrows
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/icon/**")
.addResourceLocations("classpath:/static/icon/")
.setCachePeriod(0);
registry.addResourceHandler("/assets/**")
.addResourceLocations("classpath:/static/assets/")
.setCachePeriod(0);
registry.addResourceHandler("swagger-ui.html").addResourceLocations(
"classpath:/META-INF/resources/");
String systemUrl = "file:" + fileSpaceProperties.getSystem().replace("\\", "/")+"user\\";
registry.addResourceHandler("/avatar/**").addResourceLocations(systemUrl).setCachePeriod(0);
}
}

View File

@ -0,0 +1,16 @@
package com.yfd.platform.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config.bean;
import lombok.Data;
/**
* 登录验证码配置信息
*
* @author: liaojinlong
* @date: 2020/6/10 18:53
*/
@Data
public class LoginCode {
/**
* 验证码配置
*/
private LoginCodeEnum codeType;
/**
* 验证码有效期 分钟
*/
private Long expiration = 2L;
/**
* 验证码内容长度
*/
private int length = 2;
/**
* 验证码宽度
*/
private int width = 111;
/**
* 验证码高度
*/
private int height = 36;
/**
* 验证码字体
*/
private String fontName;
/**
* 字体大小
*/
private int fontSize = 25;
public LoginCodeEnum getCodeType() {
return codeType;
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config.bean;
/**
* 验证码配置枚举
*
* @author: liaojinlong
* @date: 2020/6/10 17:40
*/
public enum LoginCodeEnum {
/**
* 算数
*/
arithmetic,
/**
* 中文
*/
chinese,
/**
* 中文闪图
*/
chinese_gif,
/**
* 闪图
*/
gif,
spec
}

View File

@ -0,0 +1,110 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version loginCode.length.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-loginCode.length.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config.bean;
import cn.hutool.core.util.StrUtil;
import com.wf.captcha.*;
import com.wf.captcha.base.Captcha;
import com.yfd.platform.exception.BadConfigurationException;
import lombok.Data;
import java.awt.*;
import java.util.Objects;
/**
* 配置文件读取
*
* @author liaojinlong
* @date loginCode.length0loginCode.length0/6/10 17:loginCode.length6
*/
@Data
public class LoginProperties {
/**
* 账号单用户 登录
*/
private boolean singleLogin = false;
private LoginCode loginCode;
/**
* 用户登录信息缓存
*/
private boolean cacheEnable;
public boolean isSingleLogin() {
return singleLogin;
}
public boolean isCacheEnable() {
return cacheEnable;
}
/**
* 获取验证码生产类
*
* @return /
*/
public Captcha getCaptcha() {
if (Objects.isNull(loginCode)) {
loginCode = new LoginCode();
if (Objects.isNull(loginCode.getCodeType())) {
loginCode.setCodeType(LoginCodeEnum.arithmetic);
}
}
return switchCaptcha(loginCode);
}
/**
* 依据配置信息生产验证码
*
* @param loginCode 验证码配置信息
* @return /
*/
private Captcha switchCaptcha(LoginCode loginCode) {
Captcha captcha;
synchronized (this) {
switch (loginCode.getCodeType()) {
case arithmetic:
// 算术类型 https://gitee.com/whvse/EasyCaptcha
captcha = new ArithmeticCaptcha(loginCode.getWidth(), loginCode.getHeight());
// 几位数运算默认是两位
captcha.setLen(loginCode.getLength());
break;
case chinese:
captcha = new ChineseCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case chinese_gif:
captcha = new ChineseGifCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case gif:
captcha = new GifCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case spec:
captcha = new SpecCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
default:
throw new BadConfigurationException("验证码配置信息错误!正确配置查看 LoginCodeEnum ");
}
}
if(StrUtil.isNotBlank(loginCode.getFontName())){
captcha.setFont(new Font(loginCode.getFontName(), Font.PLAIN, loginCode.getFontSize()));
}
return captcha;
}
}

View File

@ -0,0 +1,70 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config.thread;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 异步任务线程池装配类
* @author https://juejin.im/entry/5abb8f6951882555677e9da2
* @date 2019年10月31日15:06:18
*/
@Slf4j
@Configuration
public class AsyncTaskExecutePool implements AsyncConfigurer {
/** 注入配置类 */
private final AsyncTaskProperties config;
public AsyncTaskExecutePool(AsyncTaskProperties config) {
this.config = config;
}
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程池大小
executor.setCorePoolSize(config.getCorePoolSize());
//最大线程数
executor.setMaxPoolSize(config.getMaxPoolSize());
//队列容量
executor.setQueueCapacity(config.getQueueCapacity());
//活跃时间
executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
//线程名字前缀
executor.setThreadNamePrefix("el-async-");
// setRejectedExecutionHandler当pool已经达到max size的时候如何处理新任务
// CallerRunsPolicy不在新线程中执行任务而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (throwable, method, objects) -> {
log.error("===="+throwable.getMessage()+"====", throwable);
log.error("exception method:"+method.getName());
};
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config.thread;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 线程池配置属性类
* @author https://juejin.im/entry/5abb8f6951882555677e9da2
* @date 2019年10月31日14:58:18
*/
@Data
@Component
@ConfigurationProperties(prefix = "task.pool")
public class AsyncTaskProperties {
private int corePoolSize;
private int maxPoolSize;
private int keepAliveSeconds;
private int queueCapacity;
}

View File

@ -0,0 +1,62 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config.thread;
import org.springframework.stereotype.Component;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 自定义线程名称
* @author
* @date 2019年10月31日17:49:55
*/
@Component
public class TheadFactoryName implements ThreadFactory {
private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
public TheadFactoryName() {
this("el-pool");
}
private TheadFactoryName(String name){
// 使用当前线程的线程组避免依赖已弃用的 SecurityManager
group = Thread.currentThread().getThreadGroup();
//此时namePrefix就是 name + 第几个用这个工厂创建线程池的
this.namePrefix = name +
POOL_NUMBER.getAndIncrement();
}
@Override
public Thread newThread(Runnable r) {
//此时线程的名字 就是 namePrefix + -thread- + 这个线程池中第几个执行的线程
Thread t = new Thread(group, r,
namePrefix + "-thread-"+threadNumber.getAndIncrement(),
0);
if (t.isDaemon()) {
t.setDaemon(false);
}
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config.thread;
import com.yfd.platform.utils.SpringContextHolder;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 用于获取自定义线程池
* @author
* @date 2019年10月31日18:16:47
*/
public class ThreadPoolExecutorUtil {
public static ThreadPoolExecutor getPoll(){
AsyncTaskProperties properties = SpringContextHolder.getBean(AsyncTaskProperties.class);
return new ThreadPoolExecutor(
properties.getCorePoolSize(),
properties.getMaxPoolSize(),
properties.getKeepAliveSeconds(),
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(properties.getQueueCapacity()),
new TheadFactoryName()
);
}
}

View File

@ -0,0 +1,42 @@
package com.yfd.platform.constant;
/**
* @author TangWei
* @Date: 2023/3/3 17:40
* @Description: 常量类
*/
public class Constant {
public static final String LOGIN = "login:";
public static final String TOKEN = "token:";
public static final String USER_ID = "userid";
public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String CODE_KEY = "code-key-";
public static final long CODE_EXPIRATION_TIME = 1000 * 60;
/**
* 用于IP定位转换
*/
public static final String REGION = "内网IP|内网IP";
/**
* win 系统
*/
public static final String WIN = "win";
/**
* mac 系统
*/
public static final String MAC = "mac";
/**
* 常用接口
*/
public static class Url {
// IP归属地查询
// public static final String IP_URL = "http://whois.pconline.com
// .cn/ipJson.jsp?ip=%s&json=true";
public static final String IP_URL = "http://whois.pconline.com" +
".cn/ipJson.jsp?ip=%s&json=true";
}
}

View File

@ -0,0 +1,17 @@
package com.yfd.platform.datasource;
import java.lang.annotation.*;
/******************************
* 用途说明:
* 作者姓名: wxy
* 创建时间: 2022/9/23 17:48
******************************/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String name() default "";
}

View File

@ -0,0 +1,55 @@
package com.yfd.platform.datasource;
import cn.hutool.core.util.StrUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/******************************
* 用途说明:
* 作者姓名: wxy
* 创建时间: 2022/9/23 17:50
******************************/
@Aspect
@Component
public class DataSourceAspect {
@Pointcut("@annotation(com.yfd.platform.datasource.DataSource)")
public void dataSourcePointCut() {
}
private String DataBaseName;
@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
if (StrUtil.isNotBlank(DataBaseName)){
DynamicDataSource.setDataSource(DataBaseName);
}else {
DynamicDataSource.setDataSource("master");
}
try {
return point.proceed();
} finally {
DynamicDataSource.clearDataSource();
}
}
public String getDataBase(Integer type){
if (type == 1){
DataBaseName="master";
}else {
DataBaseName="slave";
}
return DataBaseName;
}
}

View File

@ -0,0 +1,40 @@
package com.yfd.platform.datasource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.Map;
/******************************
* 用途说明:
* 作者姓名: wxy
* 创建时间: 2022/9/23 17:47
******************************/
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return getDataSource();
}
public static void setDataSource(String dataSource) {
contextHolder.set(dataSource);
}
public static String getDataSource() {
return contextHolder.get();
}
public static void clearDataSource() {
contextHolder.remove();
}
}

View File

@ -0,0 +1,51 @@
package com.yfd.platform.datasource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import com.alibaba.druid.pool.DruidDataSource;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/******************************
* 用途说明:
* 作者姓名: wxy
* 创建时间: 2022/9/23 17:45
******************************/
@Configuration
@Component
public class DynamicDataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.druid.master")
public DataSource wglMasterDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setBreakAfterAcquireFailure(true);
dataSource.setConnectionErrorRetryAttempts(0);
return dataSource;
}
@Bean
@ConfigurationProperties("spring.datasource.druid.slave")
public DataSource wglSlaveDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setBreakAfterAcquireFailure(true);
dataSource.setConnectionErrorRetryAttempts(0);
return dataSource;
}
@Bean
@Primary
public DynamicDataSource dataSource(DataSource wglMasterDataSource, DataSource wglSlaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("master",wglMasterDataSource);
targetDataSources.put("slave",wglSlaveDataSource);
return new DynamicDataSource(wglMasterDataSource, targetDataSources);
}
}

View File

@ -0,0 +1,27 @@
package com.yfd.platform.exception;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class AccessDeniedHandExcetion implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
JSONObject jobj=new JSONObject();
jobj.putOnce("status","403");
jobj.putOnce("msg","用户权限不足,不能访问");
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().println(JSONUtil.toJsonStr(jobj));
}
}

View File

@ -0,0 +1,32 @@
package com.yfd.platform.exception;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.yfd.platform.config.ResponseResult;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class AuthenticationException implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, org.springframework.security.core.AuthenticationException authException) throws IOException, ServletException {
JSONObject jobj=new JSONObject();
if(authException.getMessage().equals("用户账号不存在!")){
jobj.putOnce("code","401");
jobj.putOnce("msg","用户账号不存在/密码错误,登录失败!");
}else{
jobj.putOnce("code","401");
jobj.putOnce("msg","用户Token失效请重新登录");
}
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().println(JSONUtil.toJsonStr(jobj));
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.exception;
/**
* 统一关于错误配置信息 异常
*
* @author: liaojinlong
* @date: 2020/6/10 18:06
*/
public class BadConfigurationException extends RuntimeException {
/**
* Constructs a new runtime exception with {@code null} as its
* detail message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}.
*/
public BadConfigurationException() {
super();
}
/**
* Constructs a new runtime exception with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a
* call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public BadConfigurationException(String message) {
super(message);
}
/**
* Constructs a new runtime exception with the specified detail message and
* cause. <p>Note that the detail message associated with
* {@code cause} is <i>not</i> automatically incorporated in
* this runtime exception's detail message.
*
* @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method).
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public BadConfigurationException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructs a new runtime exception with the specified cause and a
* detail message of {@code (cause==null ? null : cause.toString())}
* (which typically contains the class and detail message of
* {@code cause}). This constructor is useful for runtime exceptions
* that are little more than wrappers for other throwables.
*
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public BadConfigurationException(Throwable cause) {
super(cause);
}
/**
* Constructs a new runtime exception with the specified detail
* message, cause, suppression enabled or disabled, and writable
* stack trace enabled or disabled.
*
* @param message the detail message.
* @param cause the cause. (A {@code null} value is permitted,
* and indicates that the cause is nonexistent or unknown.)
* @param enableSuppression whether or not suppression is enabled
* or disabled
* @param writableStackTrace whether or not the stack trace should
* be writable
* @since 1.7
*/
protected BadConfigurationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.exception;
import lombok.Getter;
import org.springframework.http.HttpStatus;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
/**
* @author
* @date 2018-11-23
* 统一异常处理
*/
@Getter
public class BadRequestException extends RuntimeException{
private Integer status = BAD_REQUEST.value();
public BadRequestException(String msg){
super(msg);
}
public BadRequestException(HttpStatus status, String msg){
super(msg);
this.status = status.value();
}
}

View File

@ -0,0 +1,20 @@
package com.yfd.platform.exception;
import org.springframework.util.StringUtils;
/**
* @Author pcj
* @Date 2021/1/26 9:07
* @Version 1.0
*/
public class ChildrenExistException extends RuntimeException{
public ChildrenExistException(Class clazz, String field, String val) {
super(ChildrenExistException.generateMessage(clazz.getSimpleName(), field, val));
}
private static String generateMessage(String entity, String field, String val) {
return StringUtils.capitalize(entity)
+ " with " + field + " "+ val + " Children Exist";
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.exception;
import org.springframework.util.StringUtils;
/**
* @author
* @date 2018-11-23
*/
public class EntityExistException extends RuntimeException {
public EntityExistException(Class clazz, String field, String val) {
super(EntityExistException.generateMessage(clazz.getSimpleName(), field, val));
}
private static String generateMessage(String entity, String field, String val) {
return StringUtils.capitalize(entity)
+ " with " + field + " "+ val + " existed";
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.exception;
import org.springframework.util.StringUtils;
/**
* @author
* @date 2018-11-23
*/
public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(Class clazz, String field, String val) {
super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), field, val));
}
private static String generateMessage(String entity, String field, String val) {
return StringUtils.capitalize(entity)
+ " with " + field + " "+ val + " does not exist";
}
}

View File

@ -0,0 +1,42 @@
package com.yfd.platform.system.controller;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.datasource.DataSource;
import com.yfd.platform.datasource.DataSourceAspect;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
/**
* @author zhengsl
* @since 2022-09-20
*/
@RestController
@RequestMapping("/system")
@Tag(name = "切换数据库")
public class DataSourceController {
@Resource
DataSourceAspect dataSourceAspect;
/**
* 切换数据库
*
* @DataSource(name="master") 可以通过注解方式切换数据库
*/
@GetMapping("/changeDataSource")
@Operation(summary = "切换数据库")
public ResponseResult changeDataSource(Integer type) {
if (type == null) {
return ResponseResult.error("参数为空");
}
String dataBase = dataSourceAspect.getDataBase(type);
String mess = "已切换为" + dataBase + "数据库";
return ResponseResult.success(mess);
}
}

View File

@ -0,0 +1,238 @@
package com.yfd.platform.system.controller;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWTUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.wf.captcha.base.Captcha;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.config.WebConfig;
import com.yfd.platform.config.bean.LoginCodeEnum;
import com.yfd.platform.config.bean.LoginProperties;
import com.yfd.platform.constant.Constant;
import com.yfd.platform.system.domain.LoginUser;
import com.yfd.platform.system.domain.SysLog;
import com.yfd.platform.system.domain.SysUser;
import com.yfd.platform.system.service.ISysLogService;
import com.yfd.platform.system.service.IUserService;
import com.yfd.platform.utils.RequestHolder;
import com.yfd.platform.utils.RsaUtils;
import com.yfd.platform.utils.StringUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
/**
* @author TangWei
*/
@RestController
@RequestMapping("/user")
@Tag(name = "用户登录")
public class LoginController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private WebConfig webConfig;
@Resource
private IUserService userService;
@Value("${rsa.private_key}")
private String privateKey;
@Resource
private ISysLogService sysLogService;
@Resource
private LoginProperties loginProperties;
@PostMapping("/login")
@Operation(summary = "登录用户")
@ResponseBody
public ResponseResult login(SysUser user) throws Exception {
// 密码解密
String password = RsaUtils.decryptByPrivateKey(privateKey,
user.getPassword());
// 是否需要验证码不需要改成false
boolean hascode = true;
if (hascode) {
// 查询验证码
String code = webConfig.loginuserCache().get(user.getUuid());
// 清除验证码
webConfig.loginuserCache().remove(user.getUuid());
if (StrUtil.isBlank(code)) {
return ResponseResult.error("验证码不存在或已过期");
}
if (StrUtil.isBlank(user.getCode()) || !user.getCode().equalsIgnoreCase(code)) {
return ResponseResult.error("验证码错误");
}
}
//如果认证通过了使用userId生成token token存入ResponseResult返回
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(user.getUsername(),
password);
Authentication authenticate =
authenticationManager.authenticate(authenticationToken);
if (ObjectUtil.isNull(authenticate)) {
return ResponseResult.unlogin();
}
LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
Integer status = loginUser.getUser().getStatus();
if ("0".equals(status.toString())) {
return ResponseResult.error("账号已停用");
}
HttpServletRequest request = RequestHolder.getHttpServletRequest();
SysLog sysLog = new SysLog();
sysLog.setUsercode(user.getUsername());
sysLog.setUsername(loginUser.getUser().getNickname());
sysLog.setRequestip(StringUtils.getIp(request));
sysLog.setBrowser(StringUtils.getBrowser(request));
sysLog.setOpttype("登录(login)");
sysLog.setModule("用户登录");
String className = this.getClass().getName();
String method =
Thread.currentThread().getStackTrace()[1].getMethodName();
sysLog.setMethod(className + "." + method + "()");
//sysLog.setParams(user.toString());
sysLog.setDescription(loginUser.getUser().getNickname() + "登录系统!");
sysLog.setLogtime(new Timestamp(System.currentTimeMillis()));
sysLogService.save(sysLog);
String userId = loginUser.getUser().getId();
Map<String, Object> map = new HashMap<String, Object>(10) {
private static final long serialVersionUID = 1L;
{
put("userid", userId);
put("username", loginUser.getUsername());
long expireTime =
System.currentTimeMillis() + (long) (30L * 24L * 60L * 60L * 1000L);
put("expire_time", expireTime);//个月过期
}
};
String token = JWTUtil.createToken(map, "12345678".getBytes());
map.put("token", token);
//把完整的用户信息存入到HuTool缓存中userId作为key
String jsonStr = JSONUtil.toJsonStr(loginUser);
webConfig.loginuserCache().put("login:" + userId, jsonStr);
webConfig.loginuserCache().put("expire_time:" + userId, map.get("expire_time").toString());
return ResponseResult.successData(map);
}
@Operation(summary = "获取验证码")
@GetMapping(value = "/code")
public ResponseResult getCode() {
// 获取运算的结果
Captcha captcha = loginProperties.getCaptcha();
String uuid = Constant.CODE_KEY + IdUtil.simpleUUID();
//当验证码类型为 arithmetic时且长度 >= 2 captcha.text()的结果有几率为浮点型
String captchaValue = captcha.text();
if (captcha.getCharType() - 1 == LoginCodeEnum.arithmetic.ordinal() && captchaValue.contains(".")) {
captchaValue = captchaValue.split("\\.")[0];
}
// 保存
//redisUtils.set(uuid, captchaValue, loginProperties.getLoginCode()
// .getExpiration(), TimeUnit.MINUTES);
// 将验证码放入缓存设置失效时间为60秒
webConfig.loginuserCache().put(uuid, captchaValue,
Constant.CODE_EXPIRATION_TIME);
// 验证码信息
Map<String, Object> imgResult = new HashMap<String, Object>(2) {{
put("img", captcha.toBase64());
put("uuid", uuid);
}};
return ResponseResult.successData(imgResult);
}
@PostMapping("/logout")
@Operation(summary = "退出登录")
@ResponseBody
public ResponseResult logout() {
//获取SecurityContextHolder中的用户id
UsernamePasswordAuthenticationToken authentication =
(UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
LoginUser loginuser = (LoginUser) authentication.getPrincipal();
String userId = loginuser.getUser().getId();
//删除redis中的登陆用户信息
webConfig.loginuserCache().remove("login:" + userId);
//记录退出日志
HttpServletRequest request = RequestHolder.getHttpServletRequest();
SysLog sysLog = new SysLog();
sysLog.setUsercode(loginuser.getUsername());
sysLog.setUsername(loginuser.getUser().getNickname());
sysLog.setRequestip(StringUtils.getIp(request));
sysLog.setBrowser(StringUtils.getBrowser(request));
sysLog.setOpttype("其他(other)");
sysLog.setModule("注销退出");
sysLog.setDescription("注销退出系统!");
sysLog.setLogtime(new Timestamp(System.currentTimeMillis()));
sysLogService.save(sysLog);
return ResponseResult.success();
}
@Log(module = "用户登录", value = "更改用户密码")
@GetMapping("/updatePassword")
@Operation(summary = "更改用户密码")
@ResponseBody
public ResponseResult updatePassword(@RequestBody SysUser user) throws Exception {
// 密码解密
String password = RsaUtils.decryptByPrivateKey(privateKey,
user.getPassword());
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String cryptPassword = passwordEncoder.encode(password);
UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("password", cryptPassword);
updateWrapper.eq("id", user.getId());
userService.update(updateWrapper);
return ResponseResult.success();
}
@GetMapping("/me")
@Operation(summary = "查询当前用户信息")
@ResponseBody
public ResponseResult getUserInfo() {
ResponseResult responseResult = userService.getLoginUserInfo();
return ResponseResult.successData(responseResult);
}
@Log(module = "用户登录", value = "修改个人信息")
@PostMapping("/updatePersonalInfo")
@Operation(summary = "修改个人信息")
@ResponseBody
public ResponseResult updateUser(@org.springframework.web.bind.annotation.RequestBody SysUser user) {
if (StrUtil.isEmpty(user.getId())) {
return ResponseResult.error("没有用户ID");
}
//填写 当前用户名称
user.setLastmodifier(userService.getUsername());
//填写 当前日期
user.setLastmodifydate(new Timestamp(System.currentTimeMillis()));
boolean ok = userService.updateById(user);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
}

View File

@ -0,0 +1,150 @@
package com.yfd.platform.system.controller;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.MessageConfig;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.config.WebConfig;
import com.yfd.platform.system.domain.Message;
import com.yfd.platform.system.service.IMessageService;
import com.yfd.platform.system.service.IUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.sql.Timestamp;
import java.util.*;
/**
* <p>
* 消息通知 前端控制器
* </p>
*
* @author TangWei
* @since 2023-03-19
*/
@RestController
@RequestMapping("/system/message")
@Tag(name = "消息通知")
public class MessageController {
@Resource
private IMessageService messageService;
@Resource
private MessageConfig messageConfig;
@Operation(summary = "查询消息")
@GetMapping("/getMessageList")
public ResponseResult getMessageList(Page<Message> page,
String status, String title,
String type, String startDate,
String endDate) {
if (StrUtil.isBlank(status)) {
return ResponseResult.error("参数为空");
}
LambdaQueryWrapper<Message> queryWrapper = new LambdaQueryWrapper<>();
if ("0".equals(status)) {
queryWrapper.eq(Message::getStatus, "1");
} else {
List<String> statusList = new ArrayList<>();
statusList.add("2");
statusList.add("9");
queryWrapper.in(Message::getStatus, statusList);
if (StrUtil.isNotBlank(title)) {
queryWrapper.like(Message::getTitle, title);
}
if (StrUtil.isNotBlank(type)) {
queryWrapper.eq(Message::getType, type);
}
DateTime parseStartDate = DateUtil.parse(startDate);
DateTime parseEndDate = DateUtil.parse(endDate);
DateTime dateTime = DateUtil.offsetDay(parseEndDate, 1);
if (parseStartDate != null && parseEndDate != null) {
queryWrapper.ge(Message::getCreatetime, parseStartDate).lt(Message::getCreatetime, dateTime);
}
}
queryWrapper.orderByDesc(Message::getCreatetime);
Page<Message> pageList = messageService.page(page, queryWrapper);
return ResponseResult.successData(pageList);
}
@Operation(summary = "根据ID查询消息")
@GetMapping("/getMessageById")
public ResponseResult getMessageById(String id) {
if (StrUtil.isBlank(id)) {
return ResponseResult.error("参数为空");
}
Message message = messageService.getById(id);
Map<String, Object> map = new HashMap<>();
map.put("title", message.getTitle());
map.put("content", message.getContent());
map.put("createtime", message.getCreatetime());
return ResponseResult.successData(map);
}
@Log(module = "消息通知",value = "根据ID删除消息")
@Operation(summary = "根据ID删除消息")
@PostMapping("/deleteMessageById")
public ResponseResult deleteMessageById(@RequestParam String id) {
if (StrUtil.isBlank(id)) {
return ResponseResult.error("参数为空");
}
String[] split = id.split(",");
List<String> idList = Arrays.asList(split);
boolean ok = messageService.removeByIds(idList);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error("删除失败");
}
}
@Log(module = "消息通知", value = "将消息标记为已阅状态")
@Operation(summary = "标记已阅")
@PostMapping("/setMessageStatus")
public ResponseResult setMessageStatus(@RequestParam String id) {
if (StrUtil.isBlank(id)) {
return ResponseResult.error("参数为空");
}
String[] split = id.split(",");
long time = System.currentTimeMillis();
for (String mid : split) {
Message message = messageService.getById(mid);
if ("9".equals(message.getStatus())) {
continue;
}
message.setStatus("2");
message.setReadtime(new Timestamp(time));
messageService.updateById(message);
}
messageConfig.sendMessage();
return ResponseResult.success();
}
@Operation(summary = "全部已阅")
@PostMapping("/setAllMessageStatus")
public ResponseResult setAllMessageStatus() {
long time = System.currentTimeMillis();
List<Message> list =
messageService.list(new LambdaQueryWrapper<Message>().eq(Message::getStatus, "1"));
for (Message message : list) {
message.setStatus("2");
message.setReadtime(new Timestamp(time));
messageService.updateById(message);
}
messageConfig.sendMessage();
return ResponseResult.success();
}
}

View File

@ -0,0 +1,183 @@
package com.yfd.platform.system.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.QuartzJob;
import com.yfd.platform.system.service.IQuartzJobService;
import com.yfd.platform.system.service.impl.UserServiceImpl;
import com.yfd.platform.utils.QuartzManage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.quartz.CronExpression;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.sql.Timestamp;
import java.time.LocalDateTime;
/**
* <p>
* 定时任务 前端控制器
* </p>
*
* @author TangWei
* @since 2023-03-19
*/
@RestController
@RequestMapping("/system/quartzjob")
@Tag(name = "定时任务")
@Transactional
public class QuartzJobController {
@Resource
private IQuartzJobService quartzJobService;
@Resource
private UserServiceImpl currentUser;
@Resource
private QuartzManage quartzManage;
@Operation(summary = "查询定时任务")
@GetMapping("/getQuartzJobList")
public ResponseResult getQuartzJobList(Page<QuartzJob> page,
String jobName) {
LambdaQueryWrapper<QuartzJob> queryWrapper = new LambdaQueryWrapper<>();
if (StrUtil.isNotBlank(jobName)) {
queryWrapper.like(QuartzJob::getJobName, jobName);
}
queryWrapper.orderByAsc(QuartzJob::getOrderno);
Page<QuartzJob> pageList = quartzJobService.page(page, queryWrapper);
return ResponseResult.successData(pageList);
}
@Log(module = "定时任务管理", value = "新增定时任务")
@Operation(summary = "新增定时任务")
@PostMapping("/addQuartzJob")
public ResponseResult addQuartzJob(@RequestBody QuartzJob quartzJob) {
if (quartzJob == null) {
return ResponseResult.error("参数为空");
}
// 添加最近修改人
quartzJob.setLastmodifier(currentUser.getUsername());
// 添加最近修改时间
quartzJob.setLastmodifydate(new Timestamp(System.currentTimeMillis()));
if (StrUtil.isBlank(quartzJob.getJobCron()) || !CronExpression.isValidExpression(quartzJob.getJobCron())) {
return ResponseResult.error("cron表达式格式错误");
}
quartzJob.setStatus("0");
boolean ok = quartzJobService.addQuartzJob(quartzJob);
quartzManage.addJob(quartzJob);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error("新增失败");
}
}
@Log(module = "定时任务管理", value = "设置定时任务是否有效")
@Operation(summary = "设置定时任务是否有效")
@PostMapping("/setQuartzStatus")
public ResponseResult setQuartzStatus(@RequestParam String id,
@RequestParam String status) {
if (StrUtil.isBlank(id) || StrUtil.isBlank(status)) {
return ResponseResult.error("参数为空");
}
LambdaUpdateWrapper<QuartzJob> updateWrapper =
new LambdaUpdateWrapper<>();
//根据id 更新状态最近修改人最近修改时间
updateWrapper.eq(QuartzJob::getId, id).set(QuartzJob::getStatus,
status).set(
QuartzJob::getLastmodifier, currentUser.getUsername()).set(QuartzJob::getLastmodifydate,
LocalDateTime.now());
boolean ok = quartzJobService.update(updateWrapper);
QuartzJob quartzJob = quartzJobService.getById(id);
if ("0".equals(quartzJob.getStatus())) {
quartzManage.pauseJob(quartzJob);
} else {
quartzManage.resumeJob(quartzJob);
}
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
@Operation(summary = "根据ID查询定时任务")
@GetMapping("/getQuartzJobById")
public ResponseResult getQuartzJobById(String id) {
QuartzJob quartzJob = quartzJobService.getById(id);
return ResponseResult.successData(quartzJob);
}
@Log(module = "定时任务管理", value = "修改定时任务")
@Operation(summary = "修改定时任务")
@PostMapping("/updateQuartzJob")
@Transactional(rollbackFor = Exception.class)
public ResponseResult updateQuartzJob(@RequestBody QuartzJob quartzJob) {
// 添加最近修改人
quartzJob.setLastmodifier(currentUser.getUsername());
// 添加最近修改时间
quartzJob.setLastmodifydate(new Timestamp(System.currentTimeMillis()));
if (StrUtil.isBlank(quartzJob.getJobCron()) || !CronExpression.isValidExpression(quartzJob.getJobCron())) {
return ResponseResult.error("cron表达式格式错误");
}
boolean ok = quartzJobService.updateById(quartzJob);
quartzManage.updateJobCron(quartzJob);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error("修改失败");
}
}
@Log(module = "定时任务管理", value = "删除定时任务")
@Operation(summary = "删除定时任务")
@PostMapping("/deleteQuartzJob")
public ResponseResult deleteQuartzJob(@RequestParam String id) {
if (StrUtil.isBlank(id)) {
return ResponseResult.error("参数为空");
}
boolean ok = quartzJobService.deleteQuartzJob(id);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error("删除失败");
}
}
@Log(module = "定时任务管理", value = "执行定时任务")
@Operation(summary = "执行定时任务")
@PostMapping("/execution")
public ResponseResult execution(@RequestParam String id) {
quartzJobService.execution(quartzJobService.getById(id));
return ResponseResult.success();
}
/**********************************
* 用途说明: 拖动修改定时顺序
* 参数说明 fromID 当前ID toID 到达ID
* 返回值说明: com.yfd.platform.config.ResponseResult 成功或者失败
***********************************/
@Log(module = "定时任务管理", value = "拖动定时任务")
@PostMapping("/changeDictOrder")
@Operation(summary = "拖动修改定时任务顺序")
public ResponseResult changeQuartzOrder(@RequestParam String fromID,
@RequestParam String toID) {
boolean ok = quartzJobService.changeDictOrder(fromID, toID);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
}

View File

@ -0,0 +1,59 @@
package com.yfd.platform.system.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yfd.platform.component.ServerSendEventServer;
import com.yfd.platform.config.WebConfig;
import com.yfd.platform.constant.Constant;
import com.yfd.platform.system.domain.Message;
import com.yfd.platform.system.service.IMessageService;
import com.yfd.platform.system.service.IUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import jakarta.annotation.Resource;
/**
* @author Huhailong
*/
@Slf4j
@RestController
@CrossOrigin
@RequestMapping("/sse")
@Tag(name = "SSE推送服务")
public class SSEController {
@Resource
private IMessageService messageService;
@GetMapping("/connect/{token}")
@Operation(summary = "建立连接")
public SseEmitter connect(@PathVariable String token) {
SseEmitter connect = ServerSendEventServer.connect(token);
long count =
messageService.count(new LambdaQueryWrapper<Message>().eq(Message::getStatus, "1"));
ServerSendEventServer.sendMessage(token, count + "");
return connect;
}
@GetMapping("/sendmsg")
@Operation(summary = "发送消息")
public void sendMessage(String token, String message) throws InterruptedException {
ServerSendEventServer.sendMessage(token, message);
}
@GetMapping("/sendgroupmsg")
@Operation(summary = "多人发送消息")
public void sendgroupmsg(String groupid, String message) throws InterruptedException {
ServerSendEventServer.groupSendMessage(groupid, message);
}
@GetMapping("/disconnect/{token}")
@Operation(summary = "关闭连接")
public void disconnect(@PathVariable String token) throws InterruptedException {
ServerSendEventServer.removeUser(token);
}
}

View File

@ -0,0 +1,68 @@
package com.yfd.platform.system.controller;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.SysConfig;
import com.yfd.platform.system.service.ISysConfigService;
import com.yfd.platform.system.service.IUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.IOException;
import java.sql.Timestamp;
/**
* <p>
* 系统全局配置 前端控制器
* </p>
*
* @author zhengsl
* @since 2022-01-19
*/
@RestController
@RequestMapping("/system/config")
@Tag(name = "系统全局配置")
public class SysConfigController {
@Resource
private ISysConfigService configService;
@Resource
private IUserService userService;
@PostMapping("/getOneById")
@Operation(summary = "根据id查询全局配置详情记录")
@ResponseBody
public SysConfig getOneById(String id){
return configService.getById(id);
}
@PostMapping("/addConfig")
@Operation(summary = "根据id查询全局配置详情记录")
@ResponseBody
public ResponseResult addConfig(@RequestBody SysConfig config ) throws IOException, UnsupportedAudioFileException {
if (StrUtil.isEmpty(config.getId())){
config.setId(IdUtil.fastSimpleUUID()); }
config.setLastmodifier(userService.getUsername());
config.setLastmodifydate(new Timestamp(System.currentTimeMillis()));
boolean ok=configService.save(config);
return ResponseResult.success();
}
@PostMapping("/updateById")
@Operation(summary = "根据id修改全局配置记录")
@ResponseBody
public ResponseResult updateById(@RequestBody SysConfig config) throws IOException, UnsupportedAudioFileException {
config.setLastmodifier(userService.getUsername());
config.setLastmodifydate(new Timestamp(System.currentTimeMillis()));
boolean ok=configService.updateById(config);
return ResponseResult.success();
}
}

View File

@ -0,0 +1,142 @@
package com.yfd.platform.system.controller;
import cn.hutool.core.util.StrUtil;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.SysDictionary;
import com.yfd.platform.system.mapper.SysDictionaryItemsMapper;
import com.yfd.platform.system.service.ISysDictionaryService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
import java.util.Objects;
/**
* <p>
* 数据字典表 前端控制器
* </p>
*
* @author TangWei
* @since 2023-03-08
*/
@RestController
@RequestMapping("/system/dictionary")
@Tag(name = "数据字典")
public class SysDictionaryController {
@Resource
private ISysDictionaryService sysDictionaryService;
/**********************************
* 用途说明: 获取数据字典列表
* 参数说明 dictType 字典类型
* 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果
***********************************/
@GetMapping("/dictList")
@Operation(summary = "获取数据字典列表")
public ResponseResult getDictList(String dictType) {
if (StrUtil.isBlank(dictType)) {
return ResponseResult.error("参数为空");
}
List<SysDictionary> sysDictionaries =
sysDictionaryService.getDictList(dictType);
return ResponseResult.successData(sysDictionaries);
}
/**********************************
* 用途说明: 根据ID删除字典
* 参数说明 id 字典ID
* 返回值说明: com.yfd.platform.config.ResponseResult 返回删除结果成功或者失败
***********************************/
@Log(module = "数据字典", value = "根据ID删除字典")
@PostMapping("/deleteById")
@Operation(summary = "根据ID删除字典")
public ResponseResult deleteDictById(@RequestParam String id) {
boolean ok = sysDictionaryService.deleteDictById(id);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/**********************************
* 用途说明: 新增字典
* 参数说明 sysDictionary 字典对象
* 返回值说明: com.yfd.platform.config.ResponseResult 返回增加成功或者失败
***********************************/
@Log(module = "数据字典", value = "新增数据字典")
@PostMapping("/addDict")
@Operation(summary = "新增字典")
public ResponseResult addDict(@RequestBody SysDictionary sysDictionary) {
if (sysDictionary == null) {
return ResponseResult.error("参数为空");
}
boolean ok = sysDictionaryService.addDict(sysDictionary);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/**********************************
* 用途说明: 修改字典
* 参数说明 sysDictionary 字典对象
* 返回值说明: com.yfd.platform.config.ResponseResult 返回修改成功或者失败
***********************************/
@Log(module = "数据字典", value = "修改数据字典")
@PostMapping("/updateDict")
@Operation(summary = "修改字典")
public ResponseResult updateDict(@RequestBody SysDictionary sysDictionary) {
if (sysDictionary == null) {
return ResponseResult.error("参数为空");
}
boolean ok = sysDictionaryService.updateById(sysDictionary);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/**********************************
* 用途说明: 根据ID查询字典
* 参数说明 sysDictionary 字典对象
* 返回值说明: com.yfd.platform.config.ResponseResult 返回查询结果
***********************************/
@PostMapping("/getDictById")
@Operation(summary = "根据ID查询字典")
public ResponseResult getDictById(String id) {
if (StrUtil.isBlank(id)) {
return ResponseResult.error("参数为空");
}
SysDictionary sysDictionary = sysDictionaryService.getById(id);
return ResponseResult.successData(sysDictionary);
}
/**********************************
* 用途说明: 拖动修改字典顺序
* 参数说明 fromID 当前ID toID 到达ID
* 返回值说明: com.yfd.platform.config.ResponseResult 返回拖动成功或者失败
***********************************/
@Log(module = "数据字典", value = "拖动修改字典顺序")
@PostMapping("/changeDictOrder")
@Operation(summary = "拖动修改字典顺序")
public ResponseResult changeDictOrder(@RequestParam String fromID,
@RequestParam String toID) {
boolean ok = sysDictionaryService.changeDictOrder(fromID, toID);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
}

View File

@ -0,0 +1,201 @@
package com.yfd.platform.system.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.SysDictionaryItems;
import com.yfd.platform.system.mapper.SysDictionaryItemsMapper;
import com.yfd.platform.system.service.ISysDictionaryItemsService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
/**
* <p>
* 数据字典明细 前端控制器
* </p>
*
* @author TangWei
* @since 2023-03-08
*/
@RestController
@RequestMapping("/system/dictionaryItems")
@Tag(name = "数据字典项")
public class SysDictionaryItemsController {
@Resource
private ISysDictionaryItemsService sysDictionaryItemsService;
/**********************************
* 用途说明: 分页查询字典项信息
* 参数说明 dictID 字典ID ItemName 字典项名称 pageNum 当前页
* 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果
***********************************/
@GetMapping("/page")
@Operation(summary = "分页查询字典项信息")
public ResponseResult getDictItemPage(String dictId, String dictName,
Page<SysDictionaryItems> page) {
LambdaQueryWrapper<SysDictionaryItems> queryWrapper =
new LambdaQueryWrapper<>();
queryWrapper.eq(SysDictionaryItems::getDictId, dictId).orderByAsc(SysDictionaryItems::getOrderNo);
// 查询前将序号初始化
List<SysDictionaryItems> list =
sysDictionaryItemsService.list(queryWrapper);
for (int i = 0; i < list.size(); i++) {
SysDictionaryItems sysDictionaryItems = list.get(i);
sysDictionaryItems.setOrderNo(i + 1);
sysDictionaryItemsService.updateById(sysDictionaryItems);
}
Page<SysDictionaryItems> sysDictionaryItemsPage =
sysDictionaryItemsService.getDictItemPage(dictId, dictName,
page);
return ResponseResult.successData(sysDictionaryItemsPage);
}
/**********************************
* 用途说明: 增加字典项
* 参数说明 sysDictionaryItems 字典项信息
* 返回值说明: com.yfd.platform.config.ResponseResult 返回增加成功或者失败
***********************************/
@Log(module = "数据字典项", value = "增加字典项")
@PostMapping("/addDictionaryItem")
@Operation(summary = "增加字典项")
public ResponseResult addDictionaryItem(@RequestBody SysDictionaryItems sysDictionaryItems) {
if (sysDictionaryItems == null) {
return ResponseResult.error("参数为空");
}
boolean ok =
sysDictionaryItemsService.addDictionaryItem(sysDictionaryItems);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/**********************************
* 用途说明: 修改字典项
* 参数说明 sysDictionaryItems 字典项信息
* 返回值说明: com.yfd.platform.config.ResponseResult 返回修改成功或者失败
***********************************/
@Log(module = "数据字典项", value = "修改字典项")
@PostMapping("/updateDictionaryItem")
@Operation(summary = "修改字典项")
public ResponseResult updateDictionaryItem(@RequestBody SysDictionaryItems sysDictionaryItems) {
if (sysDictionaryItems == null) {
return ResponseResult.error("参数为空");
}
boolean ok =
sysDictionaryItemsService.updateById(sysDictionaryItems);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/**********************************
* 用途说明: 根据ID查询字典项
* 参数说明 id 字典项ID
* 返回值说明: com.yfd.platform.config.ResponseResult 返回字典项信息
***********************************/
@GetMapping("/getDictItemById")
@Operation(summary = "根据ID查询字典项")
public ResponseResult getDictItemById(String id) {
if (StrUtil.isBlank(id)) {
return ResponseResult.error("参数为空");
}
SysDictionaryItems sysDictionaryItems =
sysDictionaryItemsService.getById(id);
return ResponseResult.successData(sysDictionaryItems);
}
/**********************************
* 用途说明: 根据ID删除字典项
* 参数说明 id 字典项ID
* 返回值说明: com.yfd.platform.config.ResponseResult 返回删除成功或者失败
***********************************/
@Log(module = "数据字典项", value = "根据ID删除字典项")
@PostMapping("/deleteDictItemById")
@Operation(summary = "根据ID删除字典项")
public ResponseResult deleteDictItemById(@RequestParam String id) {
if (StrUtil.isBlank(id)) {
return ResponseResult.error("参数为空");
}
boolean ok = sysDictionaryItemsService.removeById(id);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/**********************************
* 用途说明: 批量删除字典项
* 参数说明 ids 字典项id数组
* 返回值说明: com.yfd.platform.config.ResponseResult 返回批量删除成功或失败
***********************************/
@Log(module = "数据字典项", value = "批量删除字典项")
@PostMapping("/deleteDictItemByIds")
@Operation(summary = "批量删除字典项")
public ResponseResult deleteDictItemByIds(@RequestParam String id) {
if (StrUtil.isBlank(id)) {
return ResponseResult.error("参数为空");
}
String[] splitIds = id.split(",");
// 数组转集合
List<String> ids = Arrays.asList(splitIds);
boolean ok = sysDictionaryItemsService.removeByIds(ids);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/**********************************
* 用途说明: 拖动修改字典项顺序
* 参数说明 fromID 当前ID toID 到达ID
* 返回值说明: com.yfd.platform.config.ResponseResult 返回拖动成功或者失败
***********************************/
@Log(module = "数据字典项", value = "拖动修改字典项顺序")
@PostMapping("/changeItemOrder")
@Operation(summary = "拖动修改字典项顺序")
public ResponseResult changeItemOrder(@RequestParam String fromID,
@RequestParam String toID) {
boolean ok = sysDictionaryItemsService.changeItemOrder(fromID, toID);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/**********************************
* 用途说明: 导出数据字典项数据
* 参数说明 sysDictionaryItemsList 所需导出的字典项集合
* 返回值说明: com.yfd.platform.config.ResponseResult 返回导出成功或失败
***********************************/
@Log(module = "数据字典项", value = "导出字典数据到Excel")
@GetMapping("/exportExcel")
@Operation(summary = "导出数据字典项数据")
public void exportExcel(String dictID, String itemName,
Page<SysDictionaryItems> page,
HttpServletResponse response) {
Page<SysDictionaryItems> sysDictionaryItemsPage =
sysDictionaryItemsService.getDictItemPage(dictID, itemName,
page);
sysDictionaryItemsService.exportExcel(sysDictionaryItemsPage.getRecords(), response);
}
}

View File

@ -0,0 +1,74 @@
package com.yfd.platform.system.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.SysLog;
import com.yfd.platform.system.service.ISysLogService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* <p>
* 系统操作日志 前端控制器
* </p>
*
* @author TangWei
* @since 2023-03-08
*/
@RestController
@RequestMapping("/system/log")
@Tag(name = "系统日志")
public class SysLogController {
@Resource
private ISysLogService sysLogService;
/**********************************
* 用途说明: 分页查询日志信息
* 参数说明 page分页对象username用户名(optType)
* 操作类型startDate(开始日期)endDate结束日期
* 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果
***********************************/
@PostMapping("/getLogList")
@Operation(summary = "分页查询日志信息")
public ResponseResult getLogList(String username, String optType,
String startDate,
String endDate, Page<SysLog> page) {
Page<SysLog> sysLogPage = sysLogService.getLogList(username, optType,
startDate, endDate, page);
Map<String, Object> map = new HashMap<>();
map.put("list", sysLogPage.getRecords());
map.put("total", sysLogPage.getTotal());
map.put("size", sysLogPage.getSize());
map.put("current", sysLogPage.getCurrent());
return ResponseResult.successData(map);
}
/**********************************
* 用途说明: 导出日志数据
* 参数说明 sysLogs 所需导出的字典项集合
* 返回值说明: com.yfd.platform.config.ResponseResult 返回导出成功或者失败
***********************************/
@Log(module = "系统日志", value = "导出系统日志到Excel")
@GetMapping("/exportExcel")
@Operation(summary = "导出日志数据")
public void exportExcel(String username, String optType,
String startDate,
String endDate, Page<SysLog> page,
HttpServletResponse response) throws IOException {
Page<SysLog> sysLogPage = sysLogService.getLogList(username, optType,
startDate, endDate, page);
sysLogService.exportExcel(sysLogPage.getRecords(), response);
}
}

View File

@ -0,0 +1,308 @@
package com.yfd.platform.system.controller;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.SysMenu;
import com.yfd.platform.system.domain.SysUser;
import com.yfd.platform.system.service.ISysMenuService;
import com.yfd.platform.system.service.IUserService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.apache.catalina.User;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import java.io.File;
import java.io.FileNotFoundException;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* <p>
* 菜单及按钮 前端控制器
* </p>
*
* @author zhengsl
* @since 2021-12-15
*/
@RestController
@RequestMapping("/system/menu")
@Tag(name = "菜单及按钮")
public class SysMenuController {
@Resource
private ISysMenuService sysMenuService;
@Resource
private IUserService userService;
// 菜单图片路径通过服务层配置获取无需在控制器注入
/***********************************
* 用途说明获取菜单结构树含按钮
* 参数说明
* systemcode 系统
* name 名称
* isdisplay 是否显示
* 返回值说明: 菜单结构树集合
***********************************/
@PostMapping("/getMenuButtonTree")
@Operation(summary = "获取菜单结构树(含按钮)")
@ResponseBody
public List<Map<String, Object>> getMenuButtonTree(String systemcode,
String name,
String isdisplay) {
return sysMenuService.getMenuButtonTree(systemcode, name, isdisplay);
}
/***********************************
* 用途说明获取菜单结构树不含按钮
* 参数说明
* systemcode 系统
* name 名称
* isdisplay 是否显示
* 返回值说明: 菜单结构树集合
***********************************/
@PostMapping("/getMenuTree")
@Operation(summary = "获取菜单结构树(不含按钮)")
@ResponseBody
public List<Map<String, Object>> getMenuTree(String systemcode,
String name,
String isdisplay) {
return sysMenuService.getMenuTree(systemcode, name, isdisplay);
}
/***********************************
* 用途说明权限分配
* 参数说明
* systemcode 系统
* name 名称
* isdisplay 是否显示
* 返回值说明: 菜单结构树集合
***********************************/
@PostMapping("/permissionAssignment")
@Operation(summary = "获取分配权限(不含按钮)")
@ResponseBody
public List<Map<String, Object>> permissionAssignment(String roleId) {
return sysMenuService.permissionAssignment(roleId);
}
/**********************************
* 用途说明: 获取当前用户菜单结构树
* 参数说明
* 返回值说明: java.util.List<com.yfd.platform.system.domain.SysMenu>
***********************************/
@GetMapping("/treeRoutes")
@Operation(summary = "获取当前用户菜单结构树")
@ResponseBody
public List<Map<String, Object>> getMenuTreeByUser() {
SysUser userInfo = userService.getUserInfo();
String id = "";
if (0 != userInfo.getUsertype()) {
id = userInfo.getId();
}
return sysMenuService.getMenuTree(id);
}
/***********************************
* 用途说明根据id查询菜单或按钮详情
* 参数说明
* id 菜单或按钮表id
* 返回值说明: 菜单或按钮表对象
***********************************/
@PostMapping("/getOneById")
@Operation(summary = "根据id查询菜单或按钮详情")
@ResponseBody
public ResponseResult getOneById(String id) {
SysMenu sysMenu = sysMenuService.getById(id);
return ResponseResult.successData(sysMenu);
}
/***********************************
* 用途说明新增菜单及按钮
* 参数说明
* sysMenu 菜单或按钮表对象
* 返回值说明: 是否添加成功提示
***********************************/
@Log(module = "菜单及按钮", value = "新增菜单及按钮!")
@PostMapping("/addMenu")
@Operation(summary = "新增菜单及按钮")
@ResponseBody
public ResponseResult addMenu(@RequestBody SysMenu sysMenu) {
boolean isOk = sysMenuService.addMenu(sysMenu);
if (isOk) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明修改菜单及按钮
* 参数说明
* sysMenu 菜单或按钮表对象
* 返回值说明: 是否修改成功提示
***********************************/
@Log(module = "菜单及按钮", value = "修改菜单及按钮")
@PostMapping("/updateById")
@Operation(summary = "修改菜单及按钮")
@ResponseBody
public ResponseResult updateById(@RequestBody SysMenu sysMenu) {
sysMenu.setLastmodifier(userService.getUsername());
sysMenu.setLastmodifydate(new Timestamp(System.currentTimeMillis()));
boolean isOk = sysMenuService.updateById(sysMenu);
if (isOk) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明根据id删除单个图标
* 参数说明
* id 删除图标id
* icon 图标名称
* 返回值说明: 是否删除成功
***********************************/
@Log(module = "菜单及按钮", value = "根据id删除单个图标")
@PostMapping("/deleteIcon")
@Operation(summary = "根据id删除单个图标")
@ResponseBody
public ResponseResult deleteIcon(@RequestParam String id) {
boolean ok = sysMenuService.deleteIcon(id);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明更新菜单及按钮是否有效
* 参数说明
* id 菜单及按钮表id
* isdisplay 是否有效字段
* 返回值说明: 是否更新成功
***********************************/
@Log(module = "菜单及按钮", value = "更新菜单及按钮是否有效!")
@PostMapping("/setIsDisplay")
@Operation(summary = "更新菜单及按钮是否有效")
@ResponseBody
public ResponseResult setIsDisplay(String id, String isdisplay) {
UpdateWrapper<SysMenu> updateWrapper = new UpdateWrapper<>();
//根据id 修改是否显示 最近修改人最近修改时间
updateWrapper.eq("id", id).set("isdisplay", isdisplay).set(
"lastmodifier", userService.getUsername()).set(
"lastmodifydate",
new Timestamp(System.currentTimeMillis()));
boolean ok = sysMenuService.update(updateWrapper);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明菜单及按钮序号排序
* 参数说明
* parentid 上级id
* orderMap map<菜单及按钮表id,排列序号>
* 返回值说明: 是否更新成功
***********************************/
@Log(module = "菜单及按钮", value = "菜单及按钮序号排序!")
@PostMapping("/moveOrderno")
@Operation(summary = "菜单及按钮序号排序")
@ResponseBody
public ResponseResult moveOrderno(@RequestParam String parentid,
@RequestParam String id,
@RequestParam int orderno) {
boolean ok = sysMenuService.moveOrderno(parentid, id, orderno);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明根据id删除菜单或按钮
* 参数说明
* id 删除列的id
* 返回值说明: 是否删除成功
***********************************/
@Log(module = "菜单及按钮", value = "根据id删除菜单或按钮")
@PostMapping("/deleteById")
@Operation(summary = "根据id删除菜单或按钮")
@ResponseBody
public ResponseResult deleteById(@RequestParam String id) {
boolean ok = sysMenuService.deleteById(id);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/**********************************
* 用途说明: 菜单或者按钮拖动
* 参数说明 id
* 参数说明 id1
* 返回值说明: com.yfd.platform.config.ResponseResult
***********************************/
@Log(module = "菜单及按钮", value = "拖动修改菜单或按钮同级顺序!")
@PostMapping("/changeMenuOrder")
@Operation(summary = "菜单或按钮切换")
@ResponseBody
public ResponseResult changeMenuOrder(@RequestParam String fromId,
@RequestParam String toId) {
if (StrUtil.isBlank(fromId) || StrUtil.isBlank(toId)) {
return ResponseResult.error("参数为空!");
}
if (fromId.equals(toId)) {
return ResponseResult.error("切换失败!");
}
boolean ok = sysMenuService.changeOderNoById(fromId, toId);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明上传单个图标
* 参数说明
* icon 图标
* 返回值说明: 是否上传成功
***********************************/
@PostMapping("/uploadIcon")
@Operation(summary = "上传单个图标")
@ResponseBody
public ResponseResult uploadIcon(MultipartFile icon, String menuId) throws FileNotFoundException {
if (StrUtil.isNotBlank(menuId)) {
SysMenu sysMenu = sysMenuService.getById(menuId);
//图片路径
String iconname =
System.getProperty("user.dir") + "\\src\\main" +
"\\resources\\static\\icon" + File.separator + sysMenu.getIcon();
//删除图标
new File(iconname).delete();
}
String filename = sysMenuService.uploadIcon(icon);
SysMenu sysMenu = new SysMenu();
sysMenu.setId(menuId);
sysMenu.setIcon(filename);
sysMenuService.updateById(sysMenu);
return ResponseResult.successData(filename);
}
}

View File

@ -0,0 +1,210 @@
package com.yfd.platform.system.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.SysOrganization;
import com.yfd.platform.system.domain.SysRole;
import com.yfd.platform.system.domain.SysUser;
import com.yfd.platform.system.mapper.SysRoleMapper;
import com.yfd.platform.system.service.ISysOrganizationService;
import com.yfd.platform.system.service.IUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* <p>
* 系统组织框架 前端控制器
* </p>
*
* @author zhengsl
* @since 2021-12-15
*/
@RestController
@RequestMapping("/system/organization")
@Tag(name = "系统组织框架")
public class SysOrganizationController {
@Resource
private ISysOrganizationService organizationService;
@Resource
private IUserService userService;
/***********************************
* 用途说明获取组织范围树结构
* 参数说明
*parentid 上级id
* params 名称根据名称查询二级
* 返回值说明: 组织树集合
***********************************/
@PostMapping("/getOrgScopeTree")
@Operation(summary = "获取组织范围树结构")
@ResponseBody
public List<Map<String, Object>> getOrgScopeTree(String roleId) {
return organizationService.getOrgScopeTree(roleId);
}
/***********************************
* 用途说明获取组织范围
* 参数说明
* 返回值说明: 组织范围集合
***********************************/
@PostMapping("/getOrgTree")
@Operation(summary = "获取组织结构树")
@ResponseBody
public List<Map<String, Object>> getOrgTree(String parentid,
String params) {
return organizationService.getOrgTree(parentid, params);
}
/***********************************
* 用途说明根据企业ID查询组织详情
* 参数说明
* id 企业id
* 返回值说明: 系统组织框架对象
***********************************/
@PostMapping("/getOrganizationById")
@Operation(summary = "根据企业ID查询组织信息")
@ResponseBody
public ResponseResult getOrganizationById(String id, String orgName) {
if (StrUtil.isBlank(id)) {
return ResponseResult.error("查询失败!");
}
List<SysOrganization> sysOrganizations =
organizationService.getOrganizationById(id, orgName);
return ResponseResult.successData(sysOrganizations);
}
/***********************************
* 用途说明根据ID查询组织详情
* 参数说明
* id 系统组织id
* 返回值说明: 系统组织框架对象
***********************************/
@PostMapping("/getOneById")
@Operation(summary = "根据ID查询组织详情")
@ResponseBody
public ResponseResult getOneById(String id) {
SysOrganization sysOrganization = organizationService.getById(id);
return ResponseResult.successData(sysOrganization);
}
/***********************************
* 用途说明新增系统组织框架
* 参数说明
* sysOrganization 系统组织框架对象
* 返回值说明: 是否新增成功
***********************************/
@Log(module = "系统组织框架", value = "新增企业或者部门!")
@PostMapping("/addOrg")
@Operation(summary = "新增系统组织框架")
@ResponseBody
public ResponseResult addOrg(@RequestBody SysOrganization sysOrganization) {
//判断是否是否填写 有效 否则默认为 1
if (StrUtil.isEmpty(sysOrganization.getIsvaild())) {
sysOrganization.setIsvaild("1");
}
//填写 当前用户名称
sysOrganization.setLastmodifier(userService.getUsername());
//填写 当前日期
sysOrganization.setLastmodifydate(new Timestamp(System.currentTimeMillis()));
//新增 系统组织R
boolean isOk = organizationService.addOrg(sysOrganization);
if (isOk) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明修改系统组织框架
* 参数说明
* sysOrganization 系统组织框架对象
* 返回值说明: 是否修改成功
***********************************/
@Log(module = "系统组织框架", value = "修改企业或者部门信息!")
@PostMapping("/updateById")
@Operation(summary = "修改系统组织框架")
@ResponseBody
public ResponseResult updateById(@RequestBody SysOrganization sysOrganization) {
//填写 当前用户名称
sysOrganization.setLastmodifier(userService.getUsername());
//填写 当前日期
sysOrganization.setLastmodifydate(new Timestamp(System.currentTimeMillis()));
//根据id 修改系统组织
boolean isOk = organizationService.updateById(sysOrganization);
if (isOk) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明修改系统组织框架
* 参数说明
* sysOrganization 系统组织框架对象
* 返回值说明: 是否修改成功
***********************************/
@Log(module = "系统组织框架", value = "设置企业/部门是否有效!")
@PostMapping("/setIsValid")
@Operation(summary = "设置组织是否有效")
@ResponseBody
public ResponseResult setIsValid(@RequestParam String id,
@RequestParam String isvaild) {
UpdateWrapper<SysOrganization> updateWrapper = new UpdateWrapper<>();
//根据id 修改是否有效最近修改人最近修改时间
updateWrapper.eq("id", id).set("isvaild", isvaild).set("lastmodifier"
, userService.getUsername()).set("lastmodifydate",
new Timestamp(System.currentTimeMillis()));
boolean isOk = organizationService.update(updateWrapper);
if (isOk) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明根据id删除系统组织框架
* 参数说明
* id 系统组织框架id
* 返回值说明: 是否删除成功
***********************************/
@Log(module = "系统组织框架", value = "根据ID删除企业或者部门")
@PostMapping("/deleteById")
@Operation(summary = "根据id删除系统组织框架")
@ResponseBody
public ResponseResult deleteById(@RequestParam String id) {
String[] orgIds = id.split(",");
for (String orgId : orgIds) {
LambdaQueryWrapper<SysOrganization> queryWrapper =
new LambdaQueryWrapper<>();
List<SysOrganization> list =
organizationService.list(queryWrapper.eq(SysOrganization::getParentid, orgId));
List<String> ids =
list.stream().map(SysOrganization::getId).collect(Collectors.toList());
boolean isOk = organizationService.removeById(orgId);
if (!isOk) {
continue;
}
for (String oid : ids) {
organizationService.removeById(oid);
}
}
return ResponseResult.success();
}
}

View File

@ -0,0 +1,324 @@
package com.yfd.platform.system.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.SysRole;
import com.yfd.platform.system.service.ISysRoleService;
import com.yfd.platform.system.service.IUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* <p>
* 系统角色 前端控制器
* </p>
*
* @author zhengsl
* @since 2021-12-15
*/
@RestController
@RequestMapping("/system/role")
@Tag(name = "系统角色")
public class SysRoleController {
@Resource
private ISysRoleService roleService;
@Resource
private IUserService userService;
/***********************************
* 用途说明查询所有角色
* 参数说明
* roleName 角色名称
* 返回值说明: 查询都有角色
***********************************/
@PostMapping("/list")
@Operation(summary = "查询所有角色")
@ResponseBody
public List<SysRole> list(String rolename) {
QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
if (StrUtil.isNotEmpty(rolename)) {
//根据角色名称模糊查询
queryWrapper.like("rolename", rolename);
}
//根据角色级别角色编号 正序排序
queryWrapper.ne("level", "1").orderByAsc("level", "lastmodifydate");
return roleService.list(queryWrapper);
}
/***********************************
* 用途说明根据Id获取当个角色
* 参数说明
* id 角色表id
* 返回值说明: 根据id查询到角色详情
***********************************/
@PostMapping("/getOneById")
@Operation(summary = "根据Id获取当个角色")
@ResponseBody
public ResponseResult getOneById(String id) {
SysRole sysRole = roleService.getById(id);
return ResponseResult.successData(sysRole);
}
/***********************************
* 用途说明新增角色
* 参数说明
* sysRole 新增角色信息
* 返回值说明: 是否新增成功
***********************************/
@Log(module = "系统角色", value = "新增角色")
@PostMapping("/addRole")
@Operation(summary = "新增角色")
@ResponseBody
public ResponseResult addRole(@RequestBody SysRole sysRole) {
boolean isOk = roleService.addRole(sysRole);
if (isOk) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明分配操作权限
* 参数说明
* id 角色id
* optscope 分配的权限
* 返回值说明: 是否新增成功
***********************************/
@Log(module = "系统角色", value = "分配操作权限")
@PostMapping("/setOptScope")
@Operation(summary = "分配操作权限")
@ResponseBody
public ResponseResult setOptScope(@RequestParam String id,
@RequestParam String optscope) {
UpdateWrapper<SysRole> updateWrapper = new UpdateWrapper<>();
//根据id 更新权限最近修改人最近修改时间
updateWrapper.eq("id", id).set("optscope", optscope).set(
"lastmodifier", userService.getUsername()).set(
"lastmodifydate", LocalDateTime.now());
boolean ok = roleService.update(updateWrapper);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明角色菜单权限
* 参数说明
* id 角色id
* menuIds 权限id字符串
* 返回值说明: 是否分配成功
***********************************/
@Log(module = "系统角色", value = "角色菜单权限")
@PostMapping("/setMenuById")
@Operation(summary = "角色菜单权限")
@ResponseBody
public ResponseResult setMenuById(String id, String menuIds) {
if (StrUtil.isBlank(id)) {
return ResponseResult.error("参数为空");
}
if (StrUtil.isBlank(menuIds)) {
return ResponseResult.success();
}
boolean ok = roleService.setMenuById(id, menuIds);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明设置组织范围
* 参数说明
* id 角色id
* orgscope 组织范围
* 返回值说明: 是否新增成功
***********************************/
@Log(module = "系统角色", value = "设置组织范围")
@PostMapping("/setOrgscope")
@Operation(summary = "设置组织范围")
@ResponseBody
public ResponseResult setOrgscope(@RequestParam String id,
@RequestParam String orgscope) {
UpdateWrapper<SysRole> updateWrapper = new UpdateWrapper<>();
//根据id 更新组织范围最近修改人最近修改时间
updateWrapper.eq("id", id).set("orgscope", orgscope).set(
"lastmodifier", userService.getUsername()).set(
"lastmodifydate", LocalDateTime.now());
boolean ok = roleService.update(updateWrapper);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明设置业务范围
* 参数说明
* id 角色id
* busscope 业务范围
* 返回值说明: 是否新增成功
***********************************/
@Log(module = "系统角色", value = "设置业务范围")
@PostMapping("/setBusscope")
@Operation(summary = "设置业务范围")
@ResponseBody
public ResponseResult setBusscope(@RequestParam String id,
@RequestParam String busscope) {
UpdateWrapper<SysRole> updateWrapper = new UpdateWrapper<>();
//根据id 更新业务范围最近修改人最近修改时间
updateWrapper.eq("id", id).set("busscope", busscope).set(
"lastmodifier", userService.getUsername()).set(
"lastmodifydate", LocalDateTime.now());
boolean ok = roleService.update(updateWrapper);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明角色添加用户
* 参数说明
* roleid 角色id
* userids 用户id组
* 返回值说明: 是否新增成功
***********************************/
@Log(module = "系统角色", value = "角色添加用户")
@PostMapping("/setRoleUsers")
@Operation(summary = "角色添加用户")
@ResponseBody
public ResponseResult setRoleUsers(String roleid, String userids) {
boolean isOk = true;
String[] temp = userids.split(",");
for (String userid : temp) {
isOk = isOk && userService.addUserRoles(roleid, userid);
}
if (isOk) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明删除角色用户
* 参数说明
* roleid 角色id
* 返回值说明: 是否新增成功
***********************************/
@PostMapping("/deleteRoleUser")
@Operation(summary = "删除角色用户")
@ResponseBody
public ResponseResult deleteRoleUsers(@RequestParam String roleid,
@RequestParam String userids) {
//根据角色id用户id删除
boolean ok = roleService.deleteRoleUsers(roleid, userids);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明设置角色是否有效
* 参数说明
* id 角色id
*isvaild 是否有效1 0
* 返回值说明: 是否新增成功
***********************************/
@PostMapping("/setIsvaild")
@Operation(summary = "设置角色是否有效")
@ResponseBody
public ResponseResult setIsvaild(String id, String isvaild) {
UpdateWrapper<SysRole> updateWrapper = new UpdateWrapper<>();
//根据id 更新业务范围最近修改人最近修改时间
updateWrapper.eq("id", id).set("isvaild", isvaild).set("lastmodifier"
, userService.getUsername()).set("lastmodifydate",
LocalDateTime.now());
boolean ok = roleService.update(updateWrapper);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明更新角色信息
* 参数说明
*sysRole 角色对象
* 返回值说明: 是否修改成功
***********************************/
@PostMapping("/updateById")
@Operation(summary = "更新角色信息")
@ResponseBody
public ResponseResult updateById(@RequestBody SysRole sysRole) {
//更新最近修改人
sysRole.setLastmodifier(userService.getUsername());
//更新最近修改时间
sysRole.setLastmodifydate(new Timestamp(System.currentTimeMillis()));
//根据id更新角色信息
boolean ok = roleService.updateById(sysRole);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明根据id删除角色
* 参数说明
*id 角色id
* 返回值说明: 是否删除成功
***********************************/
@PostMapping("/deleteById")
@Operation(summary = "根据id删除角色")
@ResponseBody
public ResponseResult deleteById(@RequestParam String id) {
roleService.deleteById(id);
return ResponseResult.success();
}
/***********************************
* 用途说明查询已分配的用户
* 参数说明
*orgid 所属组织
*username 用户名称
*status 状态
*level 角色级别
* rolename 角色名称
* isvaild 角色是否有效
* 返回值说明: 系统用户角色数据集合
***********************************/
@PostMapping("/listRoleUsers")
@Operation(summary = "查询已分配的用户")
@ResponseBody
public List<Map> listRoleUsers(String orgid, String username,
String status, String level,
String rolename, String isvaild) {
return roleService.listRoleUsers(orgid, username, status, level,
rolename, isvaild);
}
}

View File

@ -0,0 +1,188 @@
package com.yfd.platform.system.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.datasource.DataSource;
import com.yfd.platform.system.domain.SysUser;
import com.yfd.platform.system.service.IUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import java.sql.Timestamp;
import java.util.Map;
/**
* <p>
* 用户信息 前端控制器
* </p>
*
* @author zhengsl
* @since 2022-09-20
*/
@RestController
@RequestMapping("/system/user")
@Tag(name = "系统用户")
public class UserController {
@Resource
private IUserService userService;
@Log(module = "系统用户", value = "新增系统用户")
@PostMapping("/addUser")
@Operation(summary = "新增系统用户")
@ResponseBody
public ResponseResult addUser(@RequestBody SysUser user, String roleids) {
Map reslut = userService.addUser(user, roleids);
return ResponseResult.successData(reslut);
}
@Log(module = "系统用户", value = "修改用户信息")
@PostMapping("/updateUser")
@Operation(summary = "修改用户信息")
@ResponseBody
public ResponseResult updateUser(@RequestBody SysUser user,
String roleids) {
if (StrUtil.isEmpty(user.getId())) {
return ResponseResult.error("没有用户ID");
}
//填写 当前用户名称
user.setLastmodifier(userService.getUsername());
//填写 当前日期
user.setLastmodifydate(new Timestamp(System.currentTimeMillis()));
Map reslut = userService.updateById(user, roleids);
return ResponseResult.successData(reslut);
}
@GetMapping("/queryUsers")
@Operation(summary = "查询用户信息")
@ResponseBody
public ResponseResult queryUsers(String orgid,
String username, Page<SysUser> page) {
Page<Map<String, Object>> mapPage = userService.queryUsers(orgid,
username, page);
return ResponseResult.successData(mapPage);
}
/***********************************
* 用途说明用户分配角色
* 参数说明
*idMap 用户id与角色id
* 返回值说明: 判断是否添加成功
************************************/
@Log(module = "系统用户", value = "用户分配角色")
@PostMapping("/setUserRoles")
@Operation(summary = "用户分配角色")
@ResponseBody
public ResponseResult setUserRoles(String roleid, String userids) {
boolean ok = userService.setUserRoles(roleid, userids);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明根据id删除用户
* 参数说明
*id 用户id
* 返回值说明: 判断是否删除成功
************************************/
@Log(module = "系统用户", value = "根据ID删除用户")
@PostMapping("/deleteById")
@Operation(summary = "根据ID删除用户")
@ResponseBody
public ResponseResult deleteById(String id) {
userService.deleteById(id);
return ResponseResult.success();
}
/***********************************
* 用途说明根据ID批量删除用户
* 参数说明
*ids 用户id集合
* 返回值说明: 判断是否删除成功
************************************/
@Log(module = "系统用户", value = "根据ID批量删除用户")
@PostMapping("/deleteUserByIds")
@Operation(summary = "根据ID批量删除用户")
@ResponseBody
public ResponseResult deleteUserByIds(String id) {
if (StrUtil.isBlank(id)) {
return ResponseResult.error("参数为空");
}
boolean ok = userService.deleteUserByIds(id);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明重置用户密码(管理员)
* 参数说明
*id 重置密码的 用户id
* 返回值说明: 判断是否重置成功
************************************/
@Log(module = "系统用户", value = "重置用户密码")
@PostMapping("/resetPassword")
@Operation(summary = "重置用户密码")
@ResponseBody
@DataSource
public ResponseResult resetPassword(String id) throws Exception {
if (StrUtil.isBlank(id)) {
ResponseResult.error("参数为空");
}
boolean ok = userService.resetPassword(id);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明设置账号状态(管理员)
* 参数说明
*id 用户id
* status 设置状态
* 返回值说明: 判断是否设置成功
************************************/
@Log(module = "系统用户", value = "设置账号状态")
@PostMapping("/setStatus")
@Operation(summary = "设置账号状态")
@ResponseBody
public ResponseResult setStatus(@RequestParam String id,
@RequestParam String status) {
boolean ok = userService.setStatus(id, status);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
}
/***********************************
* 用途说明修改头像(管理员)
* 参数说明
* multipartFile 文件对象
* status 设置状态
* 返回值说明: 文件名
************************************/
@Operation(summary = "修改头像")
@PostMapping(value = "/updateAvatar")
public ResponseResult updateAvatar(String id, MultipartFile multipartFile) {
if (multipartFile == null) {
ResponseResult.error("参数为空");
}
boolean ok = userService.uploadAvatar(id, multipartFile);
return ResponseResult.success();
}
}

View File

@ -0,0 +1,78 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
* <p>
* 数据字典表
* </p>
*
* @author zhengsl
* @since 2021-10-27
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("rca_dictionary")
public class Dictionary implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 类型
*/
private String type;
/**
* 类型名称
*/
private String typename;
/**
* 代码
*/
private String code;
/**
* 名称
*/
private String name;
/**
* 顺序号
*/
private String orderno;
/**
* 上级代码
*/
private String parentcode;
/**
* 备用1
*/
private String custom1;
/**
* 备用2
*/
private String custom2;
/**
* 备用3
*/
private String custom3;
}

View File

@ -0,0 +1,76 @@
package com.yfd.platform.system.domain;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoginUser implements UserDetails {
private SysUser user;
private List<String> permissions;
public LoginUser(SysUser user, List<String> permissions) {
this.user = user;
this.permissions = permissions;
}
@JSONField(serialize = false)
private List<SimpleGrantedAuthority> authorities;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// 将权限信息放入集合
authorities = permissions.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
return authorities;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
//获取用户昵称
public String geNickname() {
return user.getNickname();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}

View File

@ -0,0 +1,117 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 消息通知
* </p>
*
* @author TangWei
* @since 2023-03-19
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_message")
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId(type = IdType.ASSIGN_UUID)
@Schema(description = "ID")
private String id;
/**
* 创建时间排序
*/
@Schema(description = "创建时间:排序")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp createtime;
/**
* 消息类型1-定时任务 2-工作流触发 3-人工触发
*/
@Schema(description = "消息类型1-定时任务 2-工作流触发 3-人工触发")
private String type;
/**
* 消息标题
*/
@Schema(description = "消息标题")
private String title;
/**
* 消息内容
*/
@Schema(description = "消息内容")
private String content;
/**
* 发送者名称定时器人员
*/
@Schema(description = "发送者名称,定时器,人员")
private String senderName;
/**
* 接收者代码 人员账号列表
*/
@Schema(description = "接收者代码 人员账号列表 ")
private String receiverCodes;
/**
* 接收者名称为空 即为所有人人员名称列表
*/
@Schema(description = "接收者名称:为空 即为所有人,人员名称列表")
private String receiverNames;
/**
* 状态1初始创建 2-消息已阅 9-消息过期
*/
@Schema(description = "状态1、初始创建 2-消息已阅 9-消息过期")
private String status;
/**
* 有效期小时
*/
@Schema(description = "有效期:小时")
private Integer validperiod;
/**
* 已阅时间
*/
@Schema(description = "已阅时间")
private Timestamp readtime;
/**
* 备用1
*/
@Schema(description = "备用1")
private String custom1;
/**
* 备用2
*/
@Schema(description = "备用2")
private String custom2;
/**
* 备用3
*/
@Schema(description = "备用3")
private String custom3;
}

View File

@ -0,0 +1,118 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 定时任务
* </p>
*
* @author TangWei
* @since 2023-03-19
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_quartz_job")
public class QuartzJob implements Serializable {
public static final String JOB_KEY = "JOB_KEY";
private static final long serialVersionUID = 1L;
/**
* ID
*/
@Schema(description = "ID")
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 排序号
*/
@Schema(description = "排序号")
private Integer orderno;
/**
* 任务名称
*/
@Schema(description = "任务名称")
private String jobName;
/**
* 执行类名称
*/
@Schema(description = "执行类名称")
private String jobClass;
/**
* 执行方法名称
*/
@Schema(description = "执行方法名称")
private String jobMethod;
/**
* 时间周期表达式
*/
@Schema(description = "时间周期表达式")
private String jobCron;
/**
* 方法参数
*/
@Schema(description = "方法参数")
private String jobParams;
/**
* 任务描述
*/
@Schema(description = "任务描述")
private String description;
/**
* 状态0-暂停1-启用
*/
@Schema(description = "状态0-暂停、1-启用")
private String status;
/**
* 最近修改者
*/
@Schema(description = "最近修改者")
private String lastmodifier;
/**
* 最近修改日期
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description = "最近修改日期")
private Timestamp lastmodifydate;
/**
* 备用1
*/
@Schema(description = "备用1")
private String custom1;
/**
* 备用2
*/
@Schema(description = "备用2")
private String custom2;
/**
* 备用3
*/
@Schema(description = "备用3")
private String custom3;
}

View File

@ -0,0 +1,78 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* <p>
* 系统全局配置
* </p>
*
* @author zhengsl
* @since 2022-01-19
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_config")
public class SysConfig implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 欢迎词
*/
private String welcome;
/**
* 系统功能介绍
*/
private String funcation;
/**
* 系统版本信息
*/
private String versioninfo;
/**
* 备注
*/
private String remark;
/**
* 最近修改者
*/
private String lastmodifier;
/**
* 最近修改日期
*/
@TableField(fill = FieldFill.UPDATE)
private Timestamp lastmodifydate;
/**
* 备用1
*/
private String custom1;
/**
* 备用2
*/
private String custom2;
/**
* 备用3
*/
private String custom3;
}

View File

@ -0,0 +1,71 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
* <p>
* 数据字典表
* </p>
*
* @author TangWei
* @since 2023-03-08
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class SysDictionary implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 字典类型 00-系统内置 01-用户配置
*/
@TableField("dicttype")
private String dictType;
/**
* 顺序号
*/
@TableField("orderno")
private Integer orderNo;
/**
* 字典编码
*/
@TableField("dictcode")
private String dictCode;
/**
* 字典名称
*/
@TableField("dictname")
private String dictName;
/**
* 备用1
*/
private String custom1;
/**
* 备用2
*/
private String custom2;
/**
* 备用3
*/
private String custom3;
}

View File

@ -0,0 +1,77 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
* <p>
* 数据字典明细
* </p>
*
* @author TangWei
* @since 2023-03-08
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class SysDictionaryItems implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 对应字典ID
*/
@TableField("dictid")
private String dictId;
/**
* 顺序号
*/
@TableField("orderno")
private Integer orderNo;
/**
* 项编码
*/
@TableField("itemcode")
private String itemCode;
/**
* 项名称
*/
@TableField("dictname")
private String dictName;
/**
* 父项编码
*/
@TableField("parentcode")
private String parentCode;
/**
* 备用1
*/
private String custom1;
/**
* 备用2
*/
private String custom2;
/**
* 备用3
*/
private String custom3;
}

View File

@ -0,0 +1,92 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.sql.Timestamp;
import java.time.LocalDateTime;
/**
* <p>
* 系统操作日志
* </p>
*
* @author TangWei
* @since 2023-03-08
*/
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class SysLog implements Serializable {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 用户账号
*/
@TableField("usercode")
private String usercode;
/**
* 用户名称
*/
private String username;
/**
* 操作类型 00-登录 01-新增 02-修改 03-删除 06-查询 09其他
*/
@TableField("opttype")
private String opttype;
/**
* 模块名称
*/
private String module;
/**
* 日志描述
*/
private String description;
/**
* 操作方法
*/
private String method;
/**
* 方法参数
*/
private String params;
/**
* 创建时间
*/
@TableField("logtime")
private Timestamp logtime;
/**
* 请求IP
*/
@TableField("requestip")
private String requestip;
/**
* 浏览器类型
*/
private String browser;
public SysLog(String opttype) {
this.opttype = opttype;
}
}

View File

@ -0,0 +1,114 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* 菜单及按钮
* </p>
*
* @author zhengsl
* @since 2021-12-15
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_menu")
public class SysMenu implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 1-web 2-pad 3-mobile
*/
private String systemcode;
/**
* 1-菜单 2-按钮
*/
private String type;
/**
* 在系统内自动生成
*/
private String code;
/**
* 名称
*/
private String name;
/**
* 图标地址
*/
private String icon;
/**
* 是否外链
*/
private String islink;
/**
* 内部模块路径或者外链地址
*/
private String opturl;
/**
* 权限控制标识
*/
private String permission;
/**
* 顶级为0
*/
private String parentid;
/**
* 排序号
*/
private Integer orderno;
/**
* 0-不显示 1-显示
*/
private String isdisplay;
/**
* 最近修改者
*/
private String lastmodifier;
/**
* 最近修改日期
*/
@TableField(fill = FieldFill.UPDATE)
private Timestamp lastmodifydate;
/**
* 备用1
*/
private String custom1;
/**
* 备用2
*/
private String custom2;
/**
* 备用3
*/
private String custom3;
}

View File

@ -0,0 +1,93 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* <p>
* 系统组织框架
* </p>
*
* @author zhengsl
* @since 2021-12-15
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_organization")
public class SysOrganization implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 1-公司 -2-部门
*/
private String orgtype;
/**
* 两位一级
*/
private String orgcode;
/**
* 组织名称
*/
private String orgname;
/**
* 上级id
*/
private String parentid;
/**
* 组织负责人
*/
private String manager;
/**
* 1- 0-
*/
private String isvaild;
/**
* 描述
*/
private String description;
/**
* 最近修改者
*/
private String lastmodifier;
/**
* 最近修改日期
*/
@TableField(fill = FieldFill.UPDATE)
private Timestamp lastmodifydate;
/**
* 备用1
*/
private String custom1;
/**
* 备用2
*/
private String custom2;
/**
* 备用3
*/
private String custom3;
}

View File

@ -0,0 +1,98 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* <p>
* 系统角色
* </p>
*
* @author zhengsl
* @since 2021-12-15
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_role")
public class SysRole implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 系统生成三位编号
*/
private String rolecode;
/**
* 角色名称
*/
private String rolename;
/**
* 1-超级管理员 2-单位管理员 3-普通用户
*/
private String level;
/**
* 描述
*/
private String description;
/**
* org1,org2
*/
private String orgscope;
/**
* 多个操作代码菜单按钮
*/
private String optscope;
/**
* json格式自定义业务范围
*/
private String busscope;
/**
* 1- 0-
*/
private String isvaild;
/**
* 最近修改者
*/
private String lastmodifier;
/**
* 最近修改日期
*/
@TableField(fill = FieldFill.UPDATE)
private Timestamp lastmodifydate;
/**
* 备用1
*/
private String custom1;
/**
* 备用2
*/
private String custom2;
/**
* 备用3
*/
private String custom3;
}

View File

@ -0,0 +1,116 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* <p>
* 系统用户
* </p>
*
* @author zhengsl
* @since 2021-10-27
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_user")
public class SysUser implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id 主键
*/
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/**
* 用户类型 0-管理员 1-普通用户
*/
private Integer usertype;
/**
* 用户名账号
*/
private String username;
/**
* 用户昵称
*/
private String nickname;
/**
* 登录密码加密存储
*/
private String password;
/**
* 性别0- 1-
*/
private String sex;
/**
* 邮箱
*/
private String email;
/**
* 手机号
*/
private String phone;
/**
* 头像预留
*/
private String avatar;
/**
* 账号状态1-正常 0-停用
*/
private Integer status;
/**
* 部门ID
*/
private String orgid;
/**
* 密码重置时间
*/
private String pwdresettime;
/**
* 最近修改者
*/
private String lastmodifier;
/**
* 最近修改日期
*/
@TableField(fill = FieldFill.UPDATE)
private Timestamp lastmodifydate;
@TableField(exist = false)
private String uuid;
@TableField(exist = false)
private String code;
/**
* 备用1
*/
private String custom1;
/**
* 备用2
*/
private String custom2;
/**
* 备用3
*/
private String custom3;
}

View File

@ -0,0 +1,16 @@
package com.yfd.platform.system.mapper;
import com.yfd.platform.system.domain.Message;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 消息通知 Mapper 接口
* </p>
*
* @author TangWei
* @since 2023-03-19
*/
public interface MessageMapper extends BaseMapper<Message> {
}

View File

@ -0,0 +1,16 @@
package com.yfd.platform.system.mapper;
import com.yfd.platform.system.domain.QuartzJob;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 定时任务 Mapper 接口
* </p>
*
* @author TangWei
* @since 2023-03-19
*/
public interface QuartzJobMapper extends BaseMapper<QuartzJob> {
}

View File

@ -0,0 +1,17 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.system.domain.SysConfig;
/**
* <p>
* 系统全局配置 Mapper 接口
* </p>
*
* @author zhengsl
* @since 2022-01-19
*/
public interface SysConfigMapper extends BaseMapper<SysConfig> {
}

View File

@ -0,0 +1,17 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.system.domain.SysDictionaryItems;
/**
* <p>
* 数据字典明细 Mapper 接口
* </p>
*
* @author TangWei
* @since 2023-03-08
*/
public interface SysDictionaryItemsMapper extends BaseMapper<SysDictionaryItems> {
}

View File

@ -0,0 +1,22 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.system.domain.SysDictionary;
/**
* <p>
* 数据字典表 Mapper 接口
* </p>
*
* @author TangWei
* @since 2023-03-08
*/
public interface SysDictionaryMapper extends BaseMapper<SysDictionary> {
/**********************************
* 用途说明: 根据字典类型获取字典最大序号
* 参数说明 sysDictionary 字典对象
* 返回值说明: 返回增加成功或者失败
***********************************/
Integer selectMaxNo(String dictType);
}

View File

@ -0,0 +1,16 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.system.domain.SysLog;
/**
* <p>
* 系统操作日志 Mapper 接口
* </p>
*
* @author TangWei
* @since 2023-03-08
*/
public interface SysLogMapper extends BaseMapper<SysLog> {
}

View File

@ -0,0 +1,59 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.system.domain.SysMenu;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* <p>
* 菜单及按钮 Mapper 接口
* </p>
*
* @author zhengsl
* @since 2021-12-15
*/
public interface SysMenuMapper extends BaseMapper<SysMenu> {
/***********************************
* 用途说明菜单及按钮序号向上移动
* 参数说明
* parentid 上级id
*Orderno 小于序号原序号
*upOrderno 大于等于序号更改的序号加一
* 返回值说明: 是否更新成功
***********************************/
boolean upMoveOrderno(@Param("parentid") String parentid, @Param("Orderno") int Orderno, @Param("upOrderno") int upOrderno);
/***********************************
* 用途说明菜单及按钮序号向下移动
* 参数说明
* parentid 上级id
*Orderno 大于序号原序号
*downOrderno 小于等于序号更改的序号减一
* 返回值说明: 是否更新成功
***********************************/
boolean downMoveOrderno(@Param("parentid") String parentid, @Param("Orderno") int Orderno, @Param("downOrderno") int downOrderno);
List<String> selectPermsByUserId(String userId);
//List<SysMenu> selectMenuByUserId(String userId);
List<Map<String,Object>> selectMenuByUserId(String userId);
/***********************************
* 用途说明根据权限id查找系统类型
* 参数说明 id 权限id
* 返回值说明: 返回系统类型
***********************************/
String getSystemCodeById(String id);
/***********************************
* 用途说明根据角色Id查找权限
* 参数说明 id 权限id
* 返回值说明: 返回权限集合
***********************************/
List<String> selectMenuByRoleId(String id);
}

View File

@ -0,0 +1,33 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.system.domain.SysOrganization;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
* 系统组织框架 Mapper 接口
* </p>
*
* @author zhengsl
* @since 2021-12-15
*/
public interface SysOrganizationMapper extends BaseMapper<SysOrganization> {
/***********************************
* 用途说明去重查询组织分类
* 返回值说明: 所有组织分类
***********************************/
List<String> queryOrgtype();
/***********************************
* 用途说明根据组织分类查询上级id
* 参数说明
* orgtype 组织分类
* 返回值说明: 上级id
***********************************/
List<String> queryParentid(@Param("orgtype") String orgtype);
}

View File

@ -0,0 +1,89 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.system.domain.SysRole;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* <p>
* 系统角色 Mapper 接口
* </p>
*
* @author zhengsl
* @since 2021-12-15
*/
public interface SysRoleMapper extends BaseMapper<SysRole> {
/***********************************
* 用途说明根据角色id查询是否存在用户
* 参数说明
* roleid 角色id
* 返回值说明: 该角色下是否存在用户
************************************/
List<Map<String, String>> isRoleUsersByroleid(String roleid);
/***********************************
* 用途说明根据角色id查询是否存在权限
* 参数说明
* roleid 角色id
* 返回值说明: 该角色下是否存在权限
************************************/
List<Map<String, String>> isRoleMenuByRoleId(String roleId);
/***********************************
* 用途说明查询已分配的用户
* 参数说明
*orgid 所属组织
*username 用户名称
*status 状态
*level 角色级别 '1-超级管理员 2-单位管理员 3-普通用户'
* rolename 角色名称
* isvaild 角色是否有效
* 返回值说明: 系统用户角色数据集合
***********************************/
List<Map> listRoleUsers(String orgid, String username, String status,
String level, String rolename, String isvaild);
/***********************************
* 用途说明根据 角色id和用户id 删除 admin除外
* 参数说明
*roleid 角色id
* urserid 用户id
* 返回值说明: 是否删除成功
***********************************/
boolean deleteRoleUsers(String roleid, String urserid);
/**********************************
* 用途说明: 根据用户id获取角色信息
* 参数说明 id 角色id
* 返回值说明: void
***********************************/
List<SysRole> getRoleByUserId(String id);
/**********************************
* 用途说明: 根据角色ID删除菜单与角色关联信息
* 参数说明 id 角色id
* 返回值说明: void
***********************************/
boolean deleteRoleMenus(String id);
/**********************************
* 用途说明: 根据角色ID删除用户与角色关联信息
* 参数说明 id 角色id
* 返回值说明: void
***********************************/
boolean deleteRoleUser(String id);
/**********************************
* 用途说明: 根据角色id获取用户id
* 参数说明 id 角色id
* 返回值说明: 用户id
***********************************/
List<String> getUserIdById(String id);
void addRoleMenu(@Param("id") String id, @Param("roleid") String roleid,
@Param("menuid") String menuid);
}

View File

@ -0,0 +1,96 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.system.domain.SysUser;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* <p>
* 系统用户表 Mapper 接口
* </p>
*
* @author zhengsl
* @since 2021-10-27
*/
public interface SysUserMapper extends BaseMapper<SysUser> {
List<Map> list(@Param("total")String total, @Param("size")String size, @Param("orgid")String orgid, @Param("username")String username, @Param("mobile")String mobile , @Param("status")String status);
/***********************************
* 用途说明新增系统角色用户对照表 对用户分配角色
* 参数说明
* id 生成的id
* roleid 角色id
* userid 用户id
* 返回值说明:
************************************/
boolean addUserRoles(@Param("id")String id,@Param("roleid") String roleid,@Param("userid") String userid);
/***********************************
* 用途说明根据用户id 和角色id 查询 系统角色用户对照表
* 参数说明
* userid 用户id
* roleid 角色id
* 返回值说明:
************************************/
List<Map> getRoleUsersByid(@Param("roleid") String roleid,@Param("userid") String userid);
/***********************************
* 用途说明根据用户表id查询角色表所有角色
* 参数说明
* userid 用户id
* 返回值说明:
************************************/
List<Map> getLevel(@Param("userid") String userid);
/***********************************
* 用途说明根据用户表id查询角色表所有角色id
* 参数说明
* userid 用户id
* 返回值说明:
************************************/
List<String> getRoleid(@Param("userid") String userid);
/***********************************
* 用途说明根据用户表id查询角色表级别
* 参数说明
* userid 用户id
* 返回值说明:
************************************/
String getMaxLevel(@Param("userid") String userid);
/***********************************
* 用途说明根据用户id删除所分配的角色
* 参数说明
* userid 用户id
* 返回值说明:
************************************/
boolean delRoleUsersByUserid(@Param("userid") String userid);
/***********************************
* 用途说明根据用户id删除所分配的不包含角色
* 参数说明
* userid 用户id
* roleids 多个角色id
* 返回值说明:
************************************/
boolean delInRoleUsersByUserid(@Param("userid") String userid,@Param("roleids")String[] roleids);
Page<Map<String, Object>> queryUsers(String orgid,
String username,
Page<SysUser> page);
Map<String, String> getOrganizationByid(String id);
/**********************************
* 用途说明: 根据ID删除用户与角色的关联信息
* 参数说明 ids 用户id集合
* 返回值说明: void
***********************************/
void delRoleUsersByUserIds(List<String> ids);
}

View File

@ -0,0 +1,16 @@
package com.yfd.platform.system.service;
import com.yfd.platform.system.domain.Message;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 消息通知 服务类
* </p>
*
* @author TangWei
* @since 2023-03-19
*/
public interface IMessageService extends IService<Message> {
}

View File

@ -0,0 +1,43 @@
package com.yfd.platform.system.service;
import com.yfd.platform.system.domain.QuartzJob;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 定时任务 服务类
* </p>
*
* @author TangWei
* @since 2023-03-19
*/
public interface IQuartzJobService extends IService<QuartzJob> {
/**********************************
* 用途说明: 新增定时任务
* 参数说明 quartzJob 定时对象
* 返回值说明: boolean 是否成功
***********************************/
boolean addQuartzJob(QuartzJob quartzJob);
/**********************************
* 用途说明: 删除定时任务
* 参数说明 id id
* 返回值说明: boolean 是否成功
***********************************/
boolean deleteQuartzJob(String id);
/**********************************
* 用途说明: 拖动修改定时任务顺序
* 参数说明 fromID 当前ID toID 到达ID
* 返回值说明: com.yfd.platform.config.ResponseResult 返回拖动成功或者失败
***********************************/
boolean changeDictOrder(String fromID, String toID);
/**********************************
* 用途说明: 执行定时任务
* 参数说明 id id
* 返回值说明: void
***********************************/
void execution(QuartzJob byId);
}

View File

@ -0,0 +1,22 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.system.domain.SysConfig;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.IOException;
import java.util.Map;
/**
* <p>
* 系统全局配置 服务类
* </p>
*
* @author zhengsl
* @since 2022-01-19
*/
public interface ISysConfigService extends IService<SysConfig> {
}

View File

@ -0,0 +1,47 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.system.domain.SysDictionaryItems;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
/**
* <p>
* 数据字典明细 服务类
* </p>
*
* @author TangWei
* @since 2023-03-08
*/
public interface ISysDictionaryItemsService extends IService<SysDictionaryItems> {
/**********************************
* 用途说明: 分页查询字典项信息
* 参数说明 dictID 字典ID ItemName 字典项名称 pageNum 当前页
* 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果
***********************************/
Page<SysDictionaryItems> getDictItemPage(String dictId, String itemName, Page<SysDictionaryItems> page);
/**********************************
* 用途说明: 增加字典项
* 参数说明 sysDictionaryItems 字典项信息
* 返回值说明: com.yfd.platform.config.ResponseResult 返回增加成功或者失败
***********************************/
boolean addDictionaryItem(SysDictionaryItems sysDictionaryItems);
/**********************************
* 用途说明: 拖动修改字典项顺序
* 参数说明 fromID 当前ID toID 到达ID
* 返回值说明: com.yfd.platform.config.ResponseResult 返回拖动成功或者失败
***********************************/
boolean changeItemOrder(String fromID, String toID);
/**********************************
* 用途说明: 导出数据字典项数据
* 参数说明 sysDictionaryItemsList 所需导出的字典项集合
* 返回值说明: com.yfd.platform.config.ResponseResult 返回导出成功或失败
***********************************/
void exportExcel(List<SysDictionaryItems> records, HttpServletResponse response);
}

View File

@ -0,0 +1,45 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.system.domain.SysDictionary;
import java.util.List;
/**
* <p>
* 数据字典表 服务类
* </p>
*
* @author TangWei
* @since 2023-03-08
*/
public interface ISysDictionaryService extends IService<SysDictionary> {
/**********************************
* 用途说明: 获取数据字典列表
* 参数说明 dictType 字典类型
* 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果
***********************************/
List<SysDictionary> getDictList(String dictType);
/**********************************
* 用途说明: 新增字典
* 参数说明 sysDictionary 字典对象
* 返回值说明: com.yfd.platform.config.ResponseResult 返回增加成功或者失败
***********************************/
boolean addDict(SysDictionary sysDictionary);
/**********************************
* 用途说明: 根据ID删除字典
* 参数说明 id 字典ID
* 返回值说明: com.yfd.platform.config.ResponseResult 返回删除结果成功或者失败
***********************************/
boolean deleteDictById(String id);
/**********************************
* 用途说明: 拖动修改字典顺序
* 参数说明 fromID 当前ID toID 到达ID
* 返回值说明: com.yfd.platform.config.ResponseResult 返回拖动成功或者失败
***********************************/
boolean changeDictOrder(String fromID, String toID);
}

View File

@ -0,0 +1,52 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.system.domain.SysLog;
import org.aspectj.lang.ProceedingJoinPoint;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* <p>
* 系统操作日志 服务类
* </p>
*
* @author TangWei
* @since 2023-03-08
*/
public interface ISysLogService extends IService<SysLog> {
/**********************************
* 用途说明: 分页查询日志信息
* 参数说明 pageNum(页码数)pageSize页大小如果是固定页大小可不传username用户名(optType)
* 操作类型startDate(开始日期)endDate结束日期
* 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果
***********************************/
Page<SysLog> getLogList(String username, String optType,
String startDate,
String endDate, Page<SysLog> page);
/**********************************
* 用途说明: 导出日志数据
* 参数说明 sysLogs 所需导出的字典项集合
* 返回值说明: com.yfd.platform.config.ResponseResult 返回导出成功或者失败
***********************************/
void exportExcel(List<SysLog> sysLogs, HttpServletResponse response) throws IOException;
/**********************************
* 用途说明: 新增日志
* 参数说明 nickname 用户名
* 参数说明 username 用户账号
* 参数说明 browser 浏览器
* 参数说明 ip 本机Ip地址
* 参数说明 joinPoint 连接点
* 参数说明 log 日志信息
* 返回值说明: void
***********************************/
void save(String nickname,String username, String browser, String ip, ProceedingJoinPoint joinPoint, SysLog log);
}

View File

@ -0,0 +1,101 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.system.domain.SysMenu;
import org.springframework.web.multipart.MultipartFile;
import java.io.FileNotFoundException;
import java.util.List;
import java.util.Map;
/**
* <p>
* 菜单及按钮 服务类
* </p>
*
* @author zhengsl
* @since 2021-12-15
*/
public interface ISysMenuService extends IService<SysMenu> {
/***********************************
* 用途说明获取菜单结构树含按钮
* 参数说明
* systemcode 系统
* name 名称
* isdisplay 是否显示
* 返回值说明: 菜单结构树集合
***********************************/
List<Map<String,Object>> getMenuButtonTree(String systemcode, String name, String isdisplay);
/***********************************
* 用途说明获取菜单结构树不含按钮
* 参数说明
* systemcode 系统
* name 名称
* isdisplay 是否显示
* 返回值说明: 菜单结构树集合
***********************************/
List<Map<String,Object>> getMenuTree(String systemcode, String name, String isdisplay);
/***********************************
* 用途说明新增菜单及按钮
* 参数说明
* sysMenu 菜单或按钮表对象
* 返回值说明: 是否添加成功提示
***********************************/
boolean addMenu(SysMenu sysMenu);
/***********************************
* 用途说明上传单个图标
* 参数说明
* id 上传图标id
* icon 图标
* 返回值说明: 是否上传成功
***********************************/
boolean uploadIcon(String id, MultipartFile icon);
/***********************************
* 用途说明根据id删除单个图标
* 参数说明
* id 删除图标id
* icon 图标名称
* 返回值说明: 是否删除成功
***********************************/
boolean deleteIcon(String id);
/***********************************
* 用途说明菜单及按钮序号排序
* 参数说明
* parentid 上级id
* orderMap map<菜单及按钮表id,排列序号>
* 返回值说明: 是否更新成功
***********************************/
boolean moveOrderno(String parentid, String id, int orderno);
/***********************************
* 用途说明根据id删除菜单或按钮
* 参数说明
* id 删除列的id
* 返回值说明: 是否删除成功
***********************************/
boolean deleteById(String id);
boolean changeOderNoById(String fromId, String toId);
List<Map<String, Object>> getMenuTree(String id);
/***********************************
* 用途说明权限分配
* 参数说明
* systemcode 系统
* name 名称
* isdisplay 是否显示
* 返回值说明: 菜单结构树集合
***********************************/
List<Map<String, Object>> permissionAssignment(String roleId);
String uploadIcon(MultipartFile icon) throws FileNotFoundException;
}

View File

@ -0,0 +1,60 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.system.domain.SysOrganization;
import java.util.List;
import java.util.Map;
/**
* <p>
* 系统组织框架 服务类
* </p>
*
* @author zhengsl
* @since 2021-12-15
*/
public interface ISysOrganizationService extends IService<SysOrganization> {
/***********************************
* 用途说明获取组织结构树
* 参数说明
*parentid 上级id
* params 名称根据名称查询二级
* 返回值说明: 组织树集合
***********************************/
List<Map<String, Object>> getOrgTree(String parentid, String params);
/***********************************
* 用途说明新增系统组织框架
* 参数说明
* sysOrganization 系统组织框架对象
* 返回值说明: 是否新增成功
***********************************/
boolean addOrg(SysOrganization sysOrganization);
/***********************************
* 用途说明根据企业ID查询组织详情
* 参数说明
* id 企业id
* 返回值说明: 系统组织框架对象
***********************************/
List<SysOrganization> getOrganizationById(String id,String orgName);
/***********************************
* 用途说明获取组织范围树结构
* 参数说明
*roleId 角色id
* 返回值说明: 组织树集合
***********************************/
List<Map<String, Object>> getOrgScopeTree(String roleId);
/**********************************
* 用途说明: 修改角色组织范围
* 参数说明 roleId 角色id
* 参数说明 orgscope 组织id集合
* 返回值说明: boolean 是否修改成功
***********************************/
boolean updateOrgScopeByRoleId(String roleId, String orgscope);
}

View File

@ -0,0 +1,66 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.system.domain.SysRole;
import java.util.List;
import java.util.Map;
/**
* <p>
* 系统角色 服务类
* </p>
*
* @author zhengsl
* @since 2021-12-15
*/
public interface ISysRoleService extends IService<SysRole> {
/***********************************
* 用途说明新增角色
* 参数说明
* sysRole 新增角色信息
* 返回值说明: 是否新增成功
***********************************/
boolean addRole(SysRole sysRole);
/***********************************
* 用途说明删除角色用户
* 参数说明
* id 系统角色用户对照表id
* 返回值说明: 是否新增成功
***********************************/
boolean deleteRoleUsers(String roleid, String urserids);
/***********************************
* 用途说明根据id删除角色
* 参数说明
*id 角色id
* 返回值说明: 是否删除成功
***********************************/
void deleteById(String id);
/***********************************
* 用途说明查询已分配的用户
* 参数说明
*orgid 所属组织
*username 用户名称
*status 状态
*level 角色级别
* rolename 角色名称
* isvaild 角色是否有效
* 返回值说明: 系统用户角色数据集合
***********************************/
List<Map> listRoleUsers(String orgid, String username, String status, String level, String rolename, String isvaild);
/***********************************
* 用途说明角色分配权限
* 参数说明
* id 角色id
* menuIds 权限id字符串
* 返回值说明: 是否分配成功
***********************************/
boolean setMenuById(String id, String menuIds);
}

View File

@ -0,0 +1,143 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.LoginUser;
import com.yfd.platform.system.domain.SysUser;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.util.List;
import java.util.Map;
/**
* <p>
* 系统用户
* </p>
*
* @author zhengsl
* @since 2021-10-27
*/
public interface IUserService extends IService<SysUser> {
//获取当前用户账号及名称
String getUsername();
//获取当前用户信息
SysUser getUserInfo();
/***********************************
* 用途说明获取当前用户账号与姓名
* 返回值说明: 当前用户账号与姓名
************************************/
Map<String, String> getNameInfo();
//获取当前用户信息带权限
ResponseResult getLoginUserInfo();
/***********************************
* 用途说明新增用户
* 参数说明
*sysUser 新增用户对象
* id 创建者id
* roleId 角色id
* 返回值说明: 提示字符串
************************************/
Map addUser(SysUser sysUser, String roleids);
/***********************************
* 用途说明:查询系统用户
* 参数说明
*page 分页集合参数
*orgid 所属组织
*username 用户名称
* mobile 手机号
* status 状态
* 返回值说明: 用户分页集合
************************************/
List<Map> list(String total, String size, String orgid, String username,
String mobile, String status);
/***********************************
* 用途说明根据ID查询用户详情
* 参数说明
*id 用户id
* 返回值说明: 用户表对象
************************************/
Map getOneById(String id);
/***********************************
* 用途说明根据ID修改用户
* 参数说明
*sysUser 用户对象
*roleids 角色id
* 返回值说明: 是否更新成功
************************************/
Map updateById(SysUser sysUser, String roleids);
/***********************************
* 用途说明用户分配角色多个
* 参数说明
*roleid 角色id
* userids 用户id数组
* 返回值说明: 判断是否添加成功
************************************/
boolean setUserRoles(String roleid, String userids);
/***********************************
* 用途说明根据id删除用户
* 参数说明
*id 用户id
* 返回值说明: 判断是否删除成功
************************************/
boolean deleteById(String id);
/***********************************
* 用途说明重置用户密码(管理员)
* 参数说明
*id 重置密码的 用户id
* 返回值说明: 判断是否重置成功
************************************/
boolean resetPassword(String id) throws Exception;
/***********************************
* 用途说明设置账号状态(管理员)
* 参数说明
*id 用户id
* status 设置状态
* 返回值说明: 判断是否设置成功
************************************/
boolean setStatus(String id, String status);
/***********************************
* 用途说明上传用户头像
* 参数说明
* id 用户id
* img 账号头像
* 返回值说明: 判断是否上传
***********************************/
boolean uploadAvatar(String id, MultipartFile img);
/***********************************
* 用途说明新增系统角色用户对照表 对用户分配角色(单个)
* 参数说明
* id 生成的id
* userid 用户id
* roleid 角色id
* 返回值说明:
************************************/
boolean addUserRoles(String roleid, String userid);
//Page<SysUser> queryUsers(String orgid, String username, Page<SysUser> page);
Page<Map<String,Object>> queryUsers(String orgid, String username, Page<SysUser> page);
/***********************************
* 用途说明根据ID批量删除用户
* 参数说明
*ids 用户id集合
* 返回值说明: 判断是否删除成功
************************************/
boolean deleteUserByIds(String ids);
}

View File

@ -0,0 +1,20 @@
package com.yfd.platform.system.service.impl;
import com.yfd.platform.system.domain.Message;
import com.yfd.platform.system.mapper.MessageMapper;
import com.yfd.platform.system.service.IMessageService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 消息通知 服务实现类
* </p>
*
* @author TangWei
* @since 2023-03-19
*/
@Service
public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> implements IMessageService {
}

View File

@ -0,0 +1,114 @@
package com.yfd.platform.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yfd.platform.system.domain.QuartzJob;
import com.yfd.platform.system.domain.SysDictionary;
import com.yfd.platform.system.mapper.QuartzJobMapper;
import com.yfd.platform.system.service.IQuartzJobService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.utils.QuartzManage;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* <p>
* 定时任务 服务实现类
* </p>
*
* @author TangWei
* @since 2023-03-19
*/
@Service
public class QuartzJobServiceImpl extends ServiceImpl<QuartzJobMapper,
QuartzJob> implements IQuartzJobService {
@Resource
private QuartzJobMapper quartzJobMapper;
@Resource
private QuartzManage quartzManage;
/**********************************
* 用途说明: 新增定时任务
* 参数说明 quartzJob 定时对象
* 返回值说明: boolean 是否成功
***********************************/
@Override
public boolean addQuartzJob(QuartzJob quartzJob) {
// 生成序号
long orderNo = this.count() + 1L;
quartzJob.setOrderno((int) orderNo);
return this.save(quartzJob);
}
/**********************************
* 用途说明: 删除定时任务
* 参数说明 id id
* 返回值说明: boolean 是否成功
***********************************/
@Override
public boolean deleteQuartzJob(String id) {
String[] split = id.split(",");
Set<String> ids = Arrays.stream(split).collect(Collectors.toSet());
for (String s : ids) {
QuartzJob quartzJob = this.getById(s);
quartzManage.deleteJob(quartzJob);
this.removeById(s);
}
// 查询所有定时任务
List<QuartzJob> list =
this.list(new LambdaQueryWrapper<QuartzJob>().orderByAsc(QuartzJob::getOrderno));
// 更新序号
for (int i = 0; i < list.size(); i++) {
QuartzJob quartzJob = list.get(i);
quartzJob.setOrderno(i + 1);
this.updateById(quartzJob);
}
return true;
}
/**********************************
* 用途说明: 拖动修改定时任务顺序
* 参数说明 fromID 当前ID toID 到达ID
* 返回值说明: com.yfd.platform.config.ResponseResult 返回拖动成功或者失败
***********************************/
@Override
public boolean changeDictOrder(String fromID, String toID) {
QuartzJob fromQuartzJob =
quartzJobMapper.selectById(fromID);
QuartzJob toQuartzJob = quartzJobMapper.selectById(toID);
// 如果数据字典不存在拖动失败
if (fromQuartzJob == null || toQuartzJob == null) {
return false;
}
Integer fromOrderNo = fromQuartzJob.getOrderno();
Integer toOrderNo = toQuartzJob.getOrderno();
// 如果数据字典的顺序号不存在拖动失败
if (fromOrderNo == null || toOrderNo == null) {
return false;
}
// 将顺序号放入字典对象中
fromQuartzJob.setOrderno(toOrderNo);
toQuartzJob.setOrderno(fromOrderNo);
// 更改顺序号
boolean fromBool = this.updateById(fromQuartzJob);
boolean toBool = this.updateById(toQuartzJob);
return fromBool && toBool;
}
/**********************************
* 用途说明: 执行定时任务
* 参数说明 id id
* 返回值说明: void
***********************************/
@Override
public void execution(QuartzJob quartzJob) {
quartzManage.runJobNow(quartzJob);
}
}

Some files were not shown because too many files have changed in this diff Show More