first commit
This commit is contained in:
@@ -0,0 +1,935 @@
|
||||
# 会员模块结构说明
|
||||
|
||||
## 模块概述
|
||||
|
||||
`ruoyi-member` 模块是系统会员中心模块,负责 App 端用户管理、认证授权、设备管理、消息推送等核心功能。
|
||||
|
||||
- **包名**: `org.dromara.member`
|
||||
- **状态**: ✅ 核心功能已实现
|
||||
|
||||
## 已完成工作
|
||||
|
||||
### 1. 模块结构
|
||||
|
||||
- ✅ 创建了完整的模块目录结构
|
||||
- ✅ 创建了 `pom.xml` 配置文件
|
||||
- ✅ 配置了模块依赖关系
|
||||
|
||||
### 2. 配置类
|
||||
|
||||
- ✅ 创建了 JWT 过滤器配置 (`AppJwtFilter`)
|
||||
- ✅ 创建了 JWT Web 配置 (`AppJwtWebConfig`)
|
||||
- ✅ 配置了组件扫描和过滤器注册
|
||||
|
||||
### 3. 数据库
|
||||
|
||||
- ✅ 创建了所有业务表的实体类和 Mapper
|
||||
- ✅ 实现了数据库表的 CRUD 操作
|
||||
- ✅ 配置了逻辑删除和字段自动填充
|
||||
|
||||
### 4. 核心功能
|
||||
|
||||
- ✅ 用户管理(注册、登录、信息管理)
|
||||
- ✅ 角色管理(角色CRUD、用户角色关联)
|
||||
- ✅ 设备管理(设备绑定、推送令牌管理)
|
||||
- ✅ 文件管理(文件上传、下载、管理)
|
||||
- ✅ 消息管理(消息推送、通知管理)
|
||||
- ✅ 操作日志(日志记录、查询、统计)
|
||||
- ✅ 登录日志(登录日志记录、查询)
|
||||
- ✅ 版本管理(App版本管理、更新检查)
|
||||
- ✅ 社交认证(第三方登录、绑定)
|
||||
- ✅ JWT认证(令牌生成、刷新、验证)
|
||||
|
||||
### 5. 异常处理
|
||||
|
||||
- ✅ 创建了统一的异常处理类 (`AppExceptionHandler`)
|
||||
- ✅ 定义了业务异常类(`DeviceException`, `FileException`, `VersionException`)
|
||||
|
||||
### 6. API接口
|
||||
|
||||
- ✅ 实现了管理端接口(用户、角色、配置管理)
|
||||
- ✅ 实现了移动端接口(用户、角色、设备、文件、消息、日志、版本管理)
|
||||
- ✅ 实现了认证接口(JWT登录、注册、刷新)
|
||||
|
||||
## 核心功能模块
|
||||
|
||||
### 1. 用户管理 (AppUser)
|
||||
|
||||
- **职责**: 用户注册、登录、信息管理、密码管理
|
||||
- **状态**: ✅ 核心功能已实现
|
||||
- **数据库表**: `app_user`, `app_user_role`
|
||||
|
||||
### 2. 角色管理 (AppRole)
|
||||
|
||||
- **职责**: 角色管理、用户角色关联
|
||||
- **状态**: ✅ 核心功能已实现
|
||||
- **数据库表**: `app_role`, `app_user_role`
|
||||
|
||||
### 3. 设备管理 (AppDevice)
|
||||
|
||||
- **职责**: 用户设备绑定、推送令牌管理、设备状态管理
|
||||
- **状态**: ✅ 核心功能已实现
|
||||
- **数据库表**: `app_device`
|
||||
|
||||
### 4. 文件管理 (AppFile)
|
||||
|
||||
- **职责**: 文件上传、下载、管理(头像、文档、图片等)
|
||||
- **状态**: ✅ 核心功能已实现
|
||||
- **数据库表**: `app_file`
|
||||
|
||||
### 5. 消息管理 (AppMessage)
|
||||
|
||||
- **职责**: 消息推送、通知管理、用户消息关联
|
||||
- **状态**: ✅ 核心功能已实现
|
||||
- **数据库表**: `app_message`, `app_user_message`
|
||||
|
||||
### 6. 操作日志 (AppOperLog)
|
||||
|
||||
- **职责**: 用户操作日志记录、查询、统计分析
|
||||
- **状态**: ✅ 核心功能已实现
|
||||
- **数据库表**: `app_oper_log`
|
||||
|
||||
### 7. 登录日志 (AppLoginLog)
|
||||
|
||||
- **职责**: 用户登录日志记录、查询
|
||||
- **状态**: ✅ 核心功能已实现
|
||||
- **数据库表**: `app_login_log`
|
||||
|
||||
### 8. 版本管理 (AppVersion)
|
||||
|
||||
- **职责**: App 版本管理、更新检查、强制更新
|
||||
- **状态**: ✅ 核心功能已实现
|
||||
- **数据库表**: `app_version`
|
||||
|
||||
### 9. 社交认证 (AppSocialAuth)
|
||||
|
||||
- **职责**: 第三方登录(微信、QQ、微博等)
|
||||
- **状态**: ✅ 核心功能已实现
|
||||
- **数据库表**: `app_social_auth`
|
||||
|
||||
### 10. JWT认证 (JwtUtil)
|
||||
|
||||
- **职责**: JWT 令牌生成、刷新、验证
|
||||
- **状态**: ✅ 核心功能已实现
|
||||
- **配置文件**: `AppJwtFilter`, `AppJwtWebConfig`
|
||||
|
||||
## 数据库表结构说明
|
||||
|
||||
### 1. 用户表 (app_user)
|
||||
|
||||
- **功能**: 存储 App 端用户基本信息
|
||||
- **关键字段**: `user_id`, `user_name`, `nick_name`, `phone`, `email`, `password`, `status`, `avatar`, `sex`, `login_ip`, `login_date`, `register_time`
|
||||
- **索引**: `user_name` (唯一), `phone`, `email`
|
||||
- **状态说明**:
|
||||
- `status`: 0-正常, 1-停用
|
||||
- `sex`: 0-男, 1-女, 2-未知
|
||||
- `del_flag`: 0-存在, 1-删除
|
||||
|
||||
### 2. 角色表 (app_role)
|
||||
|
||||
- **功能**: 存储 App 端角色信息
|
||||
- **关键字段**: `role_id`, `role_name`, `role_key`, `role_sort`, `status`
|
||||
- **索引**: `role_key` (唯一), `status`
|
||||
- **状态说明**:
|
||||
- `status`: 0-正常, 1-停用
|
||||
- `del_flag`: 0-存在, 1-删除
|
||||
|
||||
### 3. 用户角色关联表 (app_user_role)
|
||||
|
||||
- **功能**: 存储用户和角色的关联关系
|
||||
- **关键字段**: `user_id`, `role_id`
|
||||
- **索引**: `user_id`, `role_id`, `uk_user_role` (唯一索引)
|
||||
- **说明**: 多对多关系,一个用户可以有多个角色,一个角色可以分配给多个用户
|
||||
|
||||
### 4. 设备表 (app_device)
|
||||
|
||||
- **功能**: 存储用户绑定的设备信息
|
||||
- **关键字段**: `device_id`, `user_id`, `device_type`, `device_name`, `device_model`, `device_brand`, `os_version`, `app_version`, `push_token`, `is_active`, `last_active_time`
|
||||
- **索引**: `user_id`, `device_type`, `push_token`
|
||||
- **状态说明**:
|
||||
- `device_type`: ios, android, h5
|
||||
- `is_active`: 0-否, 1-是
|
||||
- `del_flag`: 0-存在, 2-删除
|
||||
|
||||
### 5. 文件表 (app_file)
|
||||
|
||||
- **功能**: 存储用户上传的文件信息
|
||||
- **关键字段**: `file_id`, `user_id`, `file_name`, `original_name`, `file_path`, `file_url`, `file_size`, `file_type`, `file_suffix`, `file_category`, `storage_service`, `status`, `download_count`, `is_public`, `file_md5`
|
||||
- **索引**: `user_id`, `file_category`, `file_md5`, `status`
|
||||
- **状态说明**:
|
||||
- `file_category`: 1-头像, 2-文档, 3-图片, 4-视频, 5-音频, 6-其他
|
||||
- `status`: 0-正常, 1-删除
|
||||
- `is_public`: 0-私有, 1-公开
|
||||
- `del_flag`: 0-存在, 2-删除
|
||||
|
||||
### 6. 消息表 (app_message)
|
||||
|
||||
- **功能**: 存储系统消息和通知
|
||||
- **关键字段**: `message_id`, `title`, `content`, `message_type`, `target_type`, `target_ids`, `send_time`, `status`
|
||||
- **索引**: `message_type`, `target_type`, `status`, `send_time`
|
||||
- **状态说明**:
|
||||
- `message_type`: system-系统消息, notice-通知, activity-活动
|
||||
- `target_type`: all-全部用户, user-指定用户, role-指定角色
|
||||
- `status`: 0-待发送, 1-已发送, 2-发送失败
|
||||
- `del_flag`: 0-存在, 2-删除
|
||||
|
||||
### 7. 用户消息关联表 (app_user_message)
|
||||
|
||||
- **功能**: 存储用户消息的读取记录
|
||||
- **关键字段**: `id`, `user_id`, `message_id`, `is_read`, `read_time`
|
||||
- **索引**: `user_id`, `message_id`, `is_read`
|
||||
- **状态说明**:
|
||||
- `is_read`: 0-未读, 1-已读
|
||||
- `del_flag`: 0-存在, 2-删除
|
||||
|
||||
### 8. 操作日志表 (app_oper_log)
|
||||
|
||||
- **功能**: 存储用户操作日志
|
||||
- **关键字段**: `oper_id`, `title`, `business_type`, `method`, `request_method`, `oper_name`, `oper_url`, `oper_ip`, `oper_location`, `oper_param`, `json_result`, `status`, `error_msg`, `oper_time`, `cost_time`
|
||||
- **索引**: `oper_name`, `status`, `oper_time`, `business_type`
|
||||
- **状态说明**:
|
||||
- `business_type`: 0-其它, 1-新增, 2-修改, 3-删除
|
||||
- `status`: 0-正常, 1-异常
|
||||
|
||||
### 9. 登录日志表 (app_login_log)
|
||||
|
||||
- **功能**: 存储用户登录日志
|
||||
- **关键字段**: `info_id`, `user_name`, `status`, `ipaddr`, `login_location`, `browser`, `os`, `msg`, `login_time`
|
||||
- **索引**: `user_name`, `status`, `login_time`, `ipaddr`
|
||||
- **状态说明**:
|
||||
- `status`: 0-成功, 1-失败
|
||||
|
||||
### 10. 版本表 (app_version)
|
||||
|
||||
- **功能**: 存储 App 版本信息
|
||||
- **关键字段**: `version_id`, `version_code`, `version_name`, `update_content`, `download_url`, `is_force`, `platform`
|
||||
- **索引**: `platform`, `version_code`
|
||||
- **状态说明**:
|
||||
- `platform`: android, ios
|
||||
- `is_force`: 0-否, 1-是
|
||||
- `del_flag`: 0-存在, 2-删除
|
||||
|
||||
### 11. 社交认证表 (app_social_auth)
|
||||
|
||||
- **功能**: 存储第三方登录授权信息
|
||||
- **关键字段**: `id`, `user_id`, `platform`, `platform_uid`, `open_id`, `union_id`, `access_token`, `expire_in`, `refresh_token`, `scope`
|
||||
- **索引**: `user_id`, `platform`, `platform_uid`, `open_id`, `union_id`
|
||||
- **状态说明**:
|
||||
- `platform`: wechat_mp-微信小程序, wechat_open-微信开放平台, qq-QQ, weibo-微博
|
||||
- `del_flag`: 0-存在, 2-删除
|
||||
|
||||
## 功能清单
|
||||
|
||||
### 1. 用户管理
|
||||
|
||||
#### 已实现功能 ✅
|
||||
|
||||
##### 用户基础功能
|
||||
|
||||
- ✅ 用户注册
|
||||
- 账号注册(支持用户名、手机号、邮箱注册)
|
||||
- 账号唯一性校验
|
||||
- 手机号唯一性校验
|
||||
- 邮箱唯一性校验
|
||||
- 注册时自动分配默认角色
|
||||
- ✅ 用户登录
|
||||
- 账号密码登录
|
||||
- 手机号验证码登录 ✅(在 ruoyi-server 模块实现)
|
||||
- 邮箱验证码登录 ✅(在 ruoyi-server 模块实现)
|
||||
- 验证码发送(短信/邮箱)✅(在 ruoyi-server 模块实现)
|
||||
- JWT 令牌生成
|
||||
- 登录日志记录
|
||||
- ✅ 用户信息管理
|
||||
- 用户列表查询(分页、条件筛选)
|
||||
- 用户详情查询
|
||||
- 用户新增/修改/删除
|
||||
- 用户状态管理(启用/停用)
|
||||
- 用户信息导出
|
||||
- ✅ 用户资料管理
|
||||
- 用户资料查询
|
||||
- 用户资料修改
|
||||
- 头像管理(关联文件表)
|
||||
- ✅ 密码管理
|
||||
- 修改密码(需验证旧密码)
|
||||
- 重置密码(管理员操作)
|
||||
- 密码加密(BCrypt)
|
||||
- ✅ 第三方账号绑定
|
||||
- 第三方账号绑定/解绑 ✅(在 ruoyi-server 模块实现)
|
||||
- 查询绑定列表 ✅
|
||||
|
||||
#### 待实现功能 ⏳
|
||||
|
||||
- [ ] 忘记密码(通过手机号/邮箱验证码找回密码)
|
||||
- [ ] 独立的手机号/邮箱绑定功能(当前可通过更新用户资料方式修改)
|
||||
- [ ] 用户等级体系
|
||||
- 用户等级定义
|
||||
- 用户等级升级规则
|
||||
- 用户积分/经验值管理
|
||||
- [ ] 用户标签
|
||||
- 用户标签管理
|
||||
- 用户标签关联
|
||||
- 标签筛选用户
|
||||
|
||||
### 2. 角色管理
|
||||
|
||||
#### 已实现功能 ✅
|
||||
|
||||
- ✅ 角色CRUD操作
|
||||
- 角色列表查询(分页、条件筛选)
|
||||
- 角色详情查询
|
||||
- 角色新增/修改/删除
|
||||
- 角色导出功能
|
||||
- ✅ 角色状态管理
|
||||
- 启用/禁用角色
|
||||
- ✅ 用户角色关联
|
||||
- 查询用户已分配角色
|
||||
- 查询用户未分配角色
|
||||
- 分配角色给用户
|
||||
- 取消用户角色关联
|
||||
- 批量分配/取消角色
|
||||
|
||||
#### 待实现功能 ⏳
|
||||
|
||||
- [ ] 角色权限管理
|
||||
- 角色权限配置
|
||||
- 权限点管理
|
||||
- 权限验证(需集成权限框架)
|
||||
- [ ] 角色数据权限
|
||||
- 数据权限范围配置
|
||||
- 数据权限过滤
|
||||
|
||||
### 3. 设备管理
|
||||
|
||||
#### 已实现功能 ✅
|
||||
|
||||
- ✅ 设备绑定
|
||||
- 设备信息绑定
|
||||
- 设备信息更新
|
||||
- ✅ 设备查询
|
||||
- 设备列表查询
|
||||
- 设备详情查询
|
||||
- 我的设备列表查询
|
||||
- 活跃设备查询
|
||||
- ✅ 设备状态管理
|
||||
- 设备活跃状态更新
|
||||
- 推送令牌管理
|
||||
- 设备心跳检测
|
||||
- ✅ 设备解绑
|
||||
- 设备解绑功能
|
||||
|
||||
#### 待实现功能 ⏳
|
||||
|
||||
- [ ] 设备推送管理
|
||||
- 消息推送(需集成推送服务)
|
||||
- 推送记录查询
|
||||
- 推送统计
|
||||
- [ ] 设备安全
|
||||
- 设备指纹识别
|
||||
- 异常设备检测
|
||||
- 设备黑名单管理
|
||||
|
||||
### 4. 文件管理
|
||||
|
||||
#### 已实现功能 ✅
|
||||
|
||||
- ✅ 文件上传
|
||||
- 单文件上传
|
||||
- 批量文件上传
|
||||
- 头像上传
|
||||
- ✅ 文件查询
|
||||
- 文件列表查询(分页)
|
||||
- 文件详情查询
|
||||
- 按分类查询文件
|
||||
- 公开文件查询
|
||||
- ✅ 文件下载
|
||||
- 文件下载
|
||||
- 下载次数统计
|
||||
- ✅ 文件管理
|
||||
- 文件信息修改
|
||||
- 文件状态管理
|
||||
- 文件公开/私有设置
|
||||
- 文件删除
|
||||
- ✅ 文件校验
|
||||
- 文件MD5校验(秒传功能)
|
||||
- 文件统计
|
||||
|
||||
#### 待实现功能 ⏳
|
||||
|
||||
- [ ] 文件存储优化
|
||||
- 文件存储服务商集成(OSS、COS等)
|
||||
- 文件CDN加速
|
||||
- 文件压缩处理
|
||||
- [ ] 文件预览
|
||||
- 图片预览
|
||||
- 文档预览(PDF、Office等)
|
||||
- 视频播放
|
||||
- [ ] 文件分享
|
||||
- 文件分享链接生成
|
||||
- 分享链接访问控制
|
||||
- 分享统计
|
||||
|
||||
### 5. 消息管理
|
||||
|
||||
#### 已实现功能 ✅
|
||||
|
||||
- ✅ 消息管理
|
||||
- 消息列表查询(分页)
|
||||
- 消息详情查询
|
||||
- 消息新增/修改/删除
|
||||
- 消息导出
|
||||
- ✅ 用户消息
|
||||
- 我的消息列表查询
|
||||
- 未读消息数量查询
|
||||
- 消息标记已读
|
||||
- 批量标记已读
|
||||
- 全部标记已读
|
||||
- ✅ 消息推送
|
||||
- 系统消息发送
|
||||
- 个人消息发送
|
||||
- 消息推送(需集成推送服务)
|
||||
- 消息广播
|
||||
|
||||
#### 待实现功能 ⏳
|
||||
|
||||
- [ ] 消息推送集成
|
||||
- 推送服务集成(极光推送、个推等)
|
||||
- 推送消息发送
|
||||
- 推送结果回调
|
||||
- 推送统计
|
||||
- [ ] 消息模板
|
||||
- 消息模板管理
|
||||
- 模板变量替换
|
||||
- [ ] 消息分类
|
||||
- 消息分类管理
|
||||
- 消息分类筛选
|
||||
- [ ] 消息设置
|
||||
- 用户消息推送设置
|
||||
- 消息免打扰时段
|
||||
- 消息接收方式设置
|
||||
|
||||
### 6. 操作日志
|
||||
|
||||
#### 已实现功能 ✅
|
||||
|
||||
- ✅ 日志记录
|
||||
- 操作日志记录
|
||||
- 批量操作日志记录
|
||||
- ✅ 日志查询
|
||||
- 日志列表查询(分页、条件筛选)
|
||||
- 我的操作日志查询
|
||||
- 日志详情查询
|
||||
- 日志导出
|
||||
- ✅ 日志统计
|
||||
- 操作日志统计
|
||||
- 行为分析
|
||||
- 热门操作统计
|
||||
- 错误操作统计
|
||||
- ✅ 日志清理
|
||||
- 日志清理
|
||||
- 按时间清理日志
|
||||
|
||||
#### 待实现功能 ⏳
|
||||
|
||||
- [ ] 日志分析
|
||||
- 操作趋势分析
|
||||
- 用户行为分析
|
||||
- 异常操作分析
|
||||
- [ ] 日志告警
|
||||
- 异常操作告警
|
||||
- 告警规则配置
|
||||
|
||||
### 7. 登录日志
|
||||
|
||||
#### 已实现功能 ✅
|
||||
|
||||
- ✅ 登录日志记录
|
||||
- 登录成功/失败日志记录
|
||||
- 登录IP、地点、浏览器等信息记录
|
||||
- ✅ 登录日志查询
|
||||
- 登录日志列表查询(分页、条件筛选)
|
||||
- 登录日志详情查询
|
||||
- 登录日志导出
|
||||
|
||||
#### 待实现功能 ⏳
|
||||
|
||||
- [ ] 登录安全
|
||||
- 异常登录检测
|
||||
- 异地登录提醒
|
||||
- 登录IP白名单/黑名单
|
||||
- [ ] 登录统计
|
||||
- 登录统计报表
|
||||
- 登录趋势分析
|
||||
- 登录设备分析
|
||||
|
||||
### 8. 版本管理
|
||||
|
||||
#### 已实现功能 ✅
|
||||
|
||||
- ✅ 版本管理
|
||||
- 版本列表查询(分页)
|
||||
- 版本详情查询
|
||||
- 版本新增/修改/删除
|
||||
- 版本导出
|
||||
- ✅ 版本检查
|
||||
- 检查更新
|
||||
- 获取最新版本
|
||||
- 版本历史查询
|
||||
- 强制更新检查
|
||||
- 更新信息查询
|
||||
- 版本对比
|
||||
- ✅ 版本统计
|
||||
- 版本下载记录
|
||||
- 版本安装记录
|
||||
|
||||
#### 待实现功能 ⏳
|
||||
|
||||
- [ ] 版本发布流程
|
||||
- 版本发布审核
|
||||
- 版本发布通知
|
||||
- [ ] 版本回退
|
||||
- 版本回退功能
|
||||
- 回退记录
|
||||
|
||||
### 9. 社交认证
|
||||
|
||||
#### 已实现功能 ✅
|
||||
|
||||
- ✅ 第三方登录
|
||||
- 微信小程序登录
|
||||
- 微信开放平台登录
|
||||
- QQ登录
|
||||
- 微博登录
|
||||
- ✅ 授权管理
|
||||
- 授权信息存储
|
||||
- 授权信息查询
|
||||
- 授权绑定/解绑 ✅(在 ruoyi-server 模块实现)
|
||||
|
||||
#### 待实现功能 ⏳
|
||||
|
||||
- [ ] 更多第三方登录
|
||||
- 支付宝登录
|
||||
- 抖音登录
|
||||
- 苹果登录(Apple ID)
|
||||
- [ ] 授权管理增强
|
||||
- 授权过期处理
|
||||
- 授权刷新
|
||||
- 授权撤销
|
||||
|
||||
### 10. JWT认证
|
||||
|
||||
#### 已实现功能 ✅
|
||||
|
||||
- ✅ JWT令牌生成
|
||||
- Access Token生成
|
||||
- Refresh Token生成
|
||||
- ✅ JWT令牌验证
|
||||
- Token验证过滤器
|
||||
- Token有效性校验
|
||||
- ✅ JWT令牌刷新
|
||||
- Token刷新接口
|
||||
- ✅ 用户登录/登出
|
||||
- 登录接口(生成Token)
|
||||
- 登出接口(Token失效)
|
||||
- ✅ 验证码
|
||||
- 图形验证码生成
|
||||
|
||||
#### 待实现功能 ⏳
|
||||
|
||||
- [ ] Token安全增强
|
||||
- Token黑名单(Redis存储)
|
||||
- Token刷新策略优化
|
||||
- Token过期时间配置
|
||||
- [ ] 多端登录管理
|
||||
- 多设备登录控制
|
||||
- 登录设备列表查询
|
||||
- 强制下线功能
|
||||
|
||||
## API接口详细说明
|
||||
|
||||
### 管理端接口
|
||||
|
||||
#### 用户管理 (`/admin/member/user`)
|
||||
|
||||
- `GET /admin/member/user/list` - 查询用户列表(分页)
|
||||
- `GET /admin/member/user/{userId}` - 获取用户详情
|
||||
- `POST /admin/member/user` - 新增用户
|
||||
- `PUT /admin/member/user` - 修改用户
|
||||
- `DELETE /admin/member/user/{userIds}` - 删除用户
|
||||
- `POST /admin/member/user/export` - 导出用户列表
|
||||
- `GET /admin/member/user/profile` - 获取当前用户资料
|
||||
- `PUT /admin/member/user/profile` - 修改当前用户资料
|
||||
- `PUT /admin/member/user/resetPwd` - 重置用户密码
|
||||
- `PUT /admin/member/user/changeStatus` - 修改用户状态
|
||||
- `GET /admin/member/user/authRole/{userId}` - 查询用户角色
|
||||
- `GET /admin/member/user/deptTree` - 查询部门树(预留)
|
||||
|
||||
#### 角色管理 (`/admin/member/role`)
|
||||
|
||||
- `GET /admin/member/role/list` - 查询角色列表(分页)
|
||||
- `GET /admin/member/role/{roleId}` - 获取角色详情
|
||||
- `POST /admin/member/role` - 新增角色
|
||||
- `PUT /admin/member/role` - 修改角色
|
||||
- `DELETE /admin/member/role/{roleIds}` - 删除角色
|
||||
- `POST /admin/member/role/export` - 导出角色列表
|
||||
- `GET /admin/member/role/optionselect` - 查询角色选项列表
|
||||
- `GET /admin/member/role/authUser/allocatedList` - 查询已分配用户角色列表
|
||||
- `GET /admin/member/role/authUser/unallocatedList` - 查询未分配用户角色列表
|
||||
- `PUT /admin/member/role/authUser/cancelAll` - 取消授权用户所有角色
|
||||
- `PUT /admin/member/role/authUser/selectAll` - 批量选择授权用户角色
|
||||
|
||||
#### 配置管理 (`/admin/member/config`)
|
||||
|
||||
- `GET /admin/member/config/list` - 查询配置列表
|
||||
- `GET /admin/member/config/{configId}` - 获取配置详情
|
||||
- `POST /admin/member/config` - 新增配置
|
||||
- `PUT /admin/member/config` - 修改配置
|
||||
- `DELETE /admin/member/config/{configIds}` - 删除配置
|
||||
- `POST /admin/member/config/export` - 导出配置列表
|
||||
- `DELETE /admin/member/config/refreshCache` - 刷新配置缓存
|
||||
- `GET /admin/member/config/configKey/{configKey}` - 根据配置键查询配置值
|
||||
- `GET /admin/member/config/systemInfo` - 获取系统信息
|
||||
- `GET /admin/member/config/statistics` - 获取统计数据
|
||||
|
||||
### 移动端接口
|
||||
|
||||
#### 用户管理 (`/app/member/user`)
|
||||
|
||||
- `GET /app/member/user/list` - 查询用户列表
|
||||
- `GET /app/member/user/{userId}` - 获取用户详情
|
||||
- `POST /app/member/user` - 新增用户
|
||||
- `PUT /app/member/user` - 修改用户
|
||||
- `DELETE /app/member/user/{userIds}` - 删除用户
|
||||
- `POST /app/member/user/export` - 导出用户列表
|
||||
- `PUT /app/member/user/resetPwd` - 重置密码
|
||||
- `PUT /app/member/user/changeStatus` - 修改状态
|
||||
- `GET /app/member/user/profile/{userId}` - 获取用户资料
|
||||
- `GET /app/member/user/getInfo` - 获取当前用户信息
|
||||
- `GET /app/member/user/profile` - 获取当前用户资料
|
||||
- `PUT /app/member/user/profile` - 修改用户资料
|
||||
- `PUT /app/member/user/profile/updatePwd` - 修改密码
|
||||
|
||||
#### 角色管理 (`/app/member/role`)
|
||||
|
||||
- `GET /app/member/role/list` - 查询角色列表
|
||||
- `GET /app/member/role/{roleId}` - 获取角色详情
|
||||
- `POST /app/member/role` - 新增角色
|
||||
- `PUT /app/member/role` - 修改角色
|
||||
- `DELETE /app/member/role/{roleIds}` - 删除角色
|
||||
- `POST /app/member/role/export` - 导出角色列表
|
||||
- `GET /app/member/role/optionselect` - 查询角色选项列表
|
||||
- `GET /app/member/role/authUser/allocatedList` - 查询已分配用户角色列表
|
||||
- `GET /app/member/role/authUser/unallocatedList` - 查询未分配用户角色列表
|
||||
- `PUT /app/member/role/authUser/cancel` - 取消授权用户角色
|
||||
- `PUT /app/member/role/authUser/cancelAll` - 取消授权用户所有角色
|
||||
- `PUT /app/member/role/authUser/selectAll` - 批量选择授权用户角色
|
||||
|
||||
#### 设备管理 (`/app/member/device`)
|
||||
|
||||
- `GET /app/member/device/list` - 查询设备列表
|
||||
- `GET /app/member/device/{deviceId}` - 获取设备详情
|
||||
- `POST /app/member/device/bind` - 绑定设备
|
||||
- `PUT /app/member/device` - 修改设备信息
|
||||
- `DELETE /app/member/device/{deviceId}` - 解绑设备
|
||||
- `GET /app/member/device/my` - 查询我的设备列表
|
||||
- `GET /app/member/device/active` - 查询活跃设备列表
|
||||
- `PUT /app/member/device/{deviceId}/status` - 更新设备状态
|
||||
- `PUT /app/member/device/{deviceId}/push-token` - 更新推送令牌
|
||||
- `POST /app/member/device/{deviceId}/heartbeat` - 设备心跳
|
||||
- `GET /app/member/device/by-push-token` - 根据推送令牌查询设备
|
||||
|
||||
#### 文件管理 (`/app/member/file`)
|
||||
|
||||
- `GET /app/member/file/list` - 查询文件列表
|
||||
- `GET /app/member/file/{fileId}` - 获取文件详情
|
||||
- `POST /app/member/file` - 新增文件记录
|
||||
- `PUT /app/member/file` - 修改文件信息
|
||||
- `DELETE /app/member/file/{fileIds}` - 删除文件
|
||||
- `POST /app/member/file/upload` - 上传文件
|
||||
- `POST /app/member/file/upload/avatar` - 上传头像
|
||||
- `POST /app/member/file/upload/batch` - 批量上传文件
|
||||
- `GET /app/member/file/category/{fileCategory}` - 按分类查询文件
|
||||
- `GET /app/member/file/download/{fileId}` - 下载文件
|
||||
- `PUT /app/member/file/status/{fileId}` - 更新文件状态
|
||||
- `PUT /app/member/file/public/{fileId}` - 更新文件公开状态
|
||||
- `GET /app/member/file/statistics` - 获取文件统计
|
||||
- `GET /app/member/file/check/{fileMd5}` - 检查文件是否存在
|
||||
- `GET /app/member/file/public/category/{fileCategory}` - 查询公开文件
|
||||
|
||||
#### 消息管理 (`/app/member/message`)
|
||||
|
||||
- `GET /app/member/message/list` - 查询消息列表
|
||||
- `GET /app/member/message/myMessages` - 查询我的消息列表
|
||||
- `GET /app/member/message/unreadCount` - 查询未读消息数量
|
||||
- `GET /app/member/message/{messageId}` - 获取消息详情
|
||||
- `POST /app/member/message` - 新增消息
|
||||
- `PUT /app/member/message` - 修改消息
|
||||
- `DELETE /app/member/message/{messageIds}` - 删除消息
|
||||
- `POST /app/member/message/export` - 导出消息列表
|
||||
- `PUT /app/member/message/markRead/{messageId}` - 标记消息已读
|
||||
- `PUT /app/member/message/markReadBatch` - 批量标记消息已读
|
||||
- `PUT /app/member/message/markAllRead` - 全部标记已读
|
||||
- `POST /app/member/message/sendSystem` - 发送系统消息
|
||||
- `POST /app/member/message/sendPersonal` - 发送个人消息
|
||||
- `POST /app/member/message/push` - 推送消息
|
||||
- `POST /app/member/message/broadcast` - 广播消息
|
||||
|
||||
#### 操作日志 (`/app/member/operlog`)
|
||||
|
||||
- `GET /app/member/operlog/list` - 查询操作日志列表
|
||||
- `GET /app/member/operlog/my` - 查询我的操作日志
|
||||
- `GET /app/member/operlog/{operId}` - 获取操作日志详情
|
||||
- `POST /app/member/operlog` - 新增操作日志
|
||||
- `PUT /app/member/operlog` - 修改操作日志
|
||||
- `DELETE /app/member/operlog/{operIds}` - 删除操作日志
|
||||
- `POST /app/member/operlog/export` - 导出操作日志列表
|
||||
- `DELETE /app/member/operlog/clean` - 清理操作日志
|
||||
- `DELETE /app/member/operlog/cleanByTime` - 按时间清理操作日志
|
||||
- `GET /app/member/operlog/statistics` - 获取操作日志统计
|
||||
- `GET /app/member/operlog/behavior` - 获取行为分析
|
||||
- `GET /app/member/operlog/popular` - 获取热门操作
|
||||
- `GET /app/member/operlog/errors` - 获取错误操作
|
||||
- `POST /app/member/operlog/record` - 记录操作
|
||||
- `POST /app/member/operlog/batchRecord` - 批量记录操作
|
||||
|
||||
#### 版本管理 (`/app/member/version`)
|
||||
|
||||
- `GET /app/member/version/list` - 查询版本列表
|
||||
- `GET /app/member/version/{versionId}` - 获取版本详情
|
||||
- `GET /app/member/version/checkUpdate` - 检查更新
|
||||
- `GET /app/member/version/latest` - 获取最新版本
|
||||
- `GET /app/member/version/history` - 获取版本历史
|
||||
- `GET /app/member/version/checkForceUpdate` - 检查强制更新
|
||||
- `GET /app/member/version/updateInfo` - 获取更新信息
|
||||
- `GET /app/member/version/compare` - 版本对比
|
||||
- `POST /app/member/version/download/{versionId}` - 记录下载
|
||||
- `POST /app/member/version/install/{versionId}` - 记录安装
|
||||
|
||||
### 认证接口
|
||||
|
||||
#### JWT认证 (`/app/jwt`)
|
||||
|
||||
- `GET /app/jwt/captcha` - 获取验证码
|
||||
- `POST /app/jwt/register` - 用户注册
|
||||
- `POST /app/jwt/login` - 用户登录
|
||||
- `POST /app/jwt/refresh` - 刷新Token
|
||||
- `POST /app/jwt/logout` - 用户登出
|
||||
|
||||
#### 第三方账号绑定 (`/app/auth`) - 在 ruoyi-server 模块
|
||||
|
||||
- `POST /app/auth/bind/social` - 绑定第三方账号
|
||||
- `POST /app/auth/unbind/social` - 解绑第三方账号
|
||||
- `GET /app/auth/social/list` - 获取用户绑定的第三方账号列表
|
||||
- `GET /app/auth/binding/{source}` - 获取第三方登录跳转URL
|
||||
- `POST /app/auth/social/binding` - 社交账号绑定回调
|
||||
|
||||
## 技术栈与开发规范
|
||||
|
||||
### 技术栈
|
||||
|
||||
- **框架**: Spring Boot 3.x
|
||||
- **ORM**: MyBatis-Plus
|
||||
- **数据库**: MySQL 8.0+
|
||||
- **认证**: Sa-Token + JWT
|
||||
- **API文档**: Swagger/OpenAPI 3.0
|
||||
- **构建工具**: Maven
|
||||
- **安全**: Spring Security Crypto (BCrypt)
|
||||
|
||||
### 开发规范
|
||||
|
||||
#### 包结构规范
|
||||
|
||||
- `controller` - 控制器层(分为 `admin` 和 `app` 两个子包)
|
||||
- `domain` - 实体类(包含 `bo` 业务对象和 `vo` 视图对象子包)
|
||||
- `mapper` - MyBatis Mapper 接口
|
||||
- `service` - 服务接口(实现类放在 `impl` 子包)
|
||||
- `config` - 配置类(JWT过滤器、Web配置等)
|
||||
- `exception` - 异常处理类
|
||||
- `utils` - 工具类(JWT工具等)
|
||||
|
||||
#### 代码规范
|
||||
|
||||
- 统一使用 Lombok 简化代码
|
||||
- 统一异常处理,使用 `ServiceException` 抛出业务异常
|
||||
- 统一返回格式,使用 `R<T>` 封装返回结果
|
||||
- 统一分页查询,使用 `PageQuery` 和 `TableDataInfo<T>`
|
||||
- 统一日志记录,使用 `@Log` 注解记录操作日志
|
||||
- 统一权限控制,管理端接口使用 `@SaCheckPermission` 注解
|
||||
|
||||
#### 数据库设计规范
|
||||
|
||||
- 表名使用 `app_` 前缀
|
||||
- 字段命名使用下划线命名法(snake_case)
|
||||
- 必须包含 `create_by`, `create_time`, `update_by`, `update_time` 字段
|
||||
- 删除标记使用逻辑删除(`del_flag` 字段)
|
||||
- 状态字段统一使用 `status`,0表示启用/正常,1表示禁用/异常
|
||||
|
||||
#### API设计规范
|
||||
|
||||
- RESTful 风格设计
|
||||
- 管理端接口路径:`/admin/member/{module}/{resource}`
|
||||
- 移动端接口路径:`/app/member/{module}/{resource}`
|
||||
- 使用 HTTP 标准方法:GET(查询)、POST(新增)、PUT(修改)、DELETE(删除)
|
||||
- 统一使用 JSON 格式进行数据交互
|
||||
- 使用 Swagger 注解完善接口文档
|
||||
|
||||
## 模块依赖关系
|
||||
|
||||
```
|
||||
ruoyi-member (会员中心模块)
|
||||
├── 依赖: ruoyi-common-* (通用工具模块)
|
||||
│ ├── ruoyi-common-core (核心工具)
|
||||
│ ├── ruoyi-common-doc (API文档)
|
||||
│ ├── ruoyi-common-log (日志)
|
||||
│ ├── ruoyi-common-mybatis (MyBatis)
|
||||
│ ├── ruoyi-common-security (安全)
|
||||
│ ├── ruoyi-common-web (Web)
|
||||
│ ├── ruoyi-common-excel (Excel)
|
||||
│ ├── ruoyi-common-translation (翻译)
|
||||
│ ├── ruoyi-common-social (社交登录)
|
||||
│ ├── ruoyi-common-satoken (权限认证)
|
||||
│ └── ruoyi-common-oss (对象存储)
|
||||
├── 依赖: sa-token-spring-boot3-starter (Sa-Token)
|
||||
├── 依赖: sa-token-jwt (JWT支持)
|
||||
└── 依赖: spring-security-crypto (密码加密)
|
||||
```
|
||||
|
||||
## 模块集成说明
|
||||
|
||||
### 与 ruoyi-server 模块的集成
|
||||
|
||||
- **登录功能集成**: 手机号登录、邮箱登录功能在 `ruoyi-server` 模块实现
|
||||
- `AppSmsAuthStrategy` - 手机号登录策略
|
||||
- `AppEmailAuthStrategy` - 邮箱登录策略
|
||||
- `CaptchaController` - 验证码发送接口
|
||||
- **第三方账号绑定集成**: 第三方账号绑定/解绑功能在 `ruoyi-server` 模块实现
|
||||
- `AppAuthController` - 提供绑定/解绑接口
|
||||
- **用户服务集成**: `ruoyi-server` 模块通过依赖 `ruoyi-member` 模块使用用户服务
|
||||
|
||||
### 与其他模块的集成
|
||||
|
||||
- **文件存储**: 依赖 `ruoyi-common-oss` 模块,支持对象存储服务集成(OSS、COS等)
|
||||
- **社交登录**: 依赖 `ruoyi-common-social` 模块,支持第三方登录(微信、QQ、微博等)
|
||||
- **权限认证**: 依赖 `ruoyi-common-satoken` 模块,使用 Sa-Token 进行权限管理
|
||||
|
||||
## 下一步工作
|
||||
|
||||
### 功能完善
|
||||
|
||||
1. **用户管理增强**
|
||||
- [x] 手机号/邮箱登录功能 ✅(已在 ruoyi-server 模块实现)
|
||||
- [x] 第三方账号绑定/解绑功能 ✅(已在 ruoyi-server 模块实现)
|
||||
- [ ] 忘记密码功能(通过手机号/邮箱验证码找回密码)
|
||||
- [ ] 独立的手机号/邮箱绑定功能(当前可通过更新用户资料方式修改)
|
||||
- [ ] 用户等级体系
|
||||
- [ ] 用户标签管理
|
||||
|
||||
2. **角色权限系统**
|
||||
- [ ] 权限点管理
|
||||
- [ ] 角色权限配置
|
||||
- [ ] 数据权限管理
|
||||
|
||||
3. **消息推送集成**
|
||||
- [ ] 集成推送服务(极光推送、个推等)
|
||||
- [ ] 消息推送功能完善
|
||||
- [ ] 推送统计功能
|
||||
|
||||
4. **文件管理增强**
|
||||
- [ ] 文件存储服务集成(OSS、COS等)
|
||||
- [ ] 文件预览功能
|
||||
- [ ] 文件分享功能
|
||||
|
||||
5. **安全增强**
|
||||
- [ ] Token黑名单机制
|
||||
- [ ] 多端登录管理
|
||||
- [ ] 异常登录检测
|
||||
- [ ] 登录IP白名单/黑名单
|
||||
|
||||
6. **日志分析**
|
||||
- [ ] 操作日志分析功能
|
||||
- [ ] 登录日志分析功能
|
||||
- [ ] 日志告警功能
|
||||
|
||||
### 性能优化
|
||||
|
||||
1. **缓存优化**
|
||||
- [ ] 用户信息缓存(Redis)
|
||||
- [ ] 角色权限缓存
|
||||
- [ ] 配置信息缓存
|
||||
|
||||
2. **数据库优化**
|
||||
- [ ] 索引优化
|
||||
- [ ] 查询优化
|
||||
- [ ] 分表策略(日志表)
|
||||
|
||||
### 测试验证
|
||||
|
||||
1. **单元测试**
|
||||
- [ ] Service层单元测试
|
||||
- [ ] Controller层单元测试
|
||||
|
||||
2. **集成测试**
|
||||
- [ ] API接口测试
|
||||
- [ ] 业务流程测试
|
||||
|
||||
## 开发指南
|
||||
|
||||
### 新增功能开发步骤
|
||||
|
||||
1. **数据库设计**
|
||||
- 设计表结构(遵循数据库设计规范)
|
||||
- 确保字段命名规范,包含必要的索引
|
||||
- 添加必要的状态字段和逻辑删除字段
|
||||
|
||||
2. **创建实体类**
|
||||
- 在 `domain` 包下创建实体类
|
||||
- 创建对应的 `Bo`(业务对象)和 `Vo`(视图对象)
|
||||
- 使用 Lombok 简化代码
|
||||
|
||||
3. **创建 Mapper**
|
||||
- 在 `mapper` 包下创建 Mapper 接口
|
||||
- 继承 `BaseMapper<T>` 获得基础 CRUD 功能
|
||||
- 如需复杂查询,在 `resources/mapper/member` 下创建 XML 文件
|
||||
|
||||
4. **创建 Service**
|
||||
- 在 `service` 包下创建 Service 接口
|
||||
- 在 `service/impl` 包下创建 Service 实现类
|
||||
- 实现业务逻辑,使用事务注解保证数据一致性
|
||||
|
||||
5. **创建 Controller**
|
||||
- 管理端接口:在 `controller/admin` 包下创建
|
||||
- 移动端接口:在 `controller/app` 包下创建
|
||||
- 添加 Swagger 注解完善接口文档
|
||||
- 添加权限控制注解(管理端使用 `@SaCheckPermission`)
|
||||
|
||||
6. **测试验证**
|
||||
- 编写单元测试(可选)
|
||||
- 使用 Swagger UI 测试接口
|
||||
- 验证业务逻辑正确性
|
||||
|
||||
### 代码迁移指南
|
||||
|
||||
如果要将现有代码迁移到新的模块结构:
|
||||
|
||||
1. **创建新模块结构**(如果尚未创建)
|
||||
2. **复制代码到新模块**
|
||||
3. **修改包名**(如需要)
|
||||
4. **更新导入语句**
|
||||
5. **更新 Mapper XML 文件中的命名空间**
|
||||
6. **测试验证功能正常**
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **登录功能**: 手机号登录、邮箱登录功能已在 `ruoyi-server` 模块实现(通过 `AppSmsAuthStrategy` 和 `AppEmailAuthStrategy`),验证码发送功能通过 `CaptchaController` 提供
|
||||
2. **密码安全**: 用户密码使用 BCrypt 加密,确保密码安全存储
|
||||
3. **Token安全**: JWT Token 需要设置合理的过期时间,建议使用 Refresh Token 机制
|
||||
4. **文件上传**: 文件上传需要限制文件大小和类型,防止恶意文件上传
|
||||
5. **消息推送**: 消息推送需要集成第三方推送服务,注意推送频率限制
|
||||
6. **日志管理**: 操作日志和登录日志会随着时间增长,建议定期清理或归档
|
||||
7. **设备管理**: 设备绑定需要考虑设备唯一性,避免重复绑定
|
||||
8. **社交登录**: 第三方登录需要配置相应的应用ID和密钥
|
||||
9. **数据一致性**: 用户删除需要考虑关联数据(设备、文件、消息等)的处理
|
||||
10. **并发安全**: 用户注册、登录等操作需要考虑并发安全性
|
||||
11. **异常处理**: 需要统一异常处理,避免敏感信息泄露
|
||||
12. **模块集成**: 注意与 `ruoyi-server` 模块的集成关系,部分功能(如登录、第三方绑定)在 server 模块实现
|
||||
13. **配置管理**: JWT 过滤器配置在 `AppJwtWebConfig` 中,需要正确配置过滤路径
|
||||
14. **权限控制**: 管理端接口需要添加权限控制,移动端接口需要添加登录验证
|
||||
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-member</artifactId>
|
||||
|
||||
<description>
|
||||
ruoyi-member 会员中心模块
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-doc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-log</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-mybatis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-excel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-translation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-social</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-satoken</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-oss</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 整合 jwt -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-jwt</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-crypto</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,81 @@
|
||||
package org.dromara.member.config;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.redis.utils.RedisUtils;
|
||||
import org.dromara.member.utils.JwtUtil;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* JWT过滤器
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AppJwtFilter extends OncePerRequestFilter {
|
||||
|
||||
@Value("${ruoyi.app.jwt.secret:ruoyi-secret}")
|
||||
private String jwtSecret;
|
||||
private static final String BLACKLIST_PREFIX = "APP:JWT:BLACKLIST:";
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
String path = request.getRequestURI();
|
||||
// 仅保护敏感接口
|
||||
if (requiresAuth(path)) {
|
||||
String auth = request.getHeader("Authorization");
|
||||
if (auth == null || !auth.startsWith("Bearer ")) {
|
||||
write401(response);
|
||||
return;
|
||||
}
|
||||
String token = auth.substring("Bearer ".length()).trim();
|
||||
JwtUtil jwt = new JwtUtil(jwtSecret);
|
||||
if (!jwt.verify(token)) {
|
||||
write401(response);
|
||||
return;
|
||||
}
|
||||
Map<String, Object> payload = jwt.parsePayload(token);
|
||||
Object expObj = payload.get("exp");
|
||||
long now = java.time.Instant.now().getEpochSecond();
|
||||
long exp = expObj instanceof Number ? ((Number) expObj).longValue() : now;
|
||||
if (exp < now) {
|
||||
write401(response);
|
||||
return;
|
||||
}
|
||||
String jti = String.valueOf(payload.get("jti"));
|
||||
String bl = RedisUtils.getCacheObject(BLACKLIST_PREFIX + jti);
|
||||
if (bl != null) {
|
||||
write401(response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
private boolean requiresAuth(String path) {
|
||||
if (path == null) return false;
|
||||
// 保护系统会话/消息/用户/文件等接口
|
||||
return path.startsWith("/system/session")
|
||||
|| path.startsWith("/system/message")
|
||||
|| path.startsWith("/app/user")
|
||||
|| path.startsWith("/app/file");
|
||||
}
|
||||
|
||||
private void write401(HttpServletResponse response) throws IOException {
|
||||
response.setStatus(401);
|
||||
response.setContentType("application/json");
|
||||
response.getOutputStream().write("{\"code\":401,\"msg\":\"Unauthorized\",\"data\":null}".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package org.dromara.member.config;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* JWT Web配置
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class AppJwtWebConfig {
|
||||
private final AppJwtFilter appJwtFilter;
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<AppJwtFilter> appJwtFilterRegistration() {
|
||||
FilterRegistrationBean<AppJwtFilter> bean = new FilterRegistrationBean<>();
|
||||
bean.setFilter(appJwtFilter);
|
||||
// 设置过滤路径
|
||||
bean.addUrlPatterns("/system/session/*", "/system/message/*", "/app/user/*", "/app/file/*");
|
||||
bean.setName("AppJwtFilter");
|
||||
// 设置优先级,越小越靠前
|
||||
bean.setOrder(10);
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
||||
+266
@@ -0,0 +1,266 @@
|
||||
package org.dromara.member.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.member.domain.bo.AppFileBo;
|
||||
import org.dromara.member.domain.vo.AppFileVo;
|
||||
import org.dromara.member.service.AppFileService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端文件信息Controller
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Tag(name = "App端文件管理", description = "App端文件信息管理接口")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/app/file")
|
||||
public class AppFileController extends BaseController {
|
||||
|
||||
private final AppFileService appFileService;
|
||||
|
||||
/**
|
||||
* 查询App端文件信息列表
|
||||
*/
|
||||
@Operation(summary = "查询文件列表", description = "分页查询当前用户的文件信息列表")
|
||||
@SaCheckLogin
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<AppFileVo> list(
|
||||
@Parameter(description = "文件查询条件") @Valid AppFileBo bo,
|
||||
@Parameter(description = "分页参数") @Valid PageQuery pageQuery) {
|
||||
// 只能查询自己的文件
|
||||
bo.setUserId(LoginHelper.getUserId());
|
||||
return appFileService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取App端文件信息详细信息
|
||||
*/
|
||||
@Operation(summary = "获取文件详情", description = "根据文件ID获取文件详细信息")
|
||||
@SaCheckLogin
|
||||
@GetMapping("/{fileId}")
|
||||
public R<AppFileVo> getInfo(
|
||||
@Parameter(description = "文件ID", required = true)
|
||||
@PathVariable @NotNull(message = "文件ID不能为空") @Positive(message = "文件ID必须为正数") Long fileId) {
|
||||
AppFileVo fileVo = appFileService.queryById(fileId);
|
||||
if (fileVo == null) {
|
||||
return R.fail("文件不存在");
|
||||
}
|
||||
// 检查权限
|
||||
if (!fileVo.getUserId().equals(LoginHelper.getUserId()) && !"1".equals(fileVo.getIsPublic())) {
|
||||
return R.fail("无权限访问该文件");
|
||||
}
|
||||
return R.ok(fileVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增App端文件信息
|
||||
*/
|
||||
@Operation(summary = "新增文件信息", description = "添加新的文件信息记录")
|
||||
@SaCheckLogin
|
||||
@Log(title = "App端文件信息", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public R<Void> add(
|
||||
@Parameter(description = "文件信息", required = true)
|
||||
@Validated(AddGroup.class) @RequestBody AppFileBo bo) {
|
||||
bo.setUserId(LoginHelper.getUserId());
|
||||
return toAjax(appFileService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改App端文件信息
|
||||
*/
|
||||
@Operation(summary = "修改文件信息", description = "更新文件信息记录")
|
||||
@SaCheckLogin
|
||||
@Log(title = "App端文件信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public R<Void> edit(
|
||||
@Parameter(description = "文件信息", required = true)
|
||||
@Validated(EditGroup.class) @RequestBody AppFileBo bo) {
|
||||
// 检查权限
|
||||
AppFileVo existFile = appFileService.queryById(bo.getFileId());
|
||||
if (existFile == null) {
|
||||
return R.fail("文件不存在");
|
||||
}
|
||||
if (!existFile.getUserId().equals(LoginHelper.getUserId())) {
|
||||
return R.fail("无权限修改该文件");
|
||||
}
|
||||
return toAjax(appFileService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除App端文件信息
|
||||
*/
|
||||
@Operation(summary = "删除文件", description = "批量删除文件信息")
|
||||
@SaCheckLogin
|
||||
@Log(title = "App端文件信息", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{fileIds}")
|
||||
public R<Void> remove(
|
||||
@Parameter(description = "文件ID列表", required = true)
|
||||
@PathVariable @NotEmpty(message = "文件ID列表不能为空") Long[] fileIds) {
|
||||
return toAjax(appFileService.batchDeleteUserFiles(Arrays.asList(fileIds), LoginHelper.getUserId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*/
|
||||
@Operation(summary = "上传文件", description = "上传单个文件")
|
||||
@SaCheckLogin
|
||||
@Log(title = "文件上传", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/upload")
|
||||
public R<AppFileVo> uploadFile(
|
||||
@Parameter(description = "上传的文件", required = true)
|
||||
@RequestParam("file") @NotNull(message = "上传文件不能为空") MultipartFile file,
|
||||
@Parameter(description = "文件分类")
|
||||
@RequestParam(value = "fileCategory", required = false) @Min(value = 0, message = "文件分类不能为负数") Integer fileCategory) {
|
||||
AppFileVo result = appFileService.uploadFile(file, LoginHelper.getUserId(), fileCategory);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传头像
|
||||
*/
|
||||
@Operation(summary = "上传头像", description = "上传用户头像文件")
|
||||
@SaCheckLogin
|
||||
@Log(title = "头像上传", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/upload/avatar")
|
||||
public R<AppFileVo> uploadAvatar(
|
||||
@Parameter(description = "头像文件", required = true)
|
||||
@RequestParam("file") @NotNull(message = "头像文件不能为空") MultipartFile file) {
|
||||
AppFileVo result = appFileService.uploadAvatar(file, LoginHelper.getUserId());
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量上传文件
|
||||
*/
|
||||
@Operation(summary = "批量上传文件", description = "批量上传多个文件")
|
||||
@SaCheckLogin
|
||||
@Log(title = "批量文件上传", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/upload/batch")
|
||||
public R<List<AppFileVo>> batchUploadFiles(
|
||||
@Parameter(description = "上传的文件列表", required = true)
|
||||
@RequestParam("files") @NotEmpty(message = "上传文件列表不能为空") MultipartFile[] files,
|
||||
@Parameter(description = "文件分类")
|
||||
@RequestParam(value = "fileCategory", required = false) @Min(value = 0, message = "文件分类不能为负数") Integer fileCategory) {
|
||||
List<AppFileVo> result = appFileService.batchUploadFiles(files, LoginHelper.getUserId(), fileCategory);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件分类查询文件列表
|
||||
*/
|
||||
@Operation(summary = "根据分类获取文件", description = "获取指定分类的文件列表")
|
||||
@SaCheckLogin
|
||||
@GetMapping("/category/{fileCategory}")
|
||||
public R<List<AppFileVo>> getFilesByCategory(
|
||||
@Parameter(description = "文件分类", required = true)
|
||||
@PathVariable @NotNull(message = "文件分类不能为空") @Min(value = 0, message = "文件分类不能为负数") Integer fileCategory) {
|
||||
List<AppFileVo> result = appFileService.queryByUserId(LoginHelper.getUserId(), fileCategory);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*/
|
||||
@Operation(summary = "下载文件", description = "根据文件ID下载文件")
|
||||
@SaCheckLogin
|
||||
@Log(title = "文件下载", businessType = BusinessType.OTHER)
|
||||
@GetMapping("/download/{fileId}")
|
||||
public R<AppFileVo> downloadFile(
|
||||
@Parameter(description = "文件ID", required = true)
|
||||
@PathVariable @NotNull(message = "文件ID不能为空") @Positive(message = "文件ID必须为正数") Long fileId) {
|
||||
AppFileVo result = appFileService.downloadFile(fileId, LoginHelper.getUserId());
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新文件状态
|
||||
*/
|
||||
@Operation(summary = "更新文件状态", description = "更新文件的状态信息")
|
||||
@SaCheckLogin
|
||||
@Log(title = "更新文件状态", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/status/{fileId}")
|
||||
public R<Void> updateFileStatus(
|
||||
@Parameter(description = "文件ID", required = true)
|
||||
@PathVariable @NotNull(message = "文件ID不能为空") @Positive(message = "文件ID必须为正数") Long fileId,
|
||||
@Parameter(description = "文件状态(0-正常,1-禁用)", required = true)
|
||||
@RequestParam @NotBlank(message = "文件状态不能为空") @Pattern(regexp = "^(0|1)$", message = "文件状态只能为0或1") String status) {
|
||||
return toAjax(appFileService.updateFileStatus(fileId, status, LoginHelper.getUserId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新文件公开状态
|
||||
*/
|
||||
@Operation(summary = "更新文件公开状态", description = "设置文件是否公开")
|
||||
@SaCheckLogin
|
||||
@Log(title = "更新文件公开状态", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/public/{fileId}")
|
||||
public R<Void> updateFilePublicStatus(
|
||||
@Parameter(description = "文件ID", required = true)
|
||||
@PathVariable @NotNull(message = "文件ID不能为空") @Positive(message = "文件ID必须为正数") Long fileId,
|
||||
@Parameter(description = "是否公开(0-私有,1-公开)", required = true)
|
||||
@RequestParam @NotBlank(message = "公开状态不能为空") @Pattern(regexp = "^(0|1)$", message = "公开状态只能为0或1") String isPublic) {
|
||||
return toAjax(appFileService.updateFilePublicStatus(fileId, isPublic, LoginHelper.getUserId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户文件统计信息
|
||||
*/
|
||||
@Operation(summary = "获取文件统计", description = "获取当前用户的文件统计信息")
|
||||
@SaCheckLogin
|
||||
@GetMapping("/statistics")
|
||||
public R<AppFileVo> getUserFileStatistics() {
|
||||
AppFileVo result = appFileService.getUserFileStatistics(LoginHelper.getUserId());
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件是否存在
|
||||
*/
|
||||
@Operation(summary = "检查文件是否存在", description = "根据MD5值检查文件是否已存在")
|
||||
@SaCheckLogin
|
||||
@GetMapping("/check/{fileMd5}")
|
||||
public R<AppFileVo> checkFileExists(
|
||||
@Parameter(description = "文件MD5值", required = true)
|
||||
@PathVariable @NotBlank(message = "文件MD5不能为空") @Size(min = 32, max = 32, message = "MD5长度必须为32位") String fileMd5) {
|
||||
AppFileVo result = appFileService.checkFileExists(fileMd5, LoginHelper.getUserId());
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询公开文件列表
|
||||
*/
|
||||
@Operation(summary = "查询公开文件列表", description = "获取指定分类的公开文件列表")
|
||||
@SaIgnore
|
||||
@GetMapping("/public/category/{fileCategory}")
|
||||
public R<List<AppFileVo>> getPublicFilesByCategory(
|
||||
@Parameter(description = "文件分类", required = true)
|
||||
@PathVariable @NotNull(message = "文件分类不能为空") @Min(value = 0, message = "文件分类不能为负数") Integer fileCategory) {
|
||||
List<AppFileVo> result = appFileService.queryByCategory(fileCategory);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
package org.dromara.member.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.redis.utils.RedisUtils;
|
||||
import org.dromara.member.utils.JwtUtil;
|
||||
import org.dromara.member.domain.AppUser;
|
||||
import org.dromara.member.mapper.AppUserMapper;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* JWT认证控制器
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@SaIgnore
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/app/auth/jwt")
|
||||
public class AppJwtController {
|
||||
|
||||
private final AppUserMapper appUserMapper;
|
||||
|
||||
@Value("${ruoyi.app.jwt.secret:ruoyi-secret}")
|
||||
private String jwtSecret;
|
||||
@Value("${ruoyi.app.jwt.access-ttl-seconds:7200}")
|
||||
private long accessTtlSeconds;
|
||||
@Value("${ruoyi.app.jwt.refresh-ttl-seconds:604800}")
|
||||
private long refreshTtlSeconds;
|
||||
private static final String CAPTCHA_PREFIX = "APP:JWT:CAPTCHA:";
|
||||
private static final String BLACKLIST_PREFIX = "APP:JWT:BLACKLIST:";
|
||||
private static final String TOKEN_JTI_PREFIX = "APP:JWT:JTI:";
|
||||
private static final String USER_TOKENS_PREFIX = "APP:JWT:USER_TOKENS:";
|
||||
private static final String LOGIN_FAIL_PREFIX = "APP:JWT:LOGIN_FAIL:";
|
||||
|
||||
@Operation(summary = "生成图形验证码(4位字母数字)")
|
||||
@GetMapping("/captcha")
|
||||
public R<Map<String, String>> captcha() {
|
||||
String code = randomCode(4);
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
RedisUtils.setCacheObject(CAPTCHA_PREFIX + uuid, code, Duration.ofMinutes(5));
|
||||
// 这里简化为直接返回文本验证码;实际可返回Base64图片
|
||||
return R.ok(Map.of("uuid", uuid, "code", code));
|
||||
}
|
||||
|
||||
@Operation(summary = "注册")
|
||||
@PostMapping("/register")
|
||||
public R<Void> register(
|
||||
@Parameter(description = "手机号(+86或11位)") @RequestParam @Pattern(regexp = "^(\\+86\\d{11}|\\d{11})$") String phone,
|
||||
@Parameter(description = "密码") @RequestParam @Size(min = 6, max = 64) String password,
|
||||
@Parameter(description = "验证码uuid") @RequestParam @NotBlank String captchaUuid,
|
||||
@Parameter(description = "验证码") @RequestParam @NotBlank String captchaCode) {
|
||||
if (!verifyCaptcha(captchaUuid, captchaCode)) {
|
||||
return R.fail("验证码错误");
|
||||
}
|
||||
AppUser exist = findByPhone(phone);
|
||||
if (exist != null) {
|
||||
return R.fail("手机号已注册");
|
||||
}
|
||||
org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder enc = new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder(12);
|
||||
AppUser u = new AppUser();
|
||||
u.setPhone(phone);
|
||||
u.setPassword(enc.encode(password));
|
||||
boolean ok = appUserMapper.insert(u) > 0;
|
||||
return ok ? R.ok() : R.fail("注册失败");
|
||||
}
|
||||
|
||||
@Operation(summary = "登录")
|
||||
@PostMapping("/login")
|
||||
public R<Map<String, Object>> login(
|
||||
@Parameter(description = "手机号(+86或11位)") @RequestParam @Pattern(regexp = "^(\\+86\\d{11}|\\d{11})$") String phone,
|
||||
@Parameter(description = "密码") @RequestParam @Size(min = 6, max = 64) String password,
|
||||
@Parameter(description = "验证码uuid") @RequestParam @NotBlank String captchaUuid,
|
||||
@Parameter(description = "验证码") @RequestParam @NotBlank String captchaCode) {
|
||||
if (!verifyCaptcha(captchaUuid, captchaCode)) {
|
||||
return R.fail("验证码错误");
|
||||
}
|
||||
String failKey = LOGIN_FAIL_PREFIX + phone;
|
||||
Integer cnt = RedisUtils.getCacheObject(failKey);
|
||||
if (cnt != null && cnt >= 5) {
|
||||
return R.fail("登录失败次数过多,请稍后再试");
|
||||
}
|
||||
AppUser user = findByPhone(phone);
|
||||
org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder enc = new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder(12);
|
||||
if (user == null || !enc.matches(password, user.getPassword())) {
|
||||
int n = (cnt == null ? 0 : cnt) + 1;
|
||||
RedisUtils.setCacheObject(failKey, n, Duration.ofHours(1));
|
||||
return R.fail("手机号或密码错误");
|
||||
}
|
||||
JwtUtil jwt = new JwtUtil(jwtSecret);
|
||||
String jti = UUID.randomUUID().toString();
|
||||
String access = jwt.generateToken(String.valueOf(user.getUserId()), accessTtlSeconds, jti);
|
||||
String refresh = jwt.generateToken("refresh:" + user.getUserId(), refreshTtlSeconds, UUID.randomUUID().toString());
|
||||
RedisUtils.setCacheObject(TOKEN_JTI_PREFIX + jti, "1", Duration.ofSeconds(accessTtlSeconds));
|
||||
limitUserDevices(user.getUserId(), jti);
|
||||
Map<String, Object> data = new LinkedHashMap<>();
|
||||
data.put("accessToken", access);
|
||||
data.put("refreshToken", refresh);
|
||||
data.put("expiresIn", accessTtlSeconds);
|
||||
return R.ok(data);
|
||||
}
|
||||
|
||||
@Operation(summary = "刷新Token")
|
||||
@PostMapping("/refresh")
|
||||
public R<Map<String, Object>> refresh(@Parameter(description = "刷新令牌") @RequestParam String refreshToken) {
|
||||
JwtUtil jwt = new JwtUtil(jwtSecret);
|
||||
if (!jwt.verify(refreshToken)) return R.fail("刷新令牌无效");
|
||||
Map<String, Object> payload = jwt.parsePayload(refreshToken);
|
||||
String sub = String.valueOf(payload.get("sub"));
|
||||
if (sub == null || !sub.startsWith("refresh:")) return R.fail("刷新令牌错误");
|
||||
String userId = sub.substring("refresh:".length());
|
||||
String jti = UUID.randomUUID().toString();
|
||||
String access = jwt.generateToken(userId, accessTtlSeconds, jti);
|
||||
RedisUtils.setCacheObject(TOKEN_JTI_PREFIX + jti, "1", Duration.ofSeconds(accessTtlSeconds));
|
||||
limitUserDevices(Long.parseLong(userId), jti);
|
||||
return R.ok(Map.of("accessToken", access, "expiresIn", accessTtlSeconds));
|
||||
}
|
||||
|
||||
@Operation(summary = "注销")
|
||||
@PostMapping("/logout")
|
||||
public R<Void> logout(@Parameter(description = "访问令牌") @RequestParam String accessToken) {
|
||||
JwtUtil jwt = new JwtUtil(jwtSecret);
|
||||
if (!jwt.verify(accessToken)) return R.fail("令牌无效");
|
||||
Map<String, Object> payload = jwt.parsePayload(accessToken);
|
||||
String jti = String.valueOf(payload.get("jti"));
|
||||
Object expObj = payload.get("exp");
|
||||
long now = java.time.Instant.now().getEpochSecond();
|
||||
long exp = expObj instanceof Number ? ((Number) expObj).longValue() : now;
|
||||
long remain = Math.max(0, exp - now);
|
||||
RedisUtils.setCacheObject(BLACKLIST_PREFIX + jti, "1", Duration.ofSeconds(remain));
|
||||
RedisUtils.deleteObject(TOKEN_JTI_PREFIX + jti);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
private boolean verifyCaptcha(String uuid, String code) {
|
||||
String real = RedisUtils.getCacheObject(CAPTCHA_PREFIX + uuid);
|
||||
return real != null && real.equalsIgnoreCase(code);
|
||||
}
|
||||
|
||||
private String randomCode(int n) {
|
||||
String chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
java.util.Random r = new java.util.Random();
|
||||
for (int i = 0; i < n; i++) sb.append(chars.charAt(r.nextInt(chars.length())));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void limitUserDevices(Long userId, String jti) {
|
||||
String listKey = USER_TOKENS_PREFIX + userId;
|
||||
java.util.List<String> list = RedisUtils.getCacheObject(listKey);
|
||||
if (list == null) list = new java.util.ArrayList<>();
|
||||
list.add(0, jti);
|
||||
while (list.size() > 3) {
|
||||
String old = list.remove(list.size() - 1);
|
||||
RedisUtils.setCacheObject(BLACKLIST_PREFIX + old, "1", Duration.ofHours(2));
|
||||
RedisUtils.deleteObject(TOKEN_JTI_PREFIX + old);
|
||||
}
|
||||
RedisUtils.setCacheObject(listKey, list, Duration.ofDays(8));
|
||||
}
|
||||
|
||||
private AppUser findByPhone(String phone) {
|
||||
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<AppUser> lqw = com.baomidou.mybatisplus.core.toolkit.Wrappers.lambdaQuery();
|
||||
lqw.eq(AppUser::getPhone, phone);
|
||||
return appUserMapper.selectOne(lqw);
|
||||
}
|
||||
}
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
package org.dromara.member.controller.admin;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 管理端系统配置
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Tag(name = "管理端系统配置", description = "系统配置管理接口")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/admin/config")
|
||||
public class AdminConfigController extends BaseController {
|
||||
|
||||
/**
|
||||
* 查询系统配置列表
|
||||
*/
|
||||
@Operation(summary = "查询配置列表", description = "分页查询系统配置列表")
|
||||
@SaCheckPermission("admin:config:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<Map<String, Object>> list(
|
||||
@Parameter(description = "分页参数") PageQuery pageQuery) {
|
||||
// 模拟配置数据
|
||||
TableDataInfo<Map<String, Object>> dataInfo = new TableDataInfo<>();
|
||||
dataInfo.setCode(200);
|
||||
dataInfo.setMsg("查询成功");
|
||||
dataInfo.setTotal(0L);
|
||||
dataInfo.setRows(List.of());
|
||||
return dataInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出系统配置列表
|
||||
*/
|
||||
@Operation(summary = "导出配置列表", description = "导出系统配置到Excel")
|
||||
@SaCheckPermission("admin:config:export")
|
||||
@Log(title = "系统配置", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response) {
|
||||
// 导出逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统配置详细信息
|
||||
*/
|
||||
@Operation(summary = "获取配置详情", description = "根据配置ID获取详细信息")
|
||||
@SaCheckPermission("admin:config:query")
|
||||
@GetMapping("/{configId}")
|
||||
public R<Map<String, Object>> getInfo(
|
||||
@Parameter(description = "配置ID", required = true)
|
||||
@NotNull(message = "主键不能为空") @PathVariable Long configId) {
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.put("configId", configId);
|
||||
config.put("configName", "示例配置");
|
||||
config.put("configKey", "example.config");
|
||||
config.put("configValue", "示例值");
|
||||
return R.ok(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增系统配置
|
||||
*/
|
||||
@Operation(summary = "新增配置", description = "创建新的系统配置")
|
||||
@SaCheckPermission("admin:config:add")
|
||||
@Log(title = "系统配置", businessType = BusinessType.INSERT)
|
||||
@PostMapping()
|
||||
public R<Void> add(
|
||||
@Parameter(description = "配置信息", required = true)
|
||||
@Validated(AddGroup.class) @RequestBody Map<String, Object> config) {
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改系统配置
|
||||
*/
|
||||
@Operation(summary = "修改配置", description = "更新系统配置信息")
|
||||
@SaCheckPermission("admin:config:edit")
|
||||
@Log(title = "系统配置", businessType = BusinessType.UPDATE)
|
||||
@PutMapping()
|
||||
public R<Void> edit(
|
||||
@Parameter(description = "配置信息", required = true)
|
||||
@Validated(EditGroup.class) @RequestBody Map<String, Object> config) {
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除系统配置
|
||||
*/
|
||||
@Operation(summary = "删除配置", description = "批量删除系统配置")
|
||||
@SaCheckPermission("admin:config:remove")
|
||||
@Log(title = "系统配置", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{configIds}")
|
||||
public R<Void> remove(
|
||||
@Parameter(description = "配置ID列表", required = true)
|
||||
@NotEmpty(message = "主键不能为空") @PathVariable Long[] configIds) {
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新参数缓存
|
||||
*/
|
||||
@Operation(summary = "刷新缓存", description = "刷新系统配置缓存")
|
||||
@SaCheckPermission("admin:config:remove")
|
||||
@Log(title = "系统配置", businessType = BusinessType.CLEAN)
|
||||
@DeleteMapping("/refreshCache")
|
||||
public R<Void> refreshCache() {
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据参数键名查询参数值
|
||||
*/
|
||||
@Operation(summary = "根据键名查询配置", description = "根据配置键名获取配置值")
|
||||
@GetMapping("/configKey/{configKey}")
|
||||
public R<String> getConfigKey(
|
||||
@Parameter(description = "配置键名", required = true)
|
||||
@PathVariable String configKey) {
|
||||
return R.ok("配置值");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统信息
|
||||
*/
|
||||
@Operation(summary = "获取系统信息", description = "获取系统运行信息")
|
||||
@SaCheckPermission("admin:config:query")
|
||||
@GetMapping("/systemInfo")
|
||||
public R<Map<String, Object>> getSystemInfo() {
|
||||
Map<String, Object> systemInfo = new HashMap<>();
|
||||
systemInfo.put("systemName", "RuoYi-Unity-AI管理系统");
|
||||
systemInfo.put("version", "5.X");
|
||||
systemInfo.put("author", "RuoYi");
|
||||
systemInfo.put("javaVersion", System.getProperty("java.version"));
|
||||
systemInfo.put("osName", System.getProperty("os.name"));
|
||||
return R.ok(systemInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统统计信息
|
||||
*/
|
||||
@Operation(summary = "获取统计信息", description = "获取系统统计数据")
|
||||
@SaCheckPermission("admin:config:query")
|
||||
@GetMapping("/statistics")
|
||||
public R<Map<String, Object>> getStatistics() {
|
||||
Map<String, Object> statistics = new HashMap<>();
|
||||
statistics.put("totalUsers", 0);
|
||||
statistics.put("totalRoles", 0);
|
||||
statistics.put("onlineUsers", 0);
|
||||
statistics.put("todayVisits", 0);
|
||||
return R.ok(statistics);
|
||||
}
|
||||
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
package org.dromara.member.controller.admin;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.member.domain.bo.AppRoleBo;
|
||||
import org.dromara.member.domain.vo.AppRoleVo;
|
||||
import org.dromara.member.service.AppRoleService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 管理端角色信息
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Tag(name = "管理端角色管理", description = "管理端角色信息管理接口")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/admin/role")
|
||||
public class AdminRoleController extends BaseController {
|
||||
|
||||
private final AppRoleService appRoleService;
|
||||
|
||||
/**
|
||||
* 查询管理端角色信息列表
|
||||
*/
|
||||
@Operation(summary = "查询角色列表", description = "分页查询管理端角色信息列表")
|
||||
@SaCheckPermission("admin:role:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<AppRoleVo> list(@Parameter(description = "角色查询条件") AppRoleBo bo,
|
||||
@Parameter(description = "分页参数") PageQuery pageQuery) {
|
||||
return appRoleService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出管理端角色信息列表
|
||||
*/
|
||||
@Operation(summary = "导出角色列表", description = "导出管理端角色信息到Excel")
|
||||
@SaCheckPermission("admin:role:export")
|
||||
@Log(title = "管理端角色信息", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(@Parameter(description = "角色查询条件") AppRoleBo bo,
|
||||
@Parameter(description = "响应对象") HttpServletResponse response) {
|
||||
List<AppRoleVo> list = appRoleService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "管理端角色信息", AppRoleVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取管理端角色信息详细信息
|
||||
*/
|
||||
@Operation(summary = "获取角色详情", description = "根据角色ID获取详细信息")
|
||||
@SaCheckPermission("admin:role:query")
|
||||
@GetMapping("/{roleId}")
|
||||
public R<AppRoleVo> getInfo(@Parameter(description = "角色ID", required = true)
|
||||
@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long roleId) {
|
||||
return R.ok(appRoleService.queryById(roleId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增管理端角色信息
|
||||
*/
|
||||
@Operation(summary = "新增角色", description = "新增管理端角色信息")
|
||||
@SaCheckPermission("admin:role:add")
|
||||
@Log(title = "管理端角色信息", businessType = BusinessType.INSERT)
|
||||
@PostMapping()
|
||||
public R<Void> add(@Parameter(description = "角色信息", required = true)
|
||||
@Validated(AddGroup.class) @RequestBody AppRoleBo bo) {
|
||||
return toAjax(appRoleService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改管理端角色信息
|
||||
*/
|
||||
@Operation(summary = "修改角色", description = "修改管理端角色信息")
|
||||
@SaCheckPermission("admin:role:edit")
|
||||
@Log(title = "管理端角色信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Parameter(description = "角色信息", required = true)
|
||||
@Validated(EditGroup.class) @RequestBody AppRoleBo bo) {
|
||||
return toAjax(appRoleService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除管理端角色信息
|
||||
*/
|
||||
@Operation(summary = "删除角色", description = "批量删除管理端角色信息")
|
||||
@SaCheckPermission("admin:role:remove")
|
||||
@Log(title = "管理端角色信息", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{roleIds}")
|
||||
public R<Void> remove(@Parameter(description = "角色ID数组", required = true)
|
||||
@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] roleIds) {
|
||||
return toAjax(appRoleService.deleteWithValidByIds(List.of(roleIds), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色选择框列表
|
||||
*/
|
||||
@Operation(summary = "获取角色选项", description = "获取角色选择框列表")
|
||||
@SaCheckPermission("admin:role:query")
|
||||
@GetMapping("/optionselect")
|
||||
public R<List<AppRoleVo>> optionselect() {
|
||||
List<AppRoleVo> roles = appRoleService.queryList(new AppRoleBo());
|
||||
return R.ok(roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询已分配用户角色列表
|
||||
*/
|
||||
@Operation(summary = "查询已分配用户", description = "查询已分配用户角色列表")
|
||||
@SaCheckPermission("admin:role:list")
|
||||
@GetMapping("/authUser/allocatedList")
|
||||
public TableDataInfo<AppRoleVo> allocatedList(@Parameter(description = "角色查询条件") AppRoleBo bo,
|
||||
@Parameter(description = "分页参数") PageQuery pageQuery) {
|
||||
return appRoleService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询未分配用户角色列表
|
||||
*/
|
||||
@Operation(summary = "查询未分配用户", description = "查询未分配用户角色列表")
|
||||
@SaCheckPermission("admin:role:list")
|
||||
@GetMapping("/authUser/unallocatedList")
|
||||
public TableDataInfo<AppRoleVo> unallocatedList(@Parameter(description = "角色查询条件") AppRoleBo bo,
|
||||
@Parameter(description = "分页参数") PageQuery pageQuery) {
|
||||
return appRoleService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消授权用户
|
||||
*/
|
||||
@Operation(summary = "取消授权用户", description = "批量取消用户角色授权")
|
||||
@SaCheckPermission("admin:role:edit")
|
||||
@Log(title = "管理端角色信息", businessType = BusinessType.GRANT)
|
||||
@PutMapping("/authUser/cancelAll")
|
||||
public R<Void> cancelAuthUserAll(@Parameter(description = "角色ID", required = true) Long roleId,
|
||||
@Parameter(description = "用户ID数组", required = true) Long[] userIds) {
|
||||
return toAjax(appRoleService.deleteAuthUsers(roleId, userIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量选择用户授权
|
||||
*/
|
||||
@Operation(summary = "批量授权用户", description = "批量选择用户进行角色授权")
|
||||
@SaCheckPermission("admin:role:edit")
|
||||
@Log(title = "管理端角色信息", businessType = BusinessType.GRANT)
|
||||
@PutMapping("/authUser/selectAll")
|
||||
public R<Void> selectAuthUserAll(@Parameter(description = "角色ID", required = true) Long roleId,
|
||||
@Parameter(description = "用户ID数组", required = true) Long[] userIds) {
|
||||
return toAjax(appRoleService.insertAuthUsers(roleId, userIds));
|
||||
}
|
||||
|
||||
}
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
package org.dromara.member.controller.admin;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.domain.model.LoginUser;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.member.domain.bo.AppUserBo;
|
||||
import org.dromara.member.domain.vo.AppUserVo;
|
||||
import org.dromara.member.service.AppUserService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 管理端用户信息
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Tag(name = "管理端用户管理", description = "管理端用户信息管理接口")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/admin/user")
|
||||
public class AdminUserController extends BaseController {
|
||||
|
||||
private final AppUserService appUserService;
|
||||
|
||||
/**
|
||||
* 查询管理端用户信息列表
|
||||
*/
|
||||
@Operation(summary = "查询用户列表", description = "分页查询管理端用户信息列表")
|
||||
@SaCheckPermission("admin:user:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<AppUserVo> list(@Parameter(description = "用户查询条件") AppUserBo bo,
|
||||
@Parameter(description = "分页参数") PageQuery pageQuery) {
|
||||
return appUserService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出管理端用户信息列表
|
||||
*/
|
||||
@Operation(summary = "导出用户列表", description = "导出管理端用户信息到Excel")
|
||||
@SaCheckPermission("admin:user:export")
|
||||
@Log(title = "管理端用户信息", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(@Parameter(description = "用户查询条件") AppUserBo bo,
|
||||
@Parameter(description = "响应对象") HttpServletResponse response) {
|
||||
List<AppUserVo> list = appUserService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "管理端用户信息", AppUserVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取管理端用户信息详细信息
|
||||
*/
|
||||
@Operation(summary = "获取用户详情", description = "根据用户ID获取详细信息")
|
||||
@SaCheckPermission("admin:user:query")
|
||||
@GetMapping("/{userId}")
|
||||
public R<AppUserVo> getInfo(@Parameter(description = "用户ID", required = true)
|
||||
@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long userId) {
|
||||
return R.ok(appUserService.queryById(userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增管理端用户信息
|
||||
*/
|
||||
@Operation(summary = "新增用户", description = "新增管理端用户信息")
|
||||
@SaCheckPermission("admin:user:add")
|
||||
@Log(title = "管理端用户信息", businessType = BusinessType.INSERT)
|
||||
@PostMapping()
|
||||
public R<Void> add(@Parameter(description = "用户信息", required = true)
|
||||
@Validated(AddGroup.class) @RequestBody AppUserBo bo) {
|
||||
return toAjax(appUserService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改管理端用户信息
|
||||
*/
|
||||
@Operation(summary = "修改用户", description = "修改管理端用户信息")
|
||||
@SaCheckPermission("admin:user:edit")
|
||||
@Log(title = "管理端用户信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Parameter(description = "用户信息", required = true)
|
||||
@Validated(EditGroup.class) @RequestBody AppUserBo bo) {
|
||||
return toAjax(appUserService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除管理端用户信息
|
||||
*/
|
||||
@Operation(summary = "删除用户", description = "批量删除管理端用户信息")
|
||||
@SaCheckPermission("admin:user:remove")
|
||||
@Log(title = "管理端用户信息", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{userIds}")
|
||||
public R<Void> remove(@Parameter(description = "用户ID数组", required = true)
|
||||
@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] userIds) {
|
||||
return toAjax(appUserService.deleteWithValidByIds(List.of(userIds), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取个人信息
|
||||
*/
|
||||
@Operation(summary = "获取个人信息", description = "获取当前登录用户的个人信息")
|
||||
@GetMapping("/profile")
|
||||
public R<AppUserVo> profile() {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
AppUserVo user = appUserService.queryById(loginUser.getUserId());
|
||||
return R.ok(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改个人信息
|
||||
*/
|
||||
@Operation(summary = "修改个人信息", description = "修改当前登录用户的个人信息")
|
||||
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/profile")
|
||||
public R<Void> updateProfile(@Parameter(description = "用户信息", required = true)
|
||||
@RequestBody AppUserBo bo) {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
bo.setUserId(loginUser.getUserId());
|
||||
return toAjax(appUserService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
*/
|
||||
@Operation(summary = "重置密码", description = "重置用户密码")
|
||||
@SaCheckPermission("admin:user:resetPwd")
|
||||
@Log(title = "管理端用户信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/resetPwd")
|
||||
public R<Void> resetPwd(@Parameter(description = "用户信息", required = true)
|
||||
@RequestBody AppUserBo bo) {
|
||||
AppUserBo userBo = new AppUserBo();
|
||||
userBo.setUserId(bo.getUserId());
|
||||
userBo.setPassword(bo.getPassword());
|
||||
return toAjax(appUserService.updateByBo(userBo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态修改
|
||||
*/
|
||||
@Operation(summary = "修改用户状态", description = "修改用户启用/禁用状态")
|
||||
@SaCheckPermission("admin:user:edit")
|
||||
@Log(title = "管理端用户信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/changeStatus")
|
||||
public R<Void> changeStatus(@Parameter(description = "用户信息", required = true)
|
||||
@RequestBody AppUserBo bo) {
|
||||
return toAjax(appUserService.updateUserStatus(bo.getUserId(), bo.getStatus()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户编号获取授权角色
|
||||
*/
|
||||
@Operation(summary = "获取用户角色", description = "根据用户ID获取授权角色信息")
|
||||
@SaCheckPermission("admin:user:query")
|
||||
@GetMapping("/authRole/{userId}")
|
||||
public R<AppUserVo> authRole(@Parameter(description = "用户ID", required = true)
|
||||
@PathVariable Long userId) {
|
||||
AppUserVo user = appUserService.queryById(userId);
|
||||
return R.ok(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门树列表
|
||||
*/
|
||||
@Operation(summary = "获取部门树", description = "获取部门树形结构列表")
|
||||
@SaCheckPermission("admin:user:list")
|
||||
@GetMapping("/deptTree")
|
||||
public R<List<Object>> deptTree(@Parameter(description = "用户查询条件") AppUserBo bo) {
|
||||
// 这里可以根据实际需求实现部门树逻辑
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
}
|
||||
+247
@@ -0,0 +1,247 @@
|
||||
package org.dromara.member.controller.app;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.member.domain.bo.AppDeviceBo;
|
||||
import org.dromara.member.domain.vo.AppDeviceVo;
|
||||
import org.dromara.member.service.AppDeviceService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端设备管理
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Tag(name = "App端设备管理", description = "App端设备信息管理接口")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/app/device")
|
||||
public class AppDeviceController extends BaseController {
|
||||
|
||||
private final AppDeviceService appDeviceService;
|
||||
|
||||
/**
|
||||
* 查询App端设备信息列表
|
||||
*/
|
||||
@Operation(summary = "查询设备列表", description = "分页查询当前用户的设备信息列表")
|
||||
@SaCheckLogin
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<AppDeviceVo> list(@Parameter(description = "设备查询条件") @Valid AppDeviceBo bo,
|
||||
@Parameter(description = "分页参数") @Valid PageQuery pageQuery) {
|
||||
// 只能查询当前用户的设备
|
||||
bo.setUserId(StpUtil.getLoginIdAsLong());
|
||||
return appDeviceService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取App端设备信息详细信息
|
||||
*/
|
||||
@Operation(summary = "获取设备详情", description = "根据设备ID获取详细信息")
|
||||
@SaCheckLogin
|
||||
@GetMapping("/{deviceId}")
|
||||
public R<AppDeviceVo> getInfo(@Parameter(description = "设备ID", required = true)
|
||||
@PathVariable @NotNull(message = "设备ID不能为空") @Positive(message = "设备ID必须为正数") Long deviceId) {
|
||||
AppDeviceVo deviceVo = appDeviceService.queryById(deviceId);
|
||||
// 验证设备是否属于当前用户
|
||||
if (deviceVo != null && !deviceVo.getUserId().equals(StpUtil.getLoginIdAsLong())) {
|
||||
return R.fail("无权限访问该设备信息");
|
||||
}
|
||||
return R.ok(deviceVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定设备
|
||||
*/
|
||||
@Operation(summary = "绑定设备", description = "绑定新设备到当前用户")
|
||||
@SaCheckLogin
|
||||
@Log(title = "App端设备信息", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/bind")
|
||||
public R<Void> bind(@Parameter(description = "设备信息", required = true)
|
||||
@Validated(AddGroup.class) @RequestBody @NotNull(message = "设备信息不能为空") AppDeviceBo bo) {
|
||||
// 设置当前用户ID
|
||||
bo.setUserId(StpUtil.getLoginIdAsLong());
|
||||
|
||||
// 验证必要字段
|
||||
if (StringUtils.isBlank(bo.getDeviceType())) {
|
||||
return R.fail("设备类型不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(bo.getDeviceName())) {
|
||||
return R.fail("设备名称不能为空");
|
||||
}
|
||||
|
||||
return toAjax(appDeviceService.bindDevice(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改设备信息
|
||||
*/
|
||||
@Operation(summary = "修改设备信息", description = "修改设备信息")
|
||||
@SaCheckLogin
|
||||
@Log(title = "App端设备信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public R<Void> edit(@Parameter(description = "设备信息", required = true)
|
||||
@Validated(EditGroup.class) @RequestBody @NotNull(message = "设备信息不能为空") AppDeviceBo bo) {
|
||||
// 验证设备是否属于当前用户
|
||||
AppDeviceVo deviceVo = appDeviceService.queryById(bo.getDeviceId());
|
||||
if (deviceVo == null) {
|
||||
return R.fail("设备不存在");
|
||||
}
|
||||
if (!deviceVo.getUserId().equals(StpUtil.getLoginIdAsLong())) {
|
||||
return R.fail("无权限修改该设备信息");
|
||||
}
|
||||
|
||||
// 设置当前用户ID
|
||||
bo.setUserId(StpUtil.getLoginIdAsLong());
|
||||
return toAjax(appDeviceService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解绑设备
|
||||
*/
|
||||
@Operation(summary = "解绑设备", description = "解绑指定设备")
|
||||
@SaCheckLogin
|
||||
@Log(title = "App端设备信息", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{deviceId}")
|
||||
public R<Void> unbind(@Parameter(description = "设备ID", required = true)
|
||||
@PathVariable @NotNull(message = "设备ID不能为空") @Positive(message = "设备ID必须为正数") Long deviceId) {
|
||||
return toAjax(appDeviceService.unbindDevice(deviceId, StpUtil.getLoginIdAsLong()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取我的设备列表
|
||||
*/
|
||||
@Operation(summary = "获取我的设备", description = "获取当前用户的所有设备列表")
|
||||
@SaCheckLogin
|
||||
@GetMapping("/my")
|
||||
public R<List<AppDeviceVo>> getMyDevices() {
|
||||
List<AppDeviceVo> devices = appDeviceService.queryByUserId(StpUtil.getLoginIdAsLong());
|
||||
return R.ok(devices);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活跃设备列表
|
||||
*/
|
||||
@Operation(summary = "获取活跃设备", description = "获取当前用户的活跃设备列表")
|
||||
@SaCheckLogin
|
||||
@GetMapping("/active")
|
||||
public R<List<AppDeviceVo>> getActiveDevices() {
|
||||
List<AppDeviceVo> devices = appDeviceService.getActiveDevices(StpUtil.getLoginIdAsLong());
|
||||
return R.ok(devices);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备状态
|
||||
*/
|
||||
@Operation(summary = "更新设备状态", description = "更新设备的激活状态")
|
||||
@SaCheckLogin
|
||||
@Log(title = "App端设备信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/{deviceId}/status")
|
||||
public R<Void> updateStatus(@Parameter(description = "设备ID", required = true)
|
||||
@PathVariable @NotNull(message = "设备ID不能为空") @Positive(message = "设备ID必须为正数") Long deviceId,
|
||||
@Parameter(description = "设备状态(0-禁用,1-启用)", required = true)
|
||||
@RequestParam @NotBlank(message = "设备状态不能为空") @Pattern(regexp = "^[01]$", message = "设备状态只能为0或1") String isActive) {
|
||||
// 验证设备是否属于当前用户
|
||||
AppDeviceVo deviceVo = appDeviceService.queryById(deviceId);
|
||||
if (deviceVo == null) {
|
||||
return R.fail("设备不存在");
|
||||
}
|
||||
if (!deviceVo.getUserId().equals(StpUtil.getLoginIdAsLong())) {
|
||||
return R.fail("无权限修改该设备状态");
|
||||
}
|
||||
|
||||
// 验证状态值
|
||||
if (!"0".equals(isActive) && !"1".equals(isActive)) {
|
||||
return R.fail("状态值无效");
|
||||
}
|
||||
|
||||
return toAjax(appDeviceService.updateActiveStatus(deviceId, isActive));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备推送令牌
|
||||
*/
|
||||
@Operation(summary = "更新推送令牌", description = "更新设备的推送令牌")
|
||||
@SaCheckLogin
|
||||
@Log(title = "App端设备信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/{deviceId}/push-token")
|
||||
public R<Void> updatePushToken(@Parameter(description = "设备ID", required = true)
|
||||
@PathVariable @NotNull(message = "设备ID不能为空") @Positive(message = "设备ID必须为正数") Long deviceId,
|
||||
@Parameter(description = "推送令牌", required = true)
|
||||
@RequestParam @NotBlank(message = "推送令牌不能为空") @Size(max = 255, message = "推送令牌长度不能超过255个字符") String pushToken) {
|
||||
// 验证设备是否属于当前用户
|
||||
AppDeviceVo deviceVo = appDeviceService.queryById(deviceId);
|
||||
if (deviceVo == null) {
|
||||
return R.fail("设备不存在");
|
||||
}
|
||||
if (!deviceVo.getUserId().equals(StpUtil.getLoginIdAsLong())) {
|
||||
return R.fail("无权限修改该设备推送令牌");
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(pushToken)) {
|
||||
return R.fail("推送令牌不能为空");
|
||||
}
|
||||
|
||||
return toAjax(appDeviceService.updatePushToken(deviceId, pushToken));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备心跳
|
||||
*/
|
||||
@Operation(summary = "设备心跳", description = "更新设备心跳时间")
|
||||
@SaCheckLogin
|
||||
@PostMapping("/{deviceId}/heartbeat")
|
||||
public R<Void> heartbeat(@Parameter(description = "设备ID", required = true)
|
||||
@PathVariable @NotNull(message = "设备ID不能为空") @Positive(message = "设备ID必须为正数") Long deviceId) {
|
||||
// 验证设备是否属于当前用户
|
||||
AppDeviceVo deviceVo = appDeviceService.queryById(deviceId);
|
||||
if (deviceVo == null) {
|
||||
return R.fail("设备不存在");
|
||||
}
|
||||
if (!deviceVo.getUserId().equals(StpUtil.getLoginIdAsLong())) {
|
||||
return R.fail("无权限操作该设备");
|
||||
}
|
||||
|
||||
return toAjax(appDeviceService.heartbeat(deviceId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据推送令牌获取设备信息
|
||||
*/
|
||||
@Operation(summary = "根据推送令牌获取设备", description = "根据推送令牌获取设备信息")
|
||||
@SaCheckLogin
|
||||
@GetMapping("/by-push-token")
|
||||
public R<AppDeviceVo> getDeviceByPushToken(@Parameter(description = "推送令牌", required = true)
|
||||
@RequestParam @NotBlank(message = "推送令牌不能为空") @Size(max = 255, message = "推送令牌长度不能超过255个字符") String pushToken) {
|
||||
if (StringUtils.isBlank(pushToken)) {
|
||||
return R.fail("推送令牌不能为空");
|
||||
}
|
||||
|
||||
AppDeviceVo deviceVo = appDeviceService.queryByPushToken(pushToken);
|
||||
// 验证设备是否属于当前用户
|
||||
if (deviceVo != null && !deviceVo.getUserId().equals(StpUtil.getLoginIdAsLong())) {
|
||||
return R.fail("无权限访问该设备信息");
|
||||
}
|
||||
|
||||
return R.ok(deviceVo);
|
||||
}
|
||||
|
||||
}
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
package org.dromara.member.controller.app;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.domain.model.LoginUser;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.member.domain.bo.AppMessageBo;
|
||||
import org.dromara.member.domain.vo.AppMessageVo;
|
||||
import org.dromara.member.service.AppMessageService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端消息管理
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Tag(name = "App端消息管理", description = "App端消息管理相关接口")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/app/message")
|
||||
public class AppMessageController extends BaseController {
|
||||
|
||||
private final AppMessageService appMessageService;
|
||||
|
||||
/**
|
||||
* 查询App端消息列表
|
||||
*/
|
||||
@Operation(summary = "查询消息列表", description = "查询App端消息列表")
|
||||
@SaCheckPermission("app:message:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<AppMessageVo> list(@Parameter(description = "查询条件") @Valid AppMessageBo bo,
|
||||
@Parameter(description = "分页参数") @Valid PageQuery pageQuery) {
|
||||
return appMessageService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的消息列表
|
||||
*/
|
||||
@Operation(summary = "获取我的消息", description = "获取当前用户的消息列表")
|
||||
@GetMapping("/myMessages")
|
||||
public TableDataInfo<AppMessageVo> getMyMessages(@Parameter(description = "分页参数") @Valid PageQuery pageQuery) {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
AppMessageBo bo = new AppMessageBo();
|
||||
bo.setReceiverId(loginUser.getUserId());
|
||||
return appMessageService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户未读消息数量
|
||||
*/
|
||||
@Operation(summary = "获取未读消息数量", description = "获取当前用户未读消息数量")
|
||||
@GetMapping("/unreadCount")
|
||||
public R<Long> getUnreadCount() {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
Long count = appMessageService.getUnreadCount(loginUser.getUserId());
|
||||
return R.ok(count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出App端消息列表
|
||||
*/
|
||||
@Operation(summary = "导出消息列表", description = "导出App端消息列表")
|
||||
@SaCheckPermission("app:message:export")
|
||||
@Log(title = "App端消息", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(@Parameter(description = "查询条件") @Valid AppMessageBo bo, HttpServletResponse response) {
|
||||
List<AppMessageVo> list = appMessageService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "App端消息", AppMessageVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取App端消息详细信息
|
||||
*/
|
||||
@Operation(summary = "获取消息详情", description = "获取App端消息详细信息")
|
||||
@SaCheckPermission("app:message:query")
|
||||
@GetMapping("/{messageId}")
|
||||
public R<AppMessageVo> getInfo(@Parameter(description = "消息ID", required = true)
|
||||
@PathVariable @NotNull(message = "消息ID不能为空") @Positive(message = "消息ID必须为正数") Long messageId) {
|
||||
return R.ok(appMessageService.queryById(messageId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增App端消息
|
||||
*/
|
||||
@Operation(summary = "新增消息", description = "新增App端消息")
|
||||
@SaCheckPermission("app:message:add")
|
||||
@Log(title = "App端消息", businessType = BusinessType.INSERT)
|
||||
@PostMapping()
|
||||
public R<Void> add(@Parameter(description = "消息信息", required = true)
|
||||
@Validated(AddGroup.class) @RequestBody @NotNull(message = "消息信息不能为空") AppMessageBo bo) {
|
||||
return toAjax(appMessageService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改App端消息
|
||||
*/
|
||||
@Operation(summary = "修改消息", description = "修改App端消息")
|
||||
@SaCheckPermission("app:message:edit")
|
||||
@Log(title = "App端消息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Parameter(description = "消息信息", required = true)
|
||||
@Validated(EditGroup.class) @RequestBody @NotNull(message = "消息信息不能为空") AppMessageBo bo) {
|
||||
return toAjax(appMessageService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除App端消息
|
||||
*/
|
||||
@Operation(summary = "删除消息", description = "删除App端消息")
|
||||
@SaCheckPermission("app:message:remove")
|
||||
@Log(title = "App端消息", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{messageIds}")
|
||||
public R<Void> remove(@Parameter(description = "消息ID数组", required = true)
|
||||
@PathVariable @NotEmpty(message = "消息ID不能为空") Long[] messageIds) {
|
||||
return toAjax(appMessageService.deleteWithValidByIds(List.of(messageIds), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记消息为已读
|
||||
*/
|
||||
@Operation(summary = "标记消息已读", description = "标记指定消息为已读")
|
||||
@Log(title = "标记消息已读", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/markRead/{messageId}")
|
||||
public R<Void> markRead(@Parameter(description = "消息ID", required = true)
|
||||
@PathVariable @NotNull(message = "消息ID不能为空") @Positive(message = "消息ID必须为正数") Long messageId) {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
return toAjax(appMessageService.markAsRead(messageId, loginUser.getUserId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量标记消息为已读
|
||||
*/
|
||||
@Operation(summary = "批量标记已读", description = "批量标记消息为已读")
|
||||
@Log(title = "批量标记消息已读", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/markReadBatch")
|
||||
public R<Void> markReadBatch(@Parameter(description = "消息ID数组", required = true)
|
||||
@RequestBody @NotEmpty(message = "消息ID列表不能为空") Long[] messageIds) {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
return toAjax(appMessageService.markAsReadBatch(List.of(messageIds), loginUser.getUserId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记所有消息为已读
|
||||
*/
|
||||
@Operation(summary = "标记全部已读", description = "标记所有消息为已读")
|
||||
@Log(title = "标记所有消息已读", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/markAllRead")
|
||||
public R<Void> markAllRead() {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
return toAjax(appMessageService.markAllAsRead(loginUser.getUserId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送系统消息
|
||||
*/
|
||||
@Operation(summary = "发送系统消息", description = "发送系统消息")
|
||||
@SaCheckPermission("app:message:send")
|
||||
@Log(title = "发送系统消息", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/sendSystem")
|
||||
public R<Void> sendSystemMessage(@Parameter(description = "消息信息", required = true)
|
||||
@RequestBody @NotNull(message = "消息信息不能为空") @Valid AppMessageBo bo) {
|
||||
return toAjax(appMessageService.sendSystemMessage(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送个人消息
|
||||
*/
|
||||
@Operation(summary = "发送个人消息", description = "发送个人消息")
|
||||
@Log(title = "发送个人消息", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/sendPersonal")
|
||||
public R<Void> sendPersonalMessage(@Parameter(description = "消息信息", required = true)
|
||||
@RequestBody @NotNull(message = "消息信息不能为空") @Valid AppMessageBo bo) {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
bo.setSenderId(loginUser.getUserId());
|
||||
return toAjax(appMessageService.sendPersonalMessage(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送消息
|
||||
*/
|
||||
@Operation(summary = "推送消息", description = "推送消息")
|
||||
@SaCheckPermission("app:message:push")
|
||||
@Log(title = "推送消息", businessType = BusinessType.OTHER)
|
||||
@PostMapping("/push")
|
||||
public R<Void> pushMessage(@Parameter(description = "消息信息", required = true)
|
||||
@Validated @RequestBody @NotNull(message = "消息信息不能为空") AppMessageBo bo) {
|
||||
return toAjax(appMessageService.pushMessage(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 群发消息
|
||||
*/
|
||||
@Operation(summary = "群发消息", description = "群发消息")
|
||||
@SaCheckPermission("app:message:broadcast")
|
||||
@Log(title = "群发消息", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/broadcast")
|
||||
public R<Void> broadcastMessage(@Parameter(description = "消息信息", required = true)
|
||||
@Validated @RequestBody @NotNull(message = "消息信息不能为空") AppMessageBo bo) {
|
||||
return toAjax(appMessageService.broadcastMessage(bo));
|
||||
}
|
||||
}
|
||||
+257
@@ -0,0 +1,257 @@
|
||||
package org.dromara.member.controller.app;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.member.domain.bo.AppOperLogBo;
|
||||
import org.dromara.member.domain.vo.AppOperLogVo;
|
||||
import org.dromara.member.service.AppOperLogService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端操作日志
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Tag(name = "App端操作日志管理", description = "App端操作日志管理相关接口")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/app/operLog")
|
||||
public class AppOperLogController extends BaseController {
|
||||
|
||||
private final AppOperLogService appOperLogService;
|
||||
|
||||
/**
|
||||
* 查询App端操作日志列表
|
||||
*/
|
||||
@Operation(summary = "查询操作日志列表", description = "查询App端操作日志列表")
|
||||
@SaCheckPermission("app:operLog:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<AppOperLogVo> list(@Parameter(description = "查询条件") @Valid AppOperLogBo bo,
|
||||
@Parameter(description = "分页参数") @Valid PageQuery pageQuery) {
|
||||
return appOperLogService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的操作日志列表
|
||||
*/
|
||||
@Operation(summary = "获取我的操作日志", description = "获取当前用户的操作日志列表")
|
||||
@SaCheckLogin
|
||||
@GetMapping("/my")
|
||||
public TableDataInfo<AppOperLogVo> getMyOperLogs(@Parameter(description = "查询条件") @Valid AppOperLogBo bo,
|
||||
@Parameter(description = "分页参数") @Valid PageQuery pageQuery) {
|
||||
// 只查询当前用户的操作日志
|
||||
bo.setOperName(StpUtil.getLoginIdAsString());
|
||||
return appOperLogService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出App端操作日志列表
|
||||
*/
|
||||
@Operation(summary = "导出操作日志", description = "导出App端操作日志列表")
|
||||
@SaCheckPermission("app:operLog:export")
|
||||
@Log(title = "App端操作日志", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(@Parameter(description = "查询条件") @Valid AppOperLogBo bo, HttpServletResponse response) {
|
||||
List<AppOperLogVo> list = appOperLogService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "App端操作日志", AppOperLogVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取App端操作日志详细信息
|
||||
*/
|
||||
@Operation(summary = "获取操作日志详情", description = "获取App端操作日志详细信息")
|
||||
@SaCheckPermission("app:operLog:query")
|
||||
@GetMapping("/{operId}")
|
||||
public R<AppOperLogVo> getInfo(@Parameter(description = "操作日志ID", required = true)
|
||||
@PathVariable @NotNull(message = "操作日志ID不能为空") @Positive(message = "操作日志ID必须为正数") Long operId) {
|
||||
return R.ok(appOperLogService.queryById(operId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增App端操作日志
|
||||
*/
|
||||
@Operation(summary = "新增操作日志", description = "新增App端操作日志")
|
||||
@SaCheckPermission("app:operLog:add")
|
||||
@Log(title = "App端操作日志", businessType = BusinessType.INSERT)
|
||||
@PostMapping()
|
||||
public R<Void> add(@Parameter(description = "操作日志信息", required = true)
|
||||
@Validated(AddGroup.class) @RequestBody @NotNull(message = "操作日志信息不能为空") AppOperLogBo bo) {
|
||||
return toAjax(appOperLogService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改App端操作日志
|
||||
*/
|
||||
@Operation(summary = "修改操作日志", description = "修改App端操作日志")
|
||||
@SaCheckPermission("app:operLog:edit")
|
||||
@Log(title = "App端操作日志", businessType = BusinessType.UPDATE)
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Parameter(description = "操作日志信息", required = true)
|
||||
@Validated(EditGroup.class) @RequestBody @NotNull(message = "操作日志信息不能为空") AppOperLogBo bo) {
|
||||
return toAjax(appOperLogService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除App端操作日志
|
||||
*/
|
||||
@Operation(summary = "删除操作日志", description = "删除App端操作日志")
|
||||
@SaCheckPermission("app:operLog:remove")
|
||||
@Log(title = "App端操作日志", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{operIds}")
|
||||
public R<Void> remove(@Parameter(description = "操作日志ID数组", required = true)
|
||||
@PathVariable @NotEmpty(message = "操作日志ID不能为空") Long[] operIds) {
|
||||
return toAjax(appOperLogService.deleteWithValidByIds(List.of(operIds), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空App端操作日志
|
||||
*/
|
||||
@Operation(summary = "清空操作日志", description = "清空App端操作日志")
|
||||
@SaCheckPermission("app:operLog:remove")
|
||||
@Log(title = "App端操作日志", businessType = BusinessType.CLEAN)
|
||||
@DeleteMapping("/clean")
|
||||
public R<Void> clean() {
|
||||
appOperLogService.cleanOperLog();
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据时间范围删除操作日志
|
||||
*/
|
||||
@Operation(summary = "按时间删除操作日志", description = "根据时间范围删除App端操作日志")
|
||||
@SaCheckPermission("app:operLog:remove")
|
||||
@Log(title = "App端操作日志", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/cleanByTime")
|
||||
public R<Void> cleanByTime(@Parameter(description = "开始时间")
|
||||
@RequestParam(required = false) LocalDateTime beginTime,
|
||||
@Parameter(description = "结束时间")
|
||||
@RequestParam(required = false) LocalDateTime endTime) {
|
||||
appOperLogService.deleteOperLogByTime(beginTime, endTime);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作统计信息
|
||||
*/
|
||||
@Operation(summary = "获取操作统计信息", description = "获取操作日志统计信息")
|
||||
@SaCheckLogin
|
||||
@GetMapping("/statistics")
|
||||
public R<Long> getStatistics(@Parameter(description = "操作人员名称")
|
||||
@RequestParam(required = false) @Size(max = 50, message = "操作人员名称长度不能超过50个字符") String operName,
|
||||
@Parameter(description = "开始时间")
|
||||
@RequestParam(required = false) LocalDateTime beginTime,
|
||||
@Parameter(description = "结束时间")
|
||||
@RequestParam(required = false) LocalDateTime endTime) {
|
||||
// 如果没有指定操作人,则查询当前用户的统计
|
||||
if (operName == null) {
|
||||
operName = StpUtil.getLoginIdAsString();
|
||||
}
|
||||
Long count = appOperLogService.getOperLogCount(operName, beginTime, endTime);
|
||||
return R.ok(count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户行为分析数据
|
||||
*/
|
||||
@Operation(summary = "获取用户行为分析", description = "获取用户行为分析数据")
|
||||
@SaCheckLogin
|
||||
@GetMapping("/behavior")
|
||||
public R<List<AppOperLogVo>> getBehaviorAnalysis(@Parameter(description = "操作人员名称")
|
||||
@RequestParam(required = false) @Size(max = 50, message = "操作人员名称长度不能超过50个字符") String operName,
|
||||
@Parameter(description = "分析天数")
|
||||
@RequestParam(defaultValue = "7") @Min(value = 1, message = "天数必须大于0") @Max(value = 365, message = "天数不能超过365天") Integer days) {
|
||||
// 如果没有指定操作人,则查询当前用户的行为分析
|
||||
if (operName == null) {
|
||||
operName = StpUtil.getLoginIdAsString();
|
||||
}
|
||||
List<AppOperLogVo> result = appOperLogService.getUserBehaviorAnalysis(operName, days);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取热门操作统计
|
||||
*/
|
||||
@Operation(summary = "获取热门操作统计", description = "获取热门操作统计")
|
||||
@SaCheckPermission("app:operLog:list")
|
||||
@GetMapping("/popular")
|
||||
public R<List<AppOperLogVo>> getPopularOperations(@Parameter(description = "统计天数")
|
||||
@RequestParam(defaultValue = "7") @Min(value = 1, message = "天数必须大于0") @Max(value = 365, message = "天数不能超过365天") Integer days,
|
||||
@Parameter(description = "返回数量限制")
|
||||
@RequestParam(defaultValue = "10") @Min(value = 1, message = "限制数量必须大于0") @Max(value = 100, message = "限制数量不能超过100") Integer limit) {
|
||||
List<AppOperLogVo> result = appOperLogService.getPopularOperations(days, limit);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误操作统计
|
||||
*/
|
||||
@Operation(summary = "获取错误操作统计", description = "获取错误操作统计")
|
||||
@SaCheckPermission("app:operLog:list")
|
||||
@GetMapping("/errors")
|
||||
public R<List<AppOperLogVo>> getErrorOperations(@Parameter(description = "统计天数")
|
||||
@RequestParam(defaultValue = "7") @Min(value = 1, message = "天数必须大于0") @Max(value = 365, message = "天数不能超过365天") Integer days) {
|
||||
List<AppOperLogVo> result = appOperLogService.getErrorOperations(days);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录用户操作日志(供App端调用)
|
||||
*/
|
||||
@Operation(summary = "记录操作日志", description = "记录用户操作日志(供App端调用)")
|
||||
@SaCheckLogin
|
||||
@Log(title = "App端操作日志", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/record")
|
||||
public R<Void> recordOperation(@Parameter(description = "操作日志信息", required = true)
|
||||
@RequestBody @NotNull(message = "操作日志信息不能为空") @Valid AppOperLogBo bo) {
|
||||
// 设置操作人为当前登录用户
|
||||
bo.setOperName(StpUtil.getLoginIdAsString());
|
||||
bo.setOperTime(LocalDateTime.now());
|
||||
|
||||
// 异步记录操作日志
|
||||
appOperLogService.asyncRecordOperLog(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量记录操作日志
|
||||
*/
|
||||
@Operation(summary = "批量记录操作日志", description = "批量记录操作日志")
|
||||
@SaCheckLogin
|
||||
@Log(title = "App端操作日志", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/batchRecord")
|
||||
public R<Void> batchRecordOperations(@Parameter(description = "操作日志列表", required = true)
|
||||
@RequestBody @NotEmpty(message = "操作日志列表不能为空") @Valid List<AppOperLogBo> operLogs) {
|
||||
// 设置操作人为当前登录用户
|
||||
String currentUser = StpUtil.getLoginIdAsString();
|
||||
operLogs.forEach(bo -> {
|
||||
bo.setOperName(currentUser);
|
||||
bo.setOperTime(LocalDateTime.now());
|
||||
});
|
||||
|
||||
appOperLogService.batchInsertOperLog(operLogs);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
package org.dromara.member.controller.app;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.member.domain.bo.AppRoleBo;
|
||||
import org.dromara.member.domain.vo.AppRoleVo;
|
||||
import org.dromara.member.service.AppRoleService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端角色信息
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Tag(name = "App端角色管理", description = "App端角色信息的增删改查操作")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/app/role")
|
||||
public class AppRoleController extends BaseController {
|
||||
|
||||
private final AppRoleService appRoleService;
|
||||
|
||||
/**
|
||||
* 查询App端角色信息列表
|
||||
*/
|
||||
@Operation(summary = "查询App端角色信息列表", description = "分页查询App端角色信息列表")
|
||||
@SaCheckPermission("app:role:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<AppRoleVo> list(
|
||||
@Parameter(description = "角色查询条件") @Valid AppRoleBo bo,
|
||||
@Parameter(description = "分页查询参数") @Valid PageQuery pageQuery) {
|
||||
return appRoleService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出App端角色信息列表
|
||||
*/
|
||||
@Operation(summary = "导出App端角色信息列表", description = "导出App端角色信息到Excel文件")
|
||||
@SaCheckPermission("app:role:export")
|
||||
@Log(title = "App端角色信息", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(
|
||||
@Parameter(description = "角色查询条件") @Valid AppRoleBo bo,
|
||||
HttpServletResponse response) {
|
||||
List<AppRoleVo> list = appRoleService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "App端角色信息", AppRoleVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取App端角色信息详细信息
|
||||
*/
|
||||
@Operation(summary = "获取App端角色信息详细信息", description = "根据角色ID获取App端角色详细信息")
|
||||
@SaCheckPermission("app:role:query")
|
||||
@GetMapping("/{roleId}")
|
||||
public R<AppRoleVo> getInfo(
|
||||
@Parameter(description = "角色ID", required = true) @PathVariable @NotNull(message = "角色ID不能为空") @Positive(message = "角色ID必须为正数") Long roleId) {
|
||||
return R.ok(appRoleService.queryById(roleId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增App端角色信息
|
||||
*/
|
||||
@Operation(summary = "新增App端角色信息", description = "新增App端角色信息")
|
||||
@SaCheckPermission("app:role:add")
|
||||
@Log(title = "App端角色信息", businessType = BusinessType.INSERT)
|
||||
@PostMapping()
|
||||
public R<Void> add(
|
||||
@Parameter(description = "角色信息", required = true) @Validated(AddGroup.class) @RequestBody @NotNull(message = "角色信息不能为空") AppRoleBo bo) {
|
||||
return toAjax(appRoleService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改App端角色信息
|
||||
*/
|
||||
@Operation(summary = "修改App端角色信息", description = "修改App端角色信息")
|
||||
@SaCheckPermission("app:role:edit")
|
||||
@Log(title = "App端角色信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping()
|
||||
public R<Void> edit(
|
||||
@Parameter(description = "角色信息", required = true) @Validated(EditGroup.class) @RequestBody @NotNull(message = "角色信息不能为空") AppRoleBo bo) {
|
||||
return toAjax(appRoleService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除App端角色信息
|
||||
*/
|
||||
@Operation(summary = "删除App端角色信息", description = "批量删除App端角色信息")
|
||||
@SaCheckPermission("app:role:remove")
|
||||
@Log(title = "App端角色信息", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{roleIds}")
|
||||
public R<Void> remove(
|
||||
@Parameter(description = "角色ID数组", required = true) @PathVariable @NotEmpty(message = "角色ID不能为空") Long[] roleIds) {
|
||||
return toAjax(appRoleService.deleteWithValidByIds(List.of(roleIds), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色选择框列表
|
||||
*/
|
||||
@Operation(summary = "获取角色选择框列表", description = "获取所有角色的选择框列表")
|
||||
@SaCheckPermission("app:role:query")
|
||||
@GetMapping("/optionselect")
|
||||
public R<List<AppRoleVo>> optionselect() {
|
||||
return R.ok(appRoleService.selectRoleAll());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询已分配用户角色列表
|
||||
*/
|
||||
@Operation(summary = "查询已分配用户角色列表", description = "分页查询已分配用户的角色列表")
|
||||
@SaCheckPermission("app:role:list")
|
||||
@GetMapping("/authUser/allocatedList")
|
||||
public TableDataInfo<AppRoleVo> allocatedList(
|
||||
@Parameter(description = "角色查询条件") @Valid AppRoleBo bo,
|
||||
@Parameter(description = "分页查询参数") @Valid PageQuery pageQuery) {
|
||||
return appRoleService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询未分配用户角色列表
|
||||
*/
|
||||
@Operation(summary = "查询未分配用户角色列表", description = "分页查询未分配用户的角色列表")
|
||||
@SaCheckPermission("app:role:list")
|
||||
@GetMapping("/authUser/unallocatedList")
|
||||
public TableDataInfo<AppRoleVo> unallocatedList(
|
||||
@Parameter(description = "角色查询条件") @Valid AppRoleBo bo,
|
||||
@Parameter(description = "分页查询参数") @Valid PageQuery pageQuery) {
|
||||
return appRoleService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消授权用户
|
||||
*/
|
||||
@Operation(summary = "取消授权用户", description = "取消用户的角色授权")
|
||||
@SaCheckPermission("app:role:edit")
|
||||
@Log(title = "App端角色信息", businessType = BusinessType.GRANT)
|
||||
@PutMapping("/authUser/cancel")
|
||||
public R<Void> cancelAuthUser(
|
||||
@Parameter(description = "角色信息", required = true) @RequestBody @NotNull(message = "角色信息不能为空") @Valid AppRoleBo bo) {
|
||||
return toAjax(appRoleService.deleteAuthUser(bo.getUserId(), bo.getRoleId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量取消授权用户
|
||||
*/
|
||||
@Operation(summary = "批量取消授权用户", description = "批量取消用户的角色授权")
|
||||
@SaCheckPermission("app:role:edit")
|
||||
@Log(title = "App端角色信息", businessType = BusinessType.GRANT)
|
||||
@PutMapping("/authUser/cancelAll")
|
||||
public R<Void> cancelAuthUserAll(
|
||||
@Parameter(description = "角色ID", required = true) @NotNull(message = "角色ID不能为空") @Positive(message = "角色ID必须为正数") Long roleId,
|
||||
@Parameter(description = "用户ID数组", required = true) @NotEmpty(message = "用户ID不能为空") Long[] userIds) {
|
||||
return toAjax(appRoleService.deleteAuthUsers(roleId, userIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量选择用户授权
|
||||
*/
|
||||
@Operation(summary = "批量选择用户授权", description = "批量为用户分配角色授权")
|
||||
@SaCheckPermission("app:role:edit")
|
||||
@Log(title = "App端角色信息", businessType = BusinessType.GRANT)
|
||||
@PutMapping("/authUser/selectAll")
|
||||
public R<Void> selectAuthUserAll(
|
||||
@Parameter(description = "角色ID", required = true) @NotNull(message = "角色ID不能为空") @Positive(message = "角色ID必须为正数") Long roleId,
|
||||
@Parameter(description = "用户ID数组", required = true) @NotEmpty(message = "用户ID不能为空") Long[] userIds) {
|
||||
return toAjax(appRoleService.insertAuthUsers(roleId, userIds));
|
||||
}
|
||||
|
||||
}
|
||||
+220
@@ -0,0 +1,220 @@
|
||||
package org.dromara.member.controller.app;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.domain.model.LoginUser;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.member.domain.bo.AppUserBo;
|
||||
import org.dromara.member.domain.vo.AppUserVo;
|
||||
import org.dromara.member.service.AppUserService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端用户信息
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Tag(name = "App用户管理", description = "App端用户信息管理接口")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/app/user")
|
||||
public class AppUserController extends BaseController {
|
||||
|
||||
private final AppUserService appUserService;
|
||||
|
||||
/**
|
||||
* 查询App端用户信息列表
|
||||
*/
|
||||
@Operation(summary = "查询用户列表", description = "分页查询App端用户信息列表")
|
||||
@SaCheckPermission("app:user:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<AppUserVo> list(
|
||||
@Parameter(description = "查询条件") @Valid AppUserBo bo,
|
||||
@Parameter(description = "分页参数") @Valid PageQuery pageQuery) {
|
||||
return appUserService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出App端用户信息列表
|
||||
*/
|
||||
@Operation(summary = "导出用户列表", description = "导出App端用户信息到Excel")
|
||||
@SaCheckPermission("app:user:export")
|
||||
@Log(title = "App端用户信息", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(
|
||||
@Parameter(description = "查询条件") @Valid AppUserBo bo,
|
||||
HttpServletResponse response) {
|
||||
List<AppUserVo> list = appUserService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "App端用户信息", AppUserVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取App端用户信息详细信息
|
||||
*/
|
||||
@Operation(summary = "获取用户详情", description = "根据用户ID获取详细信息")
|
||||
@SaCheckPermission("app:user:query")
|
||||
@GetMapping("/{userId}")
|
||||
public R<AppUserVo> getInfo(
|
||||
@Parameter(description = "用户ID", required = true)
|
||||
@PathVariable @NotNull(message = "用户ID不能为空") @Positive(message = "用户ID必须为正数") Long userId) {
|
||||
return R.ok(appUserService.queryById(userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增App端用户信息
|
||||
*/
|
||||
@Operation(summary = "新增用户", description = "创建新的App端用户")
|
||||
@SaCheckPermission("app:user:add")
|
||||
@Log(title = "App端用户信息", businessType = BusinessType.INSERT)
|
||||
@PostMapping()
|
||||
public R<Void> add(
|
||||
@Parameter(description = "用户信息", required = true)
|
||||
@Validated(AddGroup.class) @RequestBody AppUserBo bo) {
|
||||
return toAjax(appUserService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改App端用户信息
|
||||
*/
|
||||
@Operation(summary = "修改用户", description = "更新App端用户信息")
|
||||
@SaCheckPermission("app:user:edit")
|
||||
@Log(title = "App端用户信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping()
|
||||
public R<Void> edit(
|
||||
@Parameter(description = "用户信息", required = true)
|
||||
@Validated(EditGroup.class) @RequestBody AppUserBo bo) {
|
||||
return toAjax(appUserService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除App端用户信息
|
||||
*/
|
||||
@Operation(summary = "删除用户", description = "批量删除App端用户")
|
||||
@SaCheckPermission("app:user:remove")
|
||||
@Log(title = "App端用户信息", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{userIds}")
|
||||
public R<Void> remove(
|
||||
@Parameter(description = "用户ID列表", required = true)
|
||||
@PathVariable @NotEmpty(message = "用户ID列表不能为空") Long[] userIds) {
|
||||
return toAjax(appUserService.deleteWithValidByIds(List.of(userIds), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
*/
|
||||
@Operation(summary = "重置密码", description = "重置用户密码")
|
||||
@SaCheckPermission("app:user:resetPwd")
|
||||
@Log(title = "App端用户信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/resetPwd")
|
||||
public R<Void> resetPwd(
|
||||
@Parameter(description = "用户信息", required = true)
|
||||
@Validated(EditGroup.class) @RequestBody AppUserBo bo) {
|
||||
return toAjax(appUserService.resetPassword(bo.getUserId(), bo.getPassword()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态修改
|
||||
*/
|
||||
@Operation(summary = "修改用户状态", description = "启用或禁用用户")
|
||||
@SaCheckPermission("app:user:edit")
|
||||
@Log(title = "App端用户信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/changeStatus")
|
||||
public R<Void> changeStatus(
|
||||
@Parameter(description = "用户信息", required = true)
|
||||
@Validated(EditGroup.class) @RequestBody AppUserBo bo) {
|
||||
// 如果用户状态变为禁用,则冻结用户的所有token
|
||||
if ("1".equals(bo.getStatus())) {
|
||||
StpUtil.disable(bo.getUserId(), -1); // -1表示永久冻结,直到手动解冻
|
||||
} else if ("0".equals(bo.getStatus())) {
|
||||
// 如果用户状态变为正常,则解冻用户
|
||||
StpUtil.untieDisable(bo.getUserId());
|
||||
}
|
||||
return toAjax(appUserService.updateUserStatus(bo.getUserId(), bo.getStatus()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户编号获取详细信息
|
||||
*/
|
||||
@Operation(summary = "获取用户档案", description = "根据用户ID获取用户档案信息")
|
||||
@SaCheckPermission("app:user:query")
|
||||
@GetMapping("/profile/{userId}")
|
||||
public R<AppUserVo> profile(
|
||||
@Parameter(description = "用户ID", required = true)
|
||||
@PathVariable @NotNull(message = "用户ID不能为空") @Positive(message = "用户ID必须为正数") Long userId) {
|
||||
AppUserVo user = appUserService.queryById(userId);
|
||||
return R.ok(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户信息
|
||||
*/
|
||||
@Operation(summary = "获取当前用户信息", description = "获取当前登录用户的详细信息")
|
||||
@GetMapping("/getInfo")
|
||||
public R<AppUserVo> getInfo() {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
AppUserVo user = appUserService.queryById(loginUser.getUserId());
|
||||
return R.ok(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户个人信息
|
||||
*/
|
||||
@Operation(summary = "获取个人信息", description = "获取当前用户的个人信息")
|
||||
@GetMapping("/profile")
|
||||
public R<AppUserVo> getUserProfile() {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
AppUserVo user = appUserService.queryById(loginUser.getUserId());
|
||||
return R.ok(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户个人信息
|
||||
*/
|
||||
@Operation(summary = "修改个人信息", description = "更新当前用户的个人信息")
|
||||
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/profile")
|
||||
public R<Void> updateUserProfile(
|
||||
@Parameter(description = "用户信息", required = true)
|
||||
@Validated(EditGroup.class) @RequestBody AppUserBo bo) {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
bo.setUserId(loginUser.getUserId());
|
||||
return toAjax(appUserService.updateByBo(bo));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
*/
|
||||
@Operation(summary = "修改密码", description = "修改当前用户的登录密码")
|
||||
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/profile/updatePwd")
|
||||
public R<Void> updateUserPwd(
|
||||
@Parameter(description = "原密码", required = true)
|
||||
@RequestParam @NotBlank(message = "原密码不能为空") @Size(min = 6, max = 20, message = "密码长度必须在6-20位之间") String oldPassword,
|
||||
@Parameter(description = "新密码", required = true)
|
||||
@RequestParam @NotBlank(message = "新密码不能为空") @Size(min = 6, max = 20, message = "密码长度必须在6-20位之间") String newPassword) {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
return toAjax(appUserService.updatePassword(loginUser.getUserId(), oldPassword, newPassword));
|
||||
}
|
||||
|
||||
}
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
package org.dromara.member.controller.app;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.member.domain.bo.AppVersionBo;
|
||||
import org.dromara.member.domain.vo.AppVersionVo;
|
||||
import org.dromara.member.service.AppVersionService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* App端版本管理
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Tag(name = "App端版本管理", description = "App端版本管理相关接口")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/app/version")
|
||||
public class AppVersionController extends BaseController {
|
||||
|
||||
private final AppVersionService appVersionService;
|
||||
|
||||
/**
|
||||
* 查询App版本信息列表
|
||||
*/
|
||||
@Operation(summary = "查询版本列表", description = "查询App版本信息列表")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<AppVersionVo> list(@Parameter(description = "查询条件") @Valid AppVersionBo bo,
|
||||
@Parameter(description = "分页参数") @Valid PageQuery pageQuery) {
|
||||
return appVersionService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取App版本信息详细信息
|
||||
*/
|
||||
@Operation(summary = "获取版本详情", description = "获取App版本信息详细信息")
|
||||
@GetMapping("/{versionId}")
|
||||
public R<AppVersionVo> getInfo(@Parameter(description = "版本ID", required = true)
|
||||
@PathVariable @NotNull(message = "版本ID不能为空") @Positive(message = "版本ID必须为正数") Long versionId) {
|
||||
return R.ok(appVersionService.queryById(versionId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查版本更新
|
||||
*/
|
||||
@Operation(summary = "检查版本更新", description = "检查是否有新版本可用")
|
||||
@GetMapping("/checkUpdate")
|
||||
public R<Map<String, Object>> checkUpdate(@Parameter(description = "平台类型(android/ios/web)", required = true)
|
||||
@RequestParam @NotBlank(message = "平台类型不能为空") @Pattern(regexp = "^(android|ios|web)$", message = "平台类型只能为android、ios或web") String platform,
|
||||
@Parameter(description = "当前版本号", required = true)
|
||||
@RequestParam @NotNull(message = "当前版本号不能为空") @Positive(message = "当前版本号必须为正数") Integer currentVersionCode) {
|
||||
if (StringUtils.isBlank(platform)) {
|
||||
return R.fail("平台类型不能为空");
|
||||
}
|
||||
if (currentVersionCode == null || currentVersionCode <= 0) {
|
||||
return R.fail("当前版本号无效");
|
||||
}
|
||||
|
||||
AppVersionVo updateInfo = appVersionService.getUpdateInfo(platform, currentVersionCode);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
if (updateInfo != null) {
|
||||
result.put("hasUpdate", true);
|
||||
result.put("versionInfo", updateInfo);
|
||||
result.put("isForce", "1".equals(updateInfo.getIsForce()));
|
||||
result.put("needUpdate", true);
|
||||
} else {
|
||||
result.put("hasUpdate", false);
|
||||
result.put("needUpdate", false);
|
||||
result.put("isForce", false);
|
||||
result.put("message", "当前已是最新版本");
|
||||
}
|
||||
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最新版本信息
|
||||
*/
|
||||
@Operation(summary = "获取最新版本", description = "获取指定平台的最新版本信息")
|
||||
@GetMapping("/latest")
|
||||
public R<AppVersionVo> getLatestVersion(@Parameter(description = "平台类型(android/ios/web)", required = true)
|
||||
@RequestParam @NotBlank(message = "平台类型不能为空") @Pattern(regexp = "^(android|ios|web)$", message = "平台类型只能为android、ios或web") String platform) {
|
||||
if (StringUtils.isBlank(platform)) {
|
||||
return R.fail("平台类型不能为空");
|
||||
}
|
||||
|
||||
AppVersionVo latestVersion = appVersionService.getLatestVersion(platform);
|
||||
if (latestVersion == null) {
|
||||
return R.fail("未找到该平台的版本信息");
|
||||
}
|
||||
|
||||
return R.ok(latestVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取版本历史记录
|
||||
*/
|
||||
@Operation(summary = "获取版本历史", description = "获取指定平台的版本历史记录")
|
||||
@GetMapping("/history")
|
||||
public R<List<AppVersionVo>> getVersionHistory(@Parameter(description = "平台类型(android/ios/web)", required = true)
|
||||
@RequestParam @NotBlank(message = "平台类型不能为空") @Pattern(regexp = "^(android|ios|web)$", message = "平台类型只能为android、ios或web") String platform,
|
||||
@Parameter(description = "返回数量限制")
|
||||
@RequestParam(defaultValue = "10") @Min(value = 1, message = "限制数量必须大于0") @Max(value = 100, message = "限制数量不能超过100") Integer limit) {
|
||||
if (StringUtils.isBlank(platform)) {
|
||||
return R.fail("平台类型不能为空");
|
||||
}
|
||||
|
||||
List<AppVersionVo> versionHistory = appVersionService.getVersionHistory(platform, limit);
|
||||
return R.ok(versionHistory);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否强制更新
|
||||
*/
|
||||
@Operation(summary = "检查强制更新", description = "检查当前版本是否需要强制更新")
|
||||
@GetMapping("/checkForceUpdate")
|
||||
public R<Map<String, Object>> checkForceUpdate(@Parameter(description = "平台类型(android/ios/web)", required = true)
|
||||
@RequestParam @NotBlank(message = "平台类型不能为空") @Pattern(regexp = "^(android|ios|web)$", message = "平台类型只能为android、ios或web") String platform,
|
||||
@Parameter(description = "当前版本号", required = true)
|
||||
@RequestParam @NotNull(message = "当前版本号不能为空") @Positive(message = "当前版本号必须为正数") Integer currentVersionCode) {
|
||||
if (StringUtils.isBlank(platform)) {
|
||||
return R.fail("平台类型不能为空");
|
||||
}
|
||||
if (currentVersionCode == null || currentVersionCode <= 0) {
|
||||
return R.fail("当前版本号无效");
|
||||
}
|
||||
|
||||
Boolean forceUpdate = appVersionService.checkForceUpdate(platform, currentVersionCode);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("forceUpdate", forceUpdate);
|
||||
|
||||
if (forceUpdate) {
|
||||
AppVersionVo updateInfo = appVersionService.getUpdateInfo(platform, currentVersionCode);
|
||||
result.put("versionInfo", updateInfo);
|
||||
}
|
||||
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取更新信息
|
||||
*/
|
||||
@Operation(summary = "获取更新信息", description = "获取详细的版本更新信息")
|
||||
@GetMapping("/updateInfo")
|
||||
public R<Map<String, Object>> getUpdateInfo(@Parameter(description = "平台类型(android/ios/web)", required = true)
|
||||
@RequestParam @NotBlank(message = "平台类型不能为空") @Pattern(regexp = "^(android|ios|web)$", message = "平台类型只能为android、ios或web") String platform,
|
||||
@Parameter(description = "当前版本号", required = true)
|
||||
@RequestParam @NotNull(message = "当前版本号不能为空") @Positive(message = "当前版本号必须为正数") Integer currentVersionCode) {
|
||||
if (StringUtils.isBlank(platform)) {
|
||||
return R.fail("平台类型不能为空");
|
||||
}
|
||||
if (currentVersionCode == null || currentVersionCode <= 0) {
|
||||
return R.fail("当前版本号无效");
|
||||
}
|
||||
|
||||
AppVersionVo updateInfo = appVersionService.getUpdateInfo(platform, currentVersionCode);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
if (updateInfo != null) {
|
||||
result.put("hasUpdate", true);
|
||||
result.put("versionCode", updateInfo.getVersionCode());
|
||||
result.put("versionName", updateInfo.getVersionName());
|
||||
result.put("updateContent", updateInfo.getUpdateContent());
|
||||
result.put("downloadUrl", updateInfo.getDownloadUrl());
|
||||
result.put("isForce", "1".equals(updateInfo.getIsForce()));
|
||||
result.put("platform", updateInfo.getPlatform());
|
||||
result.put("createTime", updateInfo.getCreateTime());
|
||||
} else {
|
||||
result.put("hasUpdate", false);
|
||||
result.put("message", "当前已是最新版本");
|
||||
}
|
||||
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 版本比较
|
||||
*/
|
||||
@Operation(summary = "版本比较", description = "比较两个版本之间的差异")
|
||||
@GetMapping("/compare")
|
||||
public R<Map<String, Object>> compareVersion(@Parameter(description = "平台类型(android/ios/web)", required = true)
|
||||
@RequestParam @NotBlank(message = "平台类型不能为空") @Pattern(regexp = "^(android|ios|web)$", message = "平台类型只能为android、ios或web") String platform,
|
||||
@Parameter(description = "当前版本号", required = true)
|
||||
@RequestParam @NotNull(message = "当前版本号不能为空") @Positive(message = "当前版本号必须为正数") Integer currentVersionCode,
|
||||
@Parameter(description = "目标版本号", required = true)
|
||||
@RequestParam @NotNull(message = "目标版本号不能为空") @Positive(message = "目标版本号必须为正数") Integer targetVersionCode) {
|
||||
if (StringUtils.isBlank(platform)) {
|
||||
return R.fail("平台类型不能为空");
|
||||
}
|
||||
if (currentVersionCode == null || targetVersionCode == null) {
|
||||
return R.fail("版本号不能为空");
|
||||
}
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("platform", platform);
|
||||
result.put("currentVersionCode", currentVersionCode);
|
||||
result.put("targetVersionCode", targetVersionCode);
|
||||
|
||||
if (targetVersionCode > currentVersionCode) {
|
||||
result.put("needUpdate", true);
|
||||
result.put("updateType", "upgrade");
|
||||
} else if (targetVersionCode < currentVersionCode) {
|
||||
result.put("needUpdate", false);
|
||||
result.put("updateType", "downgrade");
|
||||
} else {
|
||||
result.put("needUpdate", false);
|
||||
result.put("updateType", "same");
|
||||
}
|
||||
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录版本下载
|
||||
*/
|
||||
@Operation(summary = "记录版本下载", description = "记录用户下载版本的行为")
|
||||
@Log(title = "App版本下载", businessType = BusinessType.OTHER)
|
||||
@PostMapping("/download/{versionId}")
|
||||
public R<Void> recordDownload(@Parameter(description = "版本ID", required = true)
|
||||
@PathVariable @NotNull(message = "版本ID不能为空") @Positive(message = "版本ID必须为正数") Long versionId) {
|
||||
// 这里可以记录下载统计等信息
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录版本安装
|
||||
*/
|
||||
@Operation(summary = "记录版本安装", description = "记录用户安装版本的行为")
|
||||
@Log(title = "App版本安装", businessType = BusinessType.OTHER)
|
||||
@PostMapping("/install/{versionId}")
|
||||
public R<Void> recordInstall(@Parameter(description = "版本ID", required = true)
|
||||
@PathVariable @NotNull(message = "版本ID不能为空") @Positive(message = "版本ID必须为正数") Long versionId) {
|
||||
// 这里可以记录安装统计等信息
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package org.dromara.member.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端设备信息对象 app_device
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@TableName("app_device")
|
||||
public class AppDevice implements Serializable {
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
@TableId(value = "device_id")
|
||||
private Long deviceId;
|
||||
|
||||
/**
|
||||
* App用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 设备类型(ios android h5)
|
||||
*/
|
||||
private String deviceType;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 设备型号
|
||||
*/
|
||||
private String deviceModel;
|
||||
|
||||
/**
|
||||
* 设备品牌
|
||||
*/
|
||||
private String deviceBrand;
|
||||
|
||||
/**
|
||||
* 操作系统版本
|
||||
*/
|
||||
private String osVersion;
|
||||
|
||||
/**
|
||||
* App版本
|
||||
*/
|
||||
private String appVersion;
|
||||
|
||||
/**
|
||||
* 推送令牌
|
||||
*/
|
||||
private String pushToken;
|
||||
|
||||
/**
|
||||
* 是否活跃(0否 1是)
|
||||
*/
|
||||
private String isActive;
|
||||
|
||||
/**
|
||||
* 最后活跃时间
|
||||
*/
|
||||
private LocalDateTime lastActiveTime;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 2代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package org.dromara.member.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* App端文件信息对象 app_file
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("app_file")
|
||||
public class AppFile extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 文件ID
|
||||
*/
|
||||
@TableId(value = "file_id")
|
||||
private Long fileId;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
private String fileName;
|
||||
|
||||
/**
|
||||
* 原始文件名
|
||||
*/
|
||||
private String originalName;
|
||||
|
||||
/**
|
||||
* 文件路径
|
||||
*/
|
||||
private String filePath;
|
||||
|
||||
/**
|
||||
* 文件URL
|
||||
*/
|
||||
private String fileUrl;
|
||||
|
||||
/**
|
||||
* 文件大小(字节)
|
||||
*/
|
||||
private Long fileSize;
|
||||
|
||||
/**
|
||||
* 文件类型(MIME类型)
|
||||
*/
|
||||
private String fileType;
|
||||
|
||||
/**
|
||||
* 文件后缀
|
||||
*/
|
||||
private String fileSuffix;
|
||||
|
||||
/**
|
||||
* 文件分类(1头像 2文档 3图片 4视频 5音频 6其他)
|
||||
*/
|
||||
private Integer fileCategory;
|
||||
|
||||
/**
|
||||
* 存储服务商
|
||||
*/
|
||||
private String storageService;
|
||||
|
||||
/**
|
||||
* 文件状态(0正常 1删除)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 下载次数
|
||||
*/
|
||||
private Long downloadCount;
|
||||
|
||||
/**
|
||||
* 是否公开(0私有 1公开)
|
||||
*/
|
||||
private String isPublic;
|
||||
|
||||
/**
|
||||
* 文件MD5值
|
||||
*/
|
||||
private String fileMd5;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 2代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package org.dromara.member.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端登录日志对象 app_login_log
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@TableName("app_login_log")
|
||||
public class AppLoginLog implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 访问ID
|
||||
*/
|
||||
@TableId(value = "info_id")
|
||||
private Long infoId;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 登录状态(0成功 1失败)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 登录IP地址
|
||||
*/
|
||||
private String ipaddr;
|
||||
|
||||
/**
|
||||
* 登录地点
|
||||
*/
|
||||
private String loginLocation;
|
||||
|
||||
/**
|
||||
* 浏览器类型
|
||||
*/
|
||||
private String browser;
|
||||
|
||||
/**
|
||||
* 操作系统
|
||||
*/
|
||||
private String os;
|
||||
|
||||
/**
|
||||
* 提示消息
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* 登录时间
|
||||
*/
|
||||
private LocalDateTime loginTime;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package org.dromara.member.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端消息推送对象 app_message
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@TableName("app_message")
|
||||
public class AppMessage implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 消息ID
|
||||
*/
|
||||
@TableId(value = "message_id")
|
||||
private Long messageId;
|
||||
|
||||
/**
|
||||
* 消息标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 消息类型(system:系统消息 notice:通知 activity:活动)
|
||||
*/
|
||||
private String messageType;
|
||||
|
||||
/**
|
||||
* 推送目标(all:全部用户 user:指定用户 role:指定角色)
|
||||
*/
|
||||
private String targetType;
|
||||
|
||||
/**
|
||||
* 目标ID列表(用户ID或角色ID,逗号分隔)
|
||||
*/
|
||||
private String targetIds;
|
||||
|
||||
/**
|
||||
* 发送时间
|
||||
*/
|
||||
private LocalDateTime sendTime;
|
||||
|
||||
/**
|
||||
* 状态(0待发送 1已发送 2发送失败)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 2代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package org.dromara.member.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端操作日志对象 app_oper_log
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@TableName("app_oper_log")
|
||||
public class AppOperLog implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 日志主键
|
||||
*/
|
||||
@TableId(value = "oper_id")
|
||||
private Long operId;
|
||||
|
||||
/**
|
||||
* 模块标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 业务类型(0其它 1新增 2修改 3删除)
|
||||
*/
|
||||
private Integer businessType;
|
||||
|
||||
/**
|
||||
* 方法名称
|
||||
*/
|
||||
private String method;
|
||||
|
||||
/**
|
||||
* 请求方式
|
||||
*/
|
||||
private String requestMethod;
|
||||
|
||||
/**
|
||||
* 操作人员
|
||||
*/
|
||||
private String operName;
|
||||
|
||||
/**
|
||||
* 请求URL
|
||||
*/
|
||||
private String operUrl;
|
||||
|
||||
/**
|
||||
* 主机地址
|
||||
*/
|
||||
private String operIp;
|
||||
|
||||
/**
|
||||
* 操作地点
|
||||
*/
|
||||
private String operLocation;
|
||||
|
||||
/**
|
||||
* 请求参数
|
||||
*/
|
||||
private String operParam;
|
||||
|
||||
/**
|
||||
* 返回参数
|
||||
*/
|
||||
private String jsonResult;
|
||||
|
||||
/**
|
||||
* 操作状态(0正常 1异常)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 错误消息
|
||||
*/
|
||||
private String errorMsg;
|
||||
|
||||
/**
|
||||
* 操作时间
|
||||
*/
|
||||
private LocalDateTime operTime;
|
||||
|
||||
/**
|
||||
* 消耗时间
|
||||
*/
|
||||
private Long costTime;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.dromara.member.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端角色信息对象 app_role
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@TableName("app_role")
|
||||
public class AppRole implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* App角色ID
|
||||
*/
|
||||
@TableId(value = "role_id")
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 角色名称
|
||||
*/
|
||||
private String roleName;
|
||||
|
||||
/**
|
||||
* 角色权限字符串
|
||||
*/
|
||||
private String roleKey;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
private Integer roleSort;
|
||||
|
||||
/**
|
||||
* 角色状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
package org.dromara.member.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* App端第三方登录授权对象 app_social_auth
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@TableName("app_social_auth")
|
||||
public class AppSocialAuth implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* App用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户来源平台(wechat_mp:微信小程序 wechat_open:微信开放平台 qq:QQ weibo:微博)
|
||||
*/
|
||||
private String platform;
|
||||
|
||||
/**
|
||||
* 表示平台唯一用户标识
|
||||
*/
|
||||
private String platformUid;
|
||||
|
||||
/**
|
||||
* 微信openid
|
||||
*/
|
||||
private String openId;
|
||||
|
||||
/**
|
||||
* 微信unionid
|
||||
*/
|
||||
private String unionId;
|
||||
|
||||
/**
|
||||
* 用户的授权令牌
|
||||
*/
|
||||
private String accessToken;
|
||||
|
||||
/**
|
||||
* 用户的授权令牌的有效期
|
||||
*/
|
||||
private Integer expireIn;
|
||||
|
||||
/**
|
||||
* 刷新令牌
|
||||
*/
|
||||
private String refreshToken;
|
||||
|
||||
/**
|
||||
* 授予的权限
|
||||
*/
|
||||
private String scope;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 2代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建部门
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private Long createDept;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package org.dromara.member.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端用户信息对象 app_user
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@TableName("app_user")
|
||||
public class AppUser implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* App用户ID
|
||||
*/
|
||||
@TableId(value = "user_id")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 用户性别(0男 1女 2未知)
|
||||
*/
|
||||
private String sex;
|
||||
|
||||
/**
|
||||
* 头像地址
|
||||
*/
|
||||
private Long avatar;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 帐号状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 最后登录IP
|
||||
*/
|
||||
private String loginIp;
|
||||
|
||||
/**
|
||||
* 最后登录时间
|
||||
*/
|
||||
private LocalDateTime loginDate;
|
||||
|
||||
/**
|
||||
* 注册时间
|
||||
*/
|
||||
private LocalDateTime registerTime;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package org.dromara.member.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端用户消息读取记录对象 app_user_message
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@TableName("app_user_message")
|
||||
public class AppUserMessage implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* App用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 消息ID
|
||||
*/
|
||||
private Long messageId;
|
||||
|
||||
/**
|
||||
* 是否已读(0未读 1已读)
|
||||
*/
|
||||
private String isRead;
|
||||
|
||||
/**
|
||||
* 读取时间
|
||||
*/
|
||||
private LocalDateTime readTime;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 2代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.dromara.member.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端用户和角色关联对象 app_user_role
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@TableName("app_user_role")
|
||||
public class AppUserRole implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* App用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* App角色ID
|
||||
*/
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 2代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package org.dromara.member.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App版本信息对象 app_version
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@TableName("app_version")
|
||||
public class AppVersion implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 版本ID
|
||||
*/
|
||||
@TableId(value = "version_id")
|
||||
private Long versionId;
|
||||
|
||||
/**
|
||||
* 版本号(数字)
|
||||
*/
|
||||
private Integer versionCode;
|
||||
|
||||
/**
|
||||
* 版本名(如1.0.0)
|
||||
*/
|
||||
private String versionName;
|
||||
|
||||
/**
|
||||
* 更新内容
|
||||
*/
|
||||
private String updateContent;
|
||||
|
||||
/**
|
||||
* 下载地址
|
||||
*/
|
||||
private String downloadUrl;
|
||||
|
||||
/**
|
||||
* 是否强制更新(0否 1是)
|
||||
*/
|
||||
private String isForce;
|
||||
|
||||
/**
|
||||
* 平台类型(android ios)
|
||||
*/
|
||||
private String platform;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 2代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package org.dromara.member.domain.bo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端设备信息业务对象 app_device
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = org.dromara.member.domain.AppDevice.class, reverseConvertGenerate = false)
|
||||
public class AppDeviceBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
@NotNull(message = "设备ID不能为空", groups = {EditGroup.class})
|
||||
private Long deviceId;
|
||||
|
||||
/**
|
||||
* App用户ID
|
||||
*/
|
||||
@NotNull(message = "用户ID不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 设备类型(ios android h5)
|
||||
*/
|
||||
@NotBlank(message = "设备类型不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String deviceType;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 设备型号
|
||||
*/
|
||||
private String deviceModel;
|
||||
|
||||
/**
|
||||
* 设备品牌
|
||||
*/
|
||||
private String deviceBrand;
|
||||
|
||||
/**
|
||||
* 操作系统版本
|
||||
*/
|
||||
private String osVersion;
|
||||
|
||||
/**
|
||||
* App版本
|
||||
*/
|
||||
private String appVersion;
|
||||
|
||||
/**
|
||||
* 推送令牌
|
||||
*/
|
||||
private String pushToken;
|
||||
|
||||
/**
|
||||
* 是否活跃(0否 1是)
|
||||
*/
|
||||
private String isActive;
|
||||
|
||||
/**
|
||||
* 最后活跃时间
|
||||
*/
|
||||
private LocalDateTime lastActiveTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package org.dromara.member.domain.bo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.member.domain.AppFile;
|
||||
|
||||
/**
|
||||
* App端文件信息业务对象 app_file
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = AppFile.class, reverseConvertGenerate = false)
|
||||
public class AppFileBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 文件ID
|
||||
*/
|
||||
@NotNull(message = "文件ID不能为空", groups = {EditGroup.class})
|
||||
private Long fileId;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
@NotBlank(message = "文件名不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String fileName;
|
||||
|
||||
/**
|
||||
* 原始文件名
|
||||
*/
|
||||
@NotBlank(message = "原始文件名不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String originalName;
|
||||
|
||||
/**
|
||||
* 文件路径
|
||||
*/
|
||||
private String filePath;
|
||||
|
||||
/**
|
||||
* 文件URL
|
||||
*/
|
||||
@NotBlank(message = "文件URL不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String fileUrl;
|
||||
|
||||
/**
|
||||
* 文件大小(字节)
|
||||
*/
|
||||
@NotNull(message = "文件大小不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Long fileSize;
|
||||
|
||||
/**
|
||||
* 文件类型(MIME类型)
|
||||
*/
|
||||
private String fileType;
|
||||
|
||||
/**
|
||||
* 文件后缀
|
||||
*/
|
||||
private String fileSuffix;
|
||||
|
||||
/**
|
||||
* 文件分类(1头像 2文档 3图片 4视频 5音频 6其他)
|
||||
*/
|
||||
private Integer fileCategory;
|
||||
|
||||
/**
|
||||
* 存储服务商
|
||||
*/
|
||||
private String storageService;
|
||||
|
||||
/**
|
||||
* 文件状态(0正常 1删除)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 下载次数
|
||||
*/
|
||||
private Long downloadCount;
|
||||
|
||||
/**
|
||||
* 是否公开(0私有 1公开)
|
||||
*/
|
||||
private String isPublic;
|
||||
|
||||
/**
|
||||
* 文件MD5值
|
||||
*/
|
||||
private String fileMd5;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
package org.dromara.member.domain.bo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端消息业务对象 app_message
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = org.dromara.member.domain.AppMessage.class, reverseConvertGenerate = false)
|
||||
public class AppMessageBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 消息ID
|
||||
*/
|
||||
@NotNull(message = "消息ID不能为空", groups = {EditGroup.class})
|
||||
private Long messageId;
|
||||
|
||||
/**
|
||||
* 消息标题
|
||||
*/
|
||||
@NotBlank(message = "消息标题不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
@NotBlank(message = "消息内容不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 消息类型(system:系统消息 notice:通知 activity:活动)
|
||||
*/
|
||||
private String messageType;
|
||||
|
||||
/**
|
||||
* 推送目标(all:全部用户 user:指定用户 role:指定角色)
|
||||
*/
|
||||
private String targetType;
|
||||
|
||||
/**
|
||||
* 目标ID列表(用户ID或角色ID,逗号分隔)
|
||||
*/
|
||||
private String targetIds;
|
||||
|
||||
/**
|
||||
* 发送时间
|
||||
*/
|
||||
private LocalDateTime sendTime;
|
||||
|
||||
/**
|
||||
* 状态(0待发送 1已发送 2发送失败)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 接收者ID(用于查询当前用户的消息)
|
||||
*/
|
||||
private Long receiverId;
|
||||
|
||||
/**
|
||||
* 发送者ID
|
||||
*/
|
||||
private Long senderId;
|
||||
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
package org.dromara.member.domain.bo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.member.domain.AppOperLog;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端操作日志业务对象 app_oper_log
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = AppOperLog.class, reverseConvertGenerate = false)
|
||||
public class AppOperLogBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 日志主键
|
||||
*/
|
||||
@NotNull(message = "日志主键不能为空", groups = {EditGroup.class})
|
||||
private Long operId;
|
||||
|
||||
/**
|
||||
* 模块标题
|
||||
*/
|
||||
@NotBlank(message = "模块标题不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 业务类型(0其它 1新增 2修改 3删除)
|
||||
*/
|
||||
private Integer businessType;
|
||||
|
||||
/**
|
||||
* 方法名称
|
||||
*/
|
||||
private String method;
|
||||
|
||||
/**
|
||||
* 请求方式
|
||||
*/
|
||||
private String requestMethod;
|
||||
|
||||
/**
|
||||
* 操作人员
|
||||
*/
|
||||
private String operName;
|
||||
|
||||
/**
|
||||
* 请求URL
|
||||
*/
|
||||
private String operUrl;
|
||||
|
||||
/**
|
||||
* 主机地址
|
||||
*/
|
||||
private String operIp;
|
||||
|
||||
/**
|
||||
* 操作地点
|
||||
*/
|
||||
private String operLocation;
|
||||
|
||||
/**
|
||||
* 请求参数
|
||||
*/
|
||||
private String operParam;
|
||||
|
||||
/**
|
||||
* 返回参数
|
||||
*/
|
||||
private String jsonResult;
|
||||
|
||||
/**
|
||||
* 操作状态(0正常 1异常)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 错误消息
|
||||
*/
|
||||
private String errorMsg;
|
||||
|
||||
/**
|
||||
* 操作时间
|
||||
*/
|
||||
private LocalDateTime operTime;
|
||||
|
||||
/**
|
||||
* 消耗时间
|
||||
*/
|
||||
private Long costTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package org.dromara.member.domain.bo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.member.domain.AppRole;
|
||||
|
||||
/**
|
||||
* App端角色信息业务对象 app_role
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = AppRole.class, reverseConvertGenerate = false)
|
||||
public class AppRoleBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* App角色ID
|
||||
*/
|
||||
@NotNull(message = "App角色ID不能为空", groups = {EditGroup.class})
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 角色名称
|
||||
*/
|
||||
@NotBlank(message = "角色名称不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
@Size(max = 30, message = "角色名称长度不能超过30个字符")
|
||||
private String roleName;
|
||||
|
||||
/**
|
||||
* 角色权限字符串
|
||||
*/
|
||||
@NotBlank(message = "角色权限字符串不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
@Size(max = 100, message = "角色权限字符串长度不能超过100个字符")
|
||||
private String roleKey;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
@NotNull(message = "显示顺序不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Integer roleSort;
|
||||
|
||||
/**
|
||||
* 角色状态(0正常 1停用)
|
||||
*/
|
||||
@NotBlank(message = "角色状态不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 用户ID(用于用户角色授权操作)
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package org.dromara.member.domain.bo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.member.domain.AppUser;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端用户信息业务对象 app_user
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = AppUser.class, reverseConvertGenerate = false)
|
||||
public class AppUserBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* App用户ID
|
||||
*/
|
||||
@NotNull(message = "App用户ID不能为空", groups = {EditGroup.class})
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
@NotBlank(message = "用户账号不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
@Size(max = 30, message = "用户账号长度不能超过30个字符")
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
@NotBlank(message = "用户昵称不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
@Size(max = 30, message = "用户昵称长度不能超过30个字符")
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
@Size(max = 11, message = "手机号码长度不能超过11个字符")
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
@Email(message = "邮箱格式不正确")
|
||||
@Size(max = 50, message = "用户邮箱长度不能超过50个字符")
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 用户性别(0男 1女 2未知)
|
||||
*/
|
||||
private String sex;
|
||||
|
||||
/**
|
||||
* 头像地址
|
||||
*/
|
||||
private Long avatar;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
@Size(max = 100, message = "密码长度不能超过100个字符")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 帐号状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 最后登录IP
|
||||
*/
|
||||
private String loginIp;
|
||||
|
||||
/**
|
||||
* 最后登录时间
|
||||
*/
|
||||
private LocalDateTime loginDate;
|
||||
|
||||
/**
|
||||
* 注册时间
|
||||
*/
|
||||
private LocalDateTime registerTime;
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package org.dromara.member.domain.bo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.member.domain.AppVersion;
|
||||
|
||||
/**
|
||||
* App版本信息业务对象 app_version
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = AppVersion.class, reverseConvertGenerate = false)
|
||||
public class AppVersionBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 版本ID
|
||||
*/
|
||||
@NotNull(message = "版本ID不能为空", groups = {EditGroup.class})
|
||||
private Long versionId;
|
||||
|
||||
/**
|
||||
* 版本号(数字)
|
||||
*/
|
||||
@NotNull(message = "版本号不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Integer versionCode;
|
||||
|
||||
/**
|
||||
* 版本名(如1.0.0)
|
||||
*/
|
||||
@NotBlank(message = "版本名不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String versionName;
|
||||
|
||||
/**
|
||||
* 更新内容
|
||||
*/
|
||||
private String updateContent;
|
||||
|
||||
/**
|
||||
* 下载地址
|
||||
*/
|
||||
private String downloadUrl;
|
||||
|
||||
/**
|
||||
* 是否强制更新(0否 1是)
|
||||
*/
|
||||
private String isForce;
|
||||
|
||||
/**
|
||||
* 平台类型(android ios)
|
||||
*/
|
||||
@NotBlank(message = "平台类型不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String platform;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
package org.dromara.member.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import org.dromara.member.domain.AppDevice;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端设备信息视图对象 app_device
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = AppDevice.class)
|
||||
public class AppDeviceVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
@ExcelProperty(value = "设备ID")
|
||||
private Long deviceId;
|
||||
|
||||
/**
|
||||
* App用户ID
|
||||
*/
|
||||
@ExcelProperty(value = "App用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 设备类型(ios android h5)
|
||||
*/
|
||||
@ExcelProperty(value = "设备类型", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "app_device_type")
|
||||
private String deviceType;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
@ExcelProperty(value = "设备名称")
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 设备型号
|
||||
*/
|
||||
@ExcelProperty(value = "设备型号")
|
||||
private String deviceModel;
|
||||
|
||||
/**
|
||||
* 设备品牌
|
||||
*/
|
||||
@ExcelProperty(value = "设备品牌")
|
||||
private String deviceBrand;
|
||||
|
||||
/**
|
||||
* 操作系统版本
|
||||
*/
|
||||
@ExcelProperty(value = "操作系统版本")
|
||||
private String osVersion;
|
||||
|
||||
/**
|
||||
* App版本
|
||||
*/
|
||||
@ExcelProperty(value = "App版本")
|
||||
private String appVersion;
|
||||
|
||||
/**
|
||||
* 推送令牌
|
||||
*/
|
||||
@ExcelProperty(value = "推送令牌")
|
||||
private String pushToken;
|
||||
|
||||
/**
|
||||
* 是否活跃(0否 1是)
|
||||
*/
|
||||
@ExcelProperty(value = "是否活跃", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_yes_no")
|
||||
private String isActive;
|
||||
|
||||
/**
|
||||
* 最后活跃时间
|
||||
*/
|
||||
@ExcelProperty(value = "最后活跃时间")
|
||||
private LocalDateTime lastActiveTime;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@ExcelProperty(value = "更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package org.dromara.member.domain.vo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.member.domain.AppFile;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端文件信息视图对象 app_file
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@AutoMapper(target = AppFile.class)
|
||||
public class AppFileVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 文件ID
|
||||
*/
|
||||
private Long fileId;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
private String fileName;
|
||||
|
||||
/**
|
||||
* 原始文件名
|
||||
*/
|
||||
private String originalName;
|
||||
|
||||
/**
|
||||
* 文件路径
|
||||
*/
|
||||
private String filePath;
|
||||
|
||||
/**
|
||||
* 文件URL
|
||||
*/
|
||||
private String fileUrl;
|
||||
|
||||
/**
|
||||
* 文件大小(字节)
|
||||
*/
|
||||
private Long fileSize;
|
||||
|
||||
/**
|
||||
* 文件类型(MIME类型)
|
||||
*/
|
||||
private String fileType;
|
||||
|
||||
/**
|
||||
* 文件后缀
|
||||
*/
|
||||
private String fileSuffix;
|
||||
|
||||
/**
|
||||
* 文件分类(1头像 2文档 3图片 4视频 5音频 6其他)
|
||||
*/
|
||||
private Integer fileCategory;
|
||||
|
||||
/**
|
||||
* 存储服务商
|
||||
*/
|
||||
private String storageService;
|
||||
|
||||
/**
|
||||
* 文件状态(0正常 1删除)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 下载次数
|
||||
*/
|
||||
private Long downloadCount;
|
||||
|
||||
/**
|
||||
* 是否公开(0私有 1公开)
|
||||
*/
|
||||
private String isPublic;
|
||||
|
||||
/**
|
||||
* 文件MD5值
|
||||
*/
|
||||
private String fileMd5;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private String updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package org.dromara.member.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import org.dromara.member.domain.AppLoginLog;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端登录日志视图对象 app_login_log
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = AppLoginLog.class)
|
||||
public class AppLoginLogVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 访问ID
|
||||
*/
|
||||
@ExcelProperty(value = "访问ID")
|
||||
private Long infoId;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
@ExcelProperty(value = "用户账号")
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 登录状态(0成功 1失败)
|
||||
*/
|
||||
@ExcelProperty(value = "登录状态", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_common_status")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 登录IP地址
|
||||
*/
|
||||
@ExcelProperty(value = "登录IP地址")
|
||||
private String ipaddr;
|
||||
|
||||
/**
|
||||
* 登录地点
|
||||
*/
|
||||
@ExcelProperty(value = "登录地点")
|
||||
private String loginLocation;
|
||||
|
||||
/**
|
||||
* 浏览器类型
|
||||
*/
|
||||
@ExcelProperty(value = "浏览器类型")
|
||||
private String browser;
|
||||
|
||||
/**
|
||||
* 操作系统
|
||||
*/
|
||||
@ExcelProperty(value = "操作系统")
|
||||
private String os;
|
||||
|
||||
/**
|
||||
* 提示消息
|
||||
*/
|
||||
@ExcelProperty(value = "提示消息")
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* 访问时间
|
||||
*/
|
||||
@ExcelProperty(value = "访问时间")
|
||||
private LocalDateTime loginTime;
|
||||
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package org.dromara.member.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import org.dromara.member.domain.AppMessage;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端消息推送视图对象 app_message
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = AppMessage.class)
|
||||
public class AppMessageVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 消息ID
|
||||
*/
|
||||
@ExcelProperty(value = "消息ID")
|
||||
private Long messageId;
|
||||
|
||||
/**
|
||||
* 消息标题
|
||||
*/
|
||||
@ExcelProperty(value = "消息标题")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
@ExcelProperty(value = "消息内容")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 消息类型(system:系统消息 notice:通知 activity:活动)
|
||||
*/
|
||||
@ExcelProperty(value = "消息类型", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "app_message_type")
|
||||
private String messageType;
|
||||
|
||||
/**
|
||||
* 推送目标(all:全部用户 user:指定用户 role:指定角色)
|
||||
*/
|
||||
@ExcelProperty(value = "推送目标", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "app_target_type")
|
||||
private String targetType;
|
||||
|
||||
/**
|
||||
* 目标ID列表(用户ID或角色ID,逗号分隔)
|
||||
*/
|
||||
@ExcelProperty(value = "目标ID列表")
|
||||
private String targetIds;
|
||||
|
||||
/**
|
||||
* 发送时间
|
||||
*/
|
||||
@ExcelProperty(value = "发送时间")
|
||||
private LocalDateTime sendTime;
|
||||
|
||||
/**
|
||||
* 状态(0待发送 1已发送 2发送失败)
|
||||
*/
|
||||
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "app_message_status")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
package org.dromara.member.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import org.dromara.member.domain.AppOperLog;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端操作日志视图对象 app_oper_log
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = AppOperLog.class)
|
||||
public class AppOperLogVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 日志主键
|
||||
*/
|
||||
@ExcelProperty(value = "日志主键")
|
||||
private Long operId;
|
||||
|
||||
/**
|
||||
* 模块标题
|
||||
*/
|
||||
@ExcelProperty(value = "模块标题")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 业务类型(0其它 1新增 2修改 3删除)
|
||||
*/
|
||||
@ExcelProperty(value = "业务类型", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_oper_type")
|
||||
private Integer businessType;
|
||||
|
||||
/**
|
||||
* 方法名称
|
||||
*/
|
||||
@ExcelProperty(value = "方法名称")
|
||||
private String method;
|
||||
|
||||
/**
|
||||
* 请求方式
|
||||
*/
|
||||
@ExcelProperty(value = "请求方式")
|
||||
private String requestMethod;
|
||||
|
||||
/**
|
||||
* 操作人员
|
||||
*/
|
||||
@ExcelProperty(value = "操作人员")
|
||||
private String operName;
|
||||
|
||||
/**
|
||||
* 请求URL
|
||||
*/
|
||||
@ExcelProperty(value = "请求URL")
|
||||
private String operUrl;
|
||||
|
||||
/**
|
||||
* 主机地址
|
||||
*/
|
||||
@ExcelProperty(value = "主机地址")
|
||||
private String operIp;
|
||||
|
||||
/**
|
||||
* 操作地点
|
||||
*/
|
||||
@ExcelProperty(value = "操作地点")
|
||||
private String operLocation;
|
||||
|
||||
/**
|
||||
* 请求参数
|
||||
*/
|
||||
@ExcelProperty(value = "请求参数")
|
||||
private String operParam;
|
||||
|
||||
/**
|
||||
* 返回参数
|
||||
*/
|
||||
@ExcelProperty(value = "返回参数")
|
||||
private String jsonResult;
|
||||
|
||||
/**
|
||||
* 操作状态(0正常 1异常)
|
||||
*/
|
||||
@ExcelProperty(value = "操作状态", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_common_status")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 错误消息
|
||||
*/
|
||||
@ExcelProperty(value = "错误消息")
|
||||
private String errorMsg;
|
||||
|
||||
/**
|
||||
* 操作时间
|
||||
*/
|
||||
@ExcelProperty(value = "操作时间")
|
||||
private LocalDateTime operTime;
|
||||
|
||||
/**
|
||||
* 消耗时间
|
||||
*/
|
||||
@ExcelProperty(value = "消耗时间")
|
||||
private Long costTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package org.dromara.member.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import org.dromara.member.domain.AppRole;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端角色信息视图对象 app_role
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = AppRole.class)
|
||||
public class AppRoleVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* App角色ID
|
||||
*/
|
||||
@ExcelProperty(value = "App角色ID")
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 角色名称
|
||||
*/
|
||||
@ExcelProperty(value = "角色名称")
|
||||
private String roleName;
|
||||
|
||||
/**
|
||||
* 角色权限字符串
|
||||
*/
|
||||
@ExcelProperty(value = "角色权限字符串")
|
||||
private String roleKey;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
@ExcelProperty(value = "显示顺序")
|
||||
private Integer roleSort;
|
||||
|
||||
/**
|
||||
* 角色状态(0正常 1停用)
|
||||
*/
|
||||
@ExcelProperty(value = "角色状态", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_normal_disable")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
package org.dromara.member.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.member.domain.AppSocialAuth;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端第三方登录授权视图对象 app_social_auth
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = AppSocialAuth.class)
|
||||
public class AppSocialAuthVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@ExcelProperty(value = "主键")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* App用户ID
|
||||
*/
|
||||
@ExcelProperty(value = "App用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户来源平台(wechat_mp:微信小程序 wechat_open:微信开放平台 qq:QQ weibo:微博)
|
||||
*/
|
||||
@ExcelProperty(value = "用户来源平台")
|
||||
private String platform;
|
||||
|
||||
/**
|
||||
* 表示平台唯一用户标识
|
||||
*/
|
||||
@ExcelProperty(value = "平台唯一用户标识")
|
||||
private String platformUid;
|
||||
|
||||
/**
|
||||
* 微信openid
|
||||
*/
|
||||
@ExcelProperty(value = "微信openid")
|
||||
private String openId;
|
||||
|
||||
/**
|
||||
* 微信unionid
|
||||
*/
|
||||
@ExcelProperty(value = "微信unionid")
|
||||
private String unionId;
|
||||
|
||||
/**
|
||||
* 用户的授权令牌
|
||||
*/
|
||||
@ExcelProperty(value = "授权令牌")
|
||||
private String accessToken;
|
||||
|
||||
/**
|
||||
* 用户的授权令牌的有效期
|
||||
*/
|
||||
@ExcelProperty(value = "令牌有效期")
|
||||
private Integer expireIn;
|
||||
|
||||
/**
|
||||
* 刷新令牌
|
||||
*/
|
||||
@ExcelProperty(value = "刷新令牌")
|
||||
private String refreshToken;
|
||||
|
||||
/**
|
||||
* 授予的权限
|
||||
*/
|
||||
@ExcelProperty(value = "授予权限")
|
||||
private String scope;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package org.dromara.member.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import org.dromara.member.domain.AppUserMessage;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端用户消息读取记录视图对象 app_user_message
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = AppUserMessage.class)
|
||||
public class AppUserMessageVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@ExcelProperty(value = "主键")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* App用户ID
|
||||
*/
|
||||
@ExcelProperty(value = "App用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 消息ID
|
||||
*/
|
||||
@ExcelProperty(value = "消息ID")
|
||||
private Long messageId;
|
||||
|
||||
/**
|
||||
* 是否已读(0未读 1已读)
|
||||
*/
|
||||
@ExcelProperty(value = "是否已读", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_yes_no")
|
||||
private String isRead;
|
||||
|
||||
/**
|
||||
* 读取时间
|
||||
*/
|
||||
@ExcelProperty(value = "读取时间")
|
||||
private LocalDateTime readTime;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package org.dromara.member.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.member.domain.AppUserRole;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端用户和角色关联视图对象 app_user_role
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = AppUserRole.class)
|
||||
public class AppUserRoleVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* App用户ID
|
||||
*/
|
||||
@ExcelProperty(value = "App用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* App角色ID
|
||||
*/
|
||||
@ExcelProperty(value = "App角色ID")
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@ExcelProperty(value = "创建者")
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@ExcelProperty(value = "更新者")
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@ExcelProperty(value = "更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package org.dromara.member.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import org.dromara.member.domain.AppUser;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App端用户信息视图对象 app_user
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = AppUser.class)
|
||||
public class AppUserVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* App用户ID
|
||||
*/
|
||||
@ExcelProperty(value = "App用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
@ExcelProperty(value = "用户账号")
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
@ExcelProperty(value = "密码")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
@ExcelProperty(value = "用户昵称")
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
@ExcelProperty(value = "手机号码")
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
@ExcelProperty(value = "用户邮箱")
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 用户性别(0男 1女 2未知)
|
||||
*/
|
||||
@ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_user_sex")
|
||||
private String sex;
|
||||
|
||||
/**
|
||||
* 头像地址
|
||||
*/
|
||||
@ExcelProperty(value = "头像地址")
|
||||
private Long avatar;
|
||||
|
||||
/**
|
||||
* 帐号状态(0正常 1停用)
|
||||
*/
|
||||
@ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_normal_disable")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 最后登录IP
|
||||
*/
|
||||
@ExcelProperty(value = "最后登录IP")
|
||||
private String loginIp;
|
||||
|
||||
/**
|
||||
* 最后登录时间
|
||||
*/
|
||||
@ExcelProperty(value = "最后登录时间")
|
||||
private LocalDateTime loginDate;
|
||||
|
||||
/**
|
||||
* 注册时间
|
||||
*/
|
||||
@ExcelProperty(value = "注册时间")
|
||||
private LocalDateTime registerTime;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package org.dromara.member.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import org.dromara.member.domain.AppVersion;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* App版本信息视图对象 app_version
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = AppVersion.class)
|
||||
public class AppVersionVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 版本ID
|
||||
*/
|
||||
@ExcelProperty(value = "版本ID")
|
||||
private Long versionId;
|
||||
|
||||
/**
|
||||
* 版本号(数字)
|
||||
*/
|
||||
@ExcelProperty(value = "版本号")
|
||||
private Integer versionCode;
|
||||
|
||||
/**
|
||||
* 版本名(如1.0.0)
|
||||
*/
|
||||
@ExcelProperty(value = "版本名")
|
||||
private String versionName;
|
||||
|
||||
/**
|
||||
* 更新内容
|
||||
*/
|
||||
@ExcelProperty(value = "更新内容")
|
||||
private String updateContent;
|
||||
|
||||
/**
|
||||
* 下载地址
|
||||
*/
|
||||
@ExcelProperty(value = "下载地址")
|
||||
private String downloadUrl;
|
||||
|
||||
/**
|
||||
* 是否强制更新(0否 1是)
|
||||
*/
|
||||
@ExcelProperty(value = "是否强制更新", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_yes_no")
|
||||
private String isForce;
|
||||
|
||||
/**
|
||||
* 平台(android、ios)
|
||||
*/
|
||||
@ExcelProperty(value = "平台")
|
||||
private String platform;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
package org.dromara.member.exception;
|
||||
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.NotPermissionException;
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* App模块专用异常处理器
|
||||
* 处理App端特有的业务异常和错误场景
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Slf4j
|
||||
@Order(1) // 优先级高于全局异常处理器
|
||||
@RestControllerAdvice(basePackages = "org.dromara.app")
|
||||
public class AppExceptionHandler {
|
||||
|
||||
/**
|
||||
* App端登录异常处理
|
||||
*/
|
||||
@ExceptionHandler(NotLoginException.class)
|
||||
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
||||
public R<Void> handleNotLoginException(NotLoginException e) {
|
||||
log.warn("App端用户未登录: {}", e.getMessage());
|
||||
return R.fail(401, "请先登录后再操作");
|
||||
}
|
||||
|
||||
/**
|
||||
* App端权限异常处理
|
||||
*/
|
||||
@ExceptionHandler(NotPermissionException.class)
|
||||
@ResponseStatus(HttpStatus.FORBIDDEN)
|
||||
public R<Void> handleNotPermissionException(NotPermissionException e) {
|
||||
log.warn("App端用户权限不足: {}", e.getMessage());
|
||||
return R.fail(403, "权限不足,无法访问该资源");
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传大小超限异常
|
||||
*/
|
||||
@ExceptionHandler(MaxUploadSizeExceededException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R<Void> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
|
||||
log.error("App端文件上传大小超限: {}", e.getMessage());
|
||||
return R.fail("上传文件大小超出限制,请选择较小的文件");
|
||||
}
|
||||
|
||||
/**
|
||||
* IO异常处理(主要用于文件操作)
|
||||
*/
|
||||
@ExceptionHandler(IOException.class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public R<Void> handleIOException(IOException e) {
|
||||
log.error("App端文件操作异常: {}", e.getMessage(), e);
|
||||
return R.fail("文件操作失败,请稍后重试");
|
||||
}
|
||||
|
||||
/**
|
||||
* App端业务异常处理
|
||||
*/
|
||||
@ExceptionHandler(ServiceException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R<Void> handleServiceException(ServiceException e) {
|
||||
log.error("App端业务异常: {}", e.getMessage());
|
||||
Integer code = e.getCode();
|
||||
if (code != null) {
|
||||
return R.fail(code, e.getMessage());
|
||||
}
|
||||
return R.fail(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数验证异常处理
|
||||
*/
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
|
||||
String message = e.getBindingResult().getFieldError().getDefaultMessage();
|
||||
log.warn("App端参数验证失败: {}", message);
|
||||
return R.fail("参数验证失败: " + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数绑定异常处理
|
||||
*/
|
||||
@ExceptionHandler(BindException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R<Void> handleBindException(BindException e) {
|
||||
String message = e.getBindingResult().getFieldError().getDefaultMessage();
|
||||
log.warn("App端参数绑定失败: {}", message);
|
||||
return R.fail("参数绑定失败: " + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 约束违反异常处理
|
||||
*/
|
||||
@ExceptionHandler(ConstraintViolationException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R<Void> handleConstraintViolationException(ConstraintViolationException e) {
|
||||
String message = e.getMessage();
|
||||
log.warn("App端约束验证失败: {}", message);
|
||||
return R.fail("参数验证失败: " + message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 文件相关异常处理
|
||||
*/
|
||||
@ExceptionHandler(FileException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R<Void> handleFileException(FileException e) {
|
||||
log.error("App端文件异常: {}", e.getMessage());
|
||||
return R.fail(e.getCode(), e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备相关异常处理
|
||||
*/
|
||||
@ExceptionHandler(DeviceException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R<Void> handleDeviceException(DeviceException e) {
|
||||
log.error("App端设备异常: {}", e.getMessage());
|
||||
return R.fail(e.getCode(), e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 版本相关异常处理
|
||||
*/
|
||||
@ExceptionHandler(VersionException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R<Void> handleVersionException(VersionException e) {
|
||||
log.error("App端版本异常: {}", e.getMessage());
|
||||
return R.fail(e.getCode(), e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用异常处理
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public R<Void> handleException(Exception e) {
|
||||
log.error("App端系统异常: ", e);
|
||||
return R.fail("系统异常,请联系管理员");
|
||||
}
|
||||
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package org.dromara.member.exception;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 设备相关异常
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class DeviceException extends RuntimeException {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private Integer code;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
public DeviceException(String message) {
|
||||
super(message);
|
||||
this.message = message;
|
||||
this.code = 400;
|
||||
}
|
||||
|
||||
public DeviceException(Integer code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public DeviceException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.message = message;
|
||||
this.code = 400;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备已绑定异常
|
||||
*/
|
||||
public static DeviceException deviceAlreadyBound(String deviceInfo) {
|
||||
return new DeviceException(4001, "设备已绑定: " + deviceInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备不存在异常
|
||||
*/
|
||||
public static DeviceException deviceNotFound(Long deviceId) {
|
||||
return new DeviceException(4002, "设备不存在: " + deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备绑定失败异常
|
||||
*/
|
||||
public static DeviceException bindFailed(String reason) {
|
||||
return new DeviceException(4003, "设备绑定失败: " + reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备解绑失败异常
|
||||
*/
|
||||
public static DeviceException unbindFailed(String reason) {
|
||||
return new DeviceException(4004, "设备解绑失败: " + reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备状态异常
|
||||
*/
|
||||
public static DeviceException invalidStatus(String status) {
|
||||
return new DeviceException(4005, "设备状态异常: " + status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送令牌无效异常
|
||||
*/
|
||||
public static DeviceException invalidPushToken(String token) {
|
||||
return new DeviceException(4006, "推送令牌无效: " + token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备数量超限异常
|
||||
*/
|
||||
public static DeviceException deviceLimitExceeded(int limit) {
|
||||
return new DeviceException(4007, "设备数量超出限制,最多允许绑定 " + limit + " 台设备");
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
package org.dromara.member.exception;
|
||||
|
||||
/**
|
||||
* 文件相关异常
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public class FileException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer code;
|
||||
|
||||
private String message;
|
||||
|
||||
private String detailMessage;
|
||||
|
||||
public FileException() {
|
||||
}
|
||||
|
||||
public FileException(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public FileException(String message, Integer code) {
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public FileException(String message, Throwable e) {
|
||||
super(message, e);
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public FileException(String message, Integer code, Throwable e) {
|
||||
super(message, e);
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public FileException(String message, Integer code, String detailMessage) {
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
this.detailMessage = detailMessage;
|
||||
}
|
||||
|
||||
public FileException(String message, Integer code, String detailMessage, Throwable e) {
|
||||
super(message, e);
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
this.detailMessage = detailMessage;
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(Integer code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getDetailMessage() {
|
||||
return detailMessage;
|
||||
}
|
||||
|
||||
public void setDetailMessage(String detailMessage) {
|
||||
this.detailMessage = detailMessage;
|
||||
}
|
||||
|
||||
// 静态工厂方法
|
||||
public static FileException fileEmpty() {
|
||||
return new FileException("上传文件不能为空", 40001);
|
||||
}
|
||||
|
||||
public static FileException fileSizeExceeded(long maxSize) {
|
||||
return new FileException("文件大小超过限制", 40002, "最大允许大小: " + maxSize + "MB");
|
||||
}
|
||||
|
||||
public static FileException unsupportedFileType(String fileType) {
|
||||
return new FileException("不支持的文件类型", 40003, "文件类型: " + fileType);
|
||||
}
|
||||
|
||||
public static FileException uploadFailed(String reason) {
|
||||
return new FileException("文件上传失败", 40004, reason);
|
||||
}
|
||||
|
||||
public static FileException fileNotFound(Long fileId) {
|
||||
return new FileException("文件不存在", 40005, "文件ID: " + fileId);
|
||||
}
|
||||
|
||||
public static FileException downloadFailed(String reason) {
|
||||
return new FileException("文件下载失败", 40006, reason);
|
||||
}
|
||||
|
||||
public static FileException deleteFailed(String reason) {
|
||||
return new FileException("文件删除失败", 40007, reason);
|
||||
}
|
||||
|
||||
public static FileException accessDenied(Long fileId) {
|
||||
return new FileException("无权限访问文件", 40008, "文件ID: " + fileId);
|
||||
}
|
||||
|
||||
public static FileException storageServiceError(String service) {
|
||||
return new FileException("存储服务异常", 40009, "服务: " + service);
|
||||
}
|
||||
|
||||
public static FileException md5CalculationFailed() {
|
||||
return new FileException("文件MD5计算失败", 40010);
|
||||
}
|
||||
|
||||
public static FileException invalidFileName(String fileName) {
|
||||
return new FileException("无效的文件名", 40011, "文件名: " + fileName);
|
||||
}
|
||||
|
||||
public static FileException fileAlreadyExists(String fileName) {
|
||||
return new FileException("文件已存在", 40012, "文件名: " + fileName);
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package org.dromara.member.exception;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 版本相关异常
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class VersionException extends RuntimeException {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private Integer code;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
public VersionException(String message) {
|
||||
super(message);
|
||||
this.message = message;
|
||||
this.code = 400;
|
||||
}
|
||||
|
||||
public VersionException(Integer code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public VersionException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.message = message;
|
||||
this.code = 400;
|
||||
}
|
||||
|
||||
/**
|
||||
* 版本不存在异常
|
||||
*/
|
||||
public static VersionException versionNotFound(String version) {
|
||||
return new VersionException(5001, "版本不存在: " + version);
|
||||
}
|
||||
|
||||
/**
|
||||
* 版本号重复异常
|
||||
*/
|
||||
public static VersionException versionCodeDuplicate(Integer versionCode) {
|
||||
return new VersionException(5002, "版本号已存在: " + versionCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 版本号无效异常
|
||||
*/
|
||||
public static VersionException invalidVersionCode(Integer versionCode) {
|
||||
return new VersionException(5003, "版本号无效: " + versionCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 平台不支持异常
|
||||
*/
|
||||
public static VersionException unsupportedPlatform(String platform) {
|
||||
return new VersionException(5004, "不支持的平台: " + platform);
|
||||
}
|
||||
|
||||
/**
|
||||
* 版本发布失败异常
|
||||
*/
|
||||
public static VersionException publishFailed(String reason) {
|
||||
return new VersionException(5005, "版本发布失败: " + reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* 版本撤回失败异常
|
||||
*/
|
||||
public static VersionException withdrawFailed(String reason) {
|
||||
return new VersionException(5006, "版本撤回失败: " + reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制更新版本冲突异常
|
||||
*/
|
||||
public static VersionException forceUpdateConflict(String version) {
|
||||
return new VersionException(5007, "强制更新版本冲突: " + version);
|
||||
}
|
||||
|
||||
/**
|
||||
* 版本比较异常
|
||||
*/
|
||||
public static VersionException versionCompareError(String currentVersion, String targetVersion) {
|
||||
return new VersionException(5008, "版本比较失败: " + currentVersion + " vs " + targetVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载链接无效异常
|
||||
*/
|
||||
public static VersionException invalidDownloadUrl(String url) {
|
||||
return new VersionException(5009, "下载链接无效: " + url);
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package org.dromara.member.mapper;
|
||||
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.member.domain.AppDevice;
|
||||
import org.dromara.member.domain.vo.AppDeviceVo;
|
||||
|
||||
/**
|
||||
* App端设备信息Mapper接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppDeviceMapper extends BaseMapperPlus<AppDevice, AppDeviceVo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.dromara.member.mapper;
|
||||
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.member.domain.AppFile;
|
||||
import org.dromara.member.domain.vo.AppFileVo;
|
||||
|
||||
/**
|
||||
* App端文件信息Mapper接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppFileMapper extends BaseMapperPlus<AppFile, AppFileVo> {
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package org.dromara.member.mapper;
|
||||
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.member.domain.AppLoginLog;
|
||||
import org.dromara.member.domain.vo.AppLoginLogVo;
|
||||
|
||||
/**
|
||||
* App端登录日志Mapper接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppLoginLogMapper extends BaseMapperPlus<AppLoginLog, AppLoginLogVo> {
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package org.dromara.member.mapper;
|
||||
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.member.domain.AppMessage;
|
||||
import org.dromara.member.domain.vo.AppMessageVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端消息推送Mapper接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppMessageMapper extends BaseMapperPlus<AppMessage, AppMessageVo> {
|
||||
|
||||
/**
|
||||
* 根据用户ID查询消息列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 消息列表
|
||||
*/
|
||||
List<AppMessageVo> selectMessagesByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 根据角色ID查询消息列表
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 消息列表
|
||||
*/
|
||||
List<AppMessageVo> selectMessagesByRoleId(Long roleId);
|
||||
|
||||
/**
|
||||
* 查询全部用户消息列表
|
||||
*
|
||||
* @return 消息列表
|
||||
*/
|
||||
List<AppMessageVo> selectMessagesForAll();
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package org.dromara.member.mapper;
|
||||
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.member.domain.AppOperLog;
|
||||
import org.dromara.member.domain.vo.AppOperLogVo;
|
||||
|
||||
/**
|
||||
* App端操作日志Mapper接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppOperLogMapper extends BaseMapperPlus<AppOperLog, AppOperLogVo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package org.dromara.member.mapper;
|
||||
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.member.domain.AppRole;
|
||||
import org.dromara.member.domain.vo.AppRoleVo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* App端角色信息Mapper接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppRoleMapper extends BaseMapperPlus<AppRole, AppRoleVo> {
|
||||
|
||||
/**
|
||||
* 根据用户ID查询角色
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色列表
|
||||
*/
|
||||
List<AppRoleVo> selectRolesByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 根据用户ID获取角色权限
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 权限列表
|
||||
*/
|
||||
Set<String> selectRolePermissionByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 查询所有角色
|
||||
*
|
||||
* @return 角色列表
|
||||
*/
|
||||
List<AppRoleVo> selectRoleAll();
|
||||
|
||||
/**
|
||||
* 根据用户ID获取角色选择框列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色ID列表
|
||||
*/
|
||||
List<Long> selectRoleListByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 校验角色名称是否唯一
|
||||
*
|
||||
* @param roleName 角色名称
|
||||
* @return 结果
|
||||
*/
|
||||
int checkRoleNameUnique(String roleName);
|
||||
|
||||
/**
|
||||
* 校验角色权限是否唯一
|
||||
*
|
||||
* @param roleKey 角色权限
|
||||
* @return 结果
|
||||
*/
|
||||
int checkRoleKeyUnique(String roleKey);
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package org.dromara.member.mapper;
|
||||
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.member.domain.AppSocialAuth;
|
||||
import org.dromara.member.domain.vo.AppSocialAuthVo;
|
||||
|
||||
/**
|
||||
* App端第三方登录授权Mapper接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppSocialAuthMapper extends BaseMapperPlus<AppSocialAuth, AppSocialAuthVo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package org.dromara.member.mapper;
|
||||
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.member.domain.AppUser;
|
||||
import org.dromara.member.domain.vo.AppUserVo;
|
||||
|
||||
/**
|
||||
* App端用户信息Mapper接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppUserMapper extends BaseMapperPlus<AppUser, AppUserVo> {
|
||||
|
||||
/**
|
||||
* 根据用户账号查询用户
|
||||
*
|
||||
* @param userName 用户账号
|
||||
* @return 用户信息
|
||||
*/
|
||||
AppUserVo selectUserByUserName(String userName);
|
||||
|
||||
/**
|
||||
* 根据手机号查询用户信息
|
||||
*
|
||||
* @param phone 手机号
|
||||
* @return 用户信息
|
||||
*/
|
||||
AppUserVo selectUserByPhone(String phone);
|
||||
|
||||
/**
|
||||
* 根据邮箱查询用户信息
|
||||
*
|
||||
* @param email 邮箱
|
||||
* @return 用户信息
|
||||
*/
|
||||
AppUserVo selectUserByEmail(String email);
|
||||
|
||||
/**
|
||||
* 校验用户账号是否唯一
|
||||
*
|
||||
* @param userName 用户账号
|
||||
* @return 结果
|
||||
*/
|
||||
int checkUserNameUnique(String userName);
|
||||
|
||||
/**
|
||||
* 校验手机号码是否唯一
|
||||
*
|
||||
* @param phone 手机号码
|
||||
* @return 结果
|
||||
*/
|
||||
int checkPhoneUnique(String phone);
|
||||
|
||||
/**
|
||||
* 校验email是否唯一
|
||||
*
|
||||
* @param email 用户邮箱
|
||||
* @return 结果
|
||||
*/
|
||||
int checkEmailUnique(String email);
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package org.dromara.member.mapper;
|
||||
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.member.domain.AppUserMessage;
|
||||
import org.dromara.member.domain.vo.AppUserMessageVo;
|
||||
|
||||
/**
|
||||
* App端用户消息读取记录Mapper接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppUserMessageMapper extends BaseMapperPlus<AppUserMessage, AppUserMessageVo> {
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package org.dromara.member.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.member.domain.AppUserRole;
|
||||
import org.dromara.member.domain.vo.AppUserRoleVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端用户和角色关联Mapper接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Mapper
|
||||
public interface AppUserRoleMapper extends BaseMapperPlus<AppUserRole, AppUserRoleVo> {
|
||||
|
||||
/**
|
||||
* 通过用户ID删除用户和角色关联
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteUserRoleByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 批量删除用户和角色关联
|
||||
*
|
||||
* @param ids 需要删除的数据ID
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteUserRole(Long[] ids);
|
||||
|
||||
/**
|
||||
* 通过角色ID查询角色使用数量
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 结果
|
||||
*/
|
||||
int countUserRoleByRoleId(Long roleId);
|
||||
|
||||
/**
|
||||
* 批量新增用户角色信息
|
||||
*
|
||||
* @param userRoleList 用户角色列表
|
||||
* @return 结果
|
||||
*/
|
||||
int batchUserRole(@Param("list") List<AppUserRole> userRoleList);
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package org.dromara.member.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.member.domain.AppVersion;
|
||||
import org.dromara.member.domain.vo.AppVersionVo;
|
||||
|
||||
/**
|
||||
* App版本信息Mapper接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Mapper
|
||||
public interface AppVersionMapper extends BaseMapperPlus<AppVersion, AppVersionVo> {
|
||||
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
package org.dromara.member.service;
|
||||
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.member.domain.bo.AppDeviceBo;
|
||||
import org.dromara.member.domain.vo.AppDeviceVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端设备信息Service接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppDeviceService {
|
||||
|
||||
/**
|
||||
* 查询App端设备信息
|
||||
*/
|
||||
AppDeviceVo queryById(Long deviceId);
|
||||
|
||||
/**
|
||||
* 查询App端设备信息列表
|
||||
*/
|
||||
TableDataInfo<AppDeviceVo> queryPageList(AppDeviceBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询App端设备信息列表
|
||||
*/
|
||||
List<AppDeviceVo> queryList(AppDeviceBo bo);
|
||||
|
||||
/**
|
||||
* 新增App端设备信息
|
||||
*/
|
||||
Boolean insertByBo(AppDeviceBo bo);
|
||||
|
||||
/**
|
||||
* 修改App端设备信息
|
||||
*/
|
||||
Boolean updateByBo(AppDeviceBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除App端设备信息
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 根据用户ID查询设备列表
|
||||
*/
|
||||
List<AppDeviceVo> queryByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 绑定设备
|
||||
*/
|
||||
Boolean bindDevice(AppDeviceBo bo);
|
||||
|
||||
/**
|
||||
* 解绑设备
|
||||
*/
|
||||
Boolean unbindDevice(Long deviceId, Long userId);
|
||||
|
||||
/**
|
||||
* 更新设备活跃状态
|
||||
*/
|
||||
Boolean updateActiveStatus(Long deviceId, String isActive);
|
||||
|
||||
/**
|
||||
* 更新推送令牌
|
||||
*/
|
||||
Boolean updatePushToken(Long deviceId, String pushToken);
|
||||
|
||||
/**
|
||||
* 获取用户活跃设备
|
||||
*/
|
||||
List<AppDeviceVo> getActiveDevices(Long userId);
|
||||
|
||||
/**
|
||||
* 清理非活跃设备
|
||||
*/
|
||||
Integer cleanInactiveDevices(Integer days);
|
||||
|
||||
/**
|
||||
* 根据推送令牌查询设备
|
||||
*/
|
||||
AppDeviceVo queryByPushToken(String pushToken);
|
||||
|
||||
/**
|
||||
* 设备心跳更新
|
||||
*/
|
||||
Boolean heartbeat(Long deviceId);
|
||||
|
||||
/**
|
||||
* 批量更新设备状态
|
||||
*/
|
||||
Boolean batchUpdateStatus(List<Long> deviceIds, String isActive);
|
||||
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
package org.dromara.member.service;
|
||||
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.member.domain.bo.AppFileBo;
|
||||
import org.dromara.member.domain.vo.AppFileVo;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端文件信息Service接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppFileService {
|
||||
|
||||
/**
|
||||
* 查询App端文件信息
|
||||
*/
|
||||
AppFileVo queryById(Long fileId);
|
||||
|
||||
/**
|
||||
* 查询App端文件信息列表
|
||||
*/
|
||||
TableDataInfo<AppFileVo> queryPageList(AppFileBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询App端文件信息列表
|
||||
*/
|
||||
List<AppFileVo> queryList(AppFileBo bo);
|
||||
|
||||
/**
|
||||
* 新增App端文件信息
|
||||
*/
|
||||
Boolean insertByBo(AppFileBo bo);
|
||||
|
||||
/**
|
||||
* 修改App端文件信息
|
||||
*/
|
||||
Boolean updateByBo(AppFileBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除App端文件信息
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @param file 上传的文件
|
||||
* @param userId 用户ID
|
||||
* @param fileCategory 文件分类
|
||||
* @return 文件信息
|
||||
*/
|
||||
AppFileVo uploadFile(MultipartFile file, Long userId, Integer fileCategory);
|
||||
|
||||
/**
|
||||
* 上传头像
|
||||
*
|
||||
* @param file 头像文件
|
||||
* @param userId 用户ID
|
||||
* @return 文件信息
|
||||
*/
|
||||
AppFileVo uploadAvatar(MultipartFile file, Long userId);
|
||||
|
||||
/**
|
||||
* 批量上传文件
|
||||
*
|
||||
* @param files 文件数组
|
||||
* @param userId 用户ID
|
||||
* @param fileCategory 文件分类
|
||||
* @return 文件信息列表
|
||||
*/
|
||||
List<AppFileVo> batchUploadFiles(MultipartFile[] files, Long userId, Integer fileCategory);
|
||||
|
||||
/**
|
||||
* 根据用户ID查询文件列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param fileCategory 文件分类(可选)
|
||||
* @return 文件列表
|
||||
*/
|
||||
List<AppFileVo> queryByUserId(Long userId, Integer fileCategory);
|
||||
|
||||
/**
|
||||
* 根据文件分类查询文件列表
|
||||
*
|
||||
* @param fileCategory 文件分类
|
||||
* @return 文件列表
|
||||
*/
|
||||
List<AppFileVo> queryByCategory(Integer fileCategory);
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*
|
||||
* @param fileId 文件ID
|
||||
* @param userId 用户ID
|
||||
* @return 文件信息
|
||||
*/
|
||||
AppFileVo downloadFile(Long fileId, Long userId);
|
||||
|
||||
/**
|
||||
* 删除用户文件
|
||||
*
|
||||
* @param fileId 文件ID
|
||||
* @param userId 用户ID
|
||||
* @return 删除结果
|
||||
*/
|
||||
Boolean deleteUserFile(Long fileId, Long userId);
|
||||
|
||||
/**
|
||||
* 批量删除用户文件
|
||||
*
|
||||
* @param fileIds 文件ID列表
|
||||
* @param userId 用户ID
|
||||
* @return 删除结果
|
||||
*/
|
||||
Boolean batchDeleteUserFiles(Collection<Long> fileIds, Long userId);
|
||||
|
||||
/**
|
||||
* 更新文件状态
|
||||
*
|
||||
* @param fileId 文件ID
|
||||
* @param status 状态
|
||||
* @param userId 用户ID
|
||||
* @return 更新结果
|
||||
*/
|
||||
Boolean updateFileStatus(Long fileId, String status, Long userId);
|
||||
|
||||
/**
|
||||
* 获取用户文件统计信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 统计信息
|
||||
*/
|
||||
AppFileVo getUserFileStatistics(Long userId);
|
||||
|
||||
/**
|
||||
* 清理过期文件
|
||||
*
|
||||
* @param days 过期天数
|
||||
* @return 清理数量
|
||||
*/
|
||||
Integer cleanExpiredFiles(Integer days);
|
||||
|
||||
/**
|
||||
* 检查文件是否存在
|
||||
*
|
||||
* @param fileMd5 文件MD5
|
||||
* @param userId 用户ID
|
||||
* @return 文件信息
|
||||
*/
|
||||
AppFileVo checkFileExists(String fileMd5, Long userId);
|
||||
|
||||
/**
|
||||
* 更新文件公开状态
|
||||
*
|
||||
* @param fileId 文件ID
|
||||
* @param isPublic 是否公开
|
||||
* @param userId 用户ID
|
||||
* @return 更新结果
|
||||
*/
|
||||
Boolean updateFilePublicStatus(Long fileId, String isPublic, Long userId);
|
||||
|
||||
}
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
package org.dromara.member.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.member.domain.AppMessage;
|
||||
import org.dromara.member.domain.bo.AppMessageBo;
|
||||
import org.dromara.member.domain.vo.AppMessageVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端消息Service接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppMessageService extends IService<AppMessage> {
|
||||
|
||||
/**
|
||||
* 查询App端消息
|
||||
*
|
||||
* @param messageId 消息ID
|
||||
* @return App端消息
|
||||
*/
|
||||
AppMessageVo queryById(Long messageId);
|
||||
|
||||
/**
|
||||
* 查询App端消息列表
|
||||
*
|
||||
* @param bo App端消息
|
||||
* @param pageQuery 分页查询条件
|
||||
* @return App端消息集合
|
||||
*/
|
||||
TableDataInfo<AppMessageVo> queryPageList(AppMessageBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询App端消息列表
|
||||
*
|
||||
* @param bo App端消息
|
||||
* @return App端消息集合
|
||||
*/
|
||||
List<AppMessageVo> queryList(AppMessageBo bo);
|
||||
|
||||
/**
|
||||
* 新增App端消息
|
||||
*
|
||||
* @param bo App端消息
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean insertByBo(AppMessageBo bo);
|
||||
|
||||
/**
|
||||
* 修改App端消息
|
||||
*
|
||||
* @param bo App端消息
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean updateByBo(AppMessageBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除App端消息
|
||||
*
|
||||
* @param ids 主键集合
|
||||
* @param isValid 是否校验,true-删除前校验,false-不校验
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 获取用户未读消息数量
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 未读消息数量
|
||||
*/
|
||||
Long getUnreadCount(Long userId);
|
||||
|
||||
/**
|
||||
* 标记消息为已读
|
||||
*
|
||||
* @param messageId 消息ID
|
||||
* @param userId 用户ID
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean markAsRead(Long messageId, Long userId);
|
||||
|
||||
/**
|
||||
* 批量标记消息为已读
|
||||
*
|
||||
* @param messageIds 消息ID列表
|
||||
* @param userId 用户ID
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean markAsReadBatch(List<Long> messageIds, Long userId);
|
||||
|
||||
/**
|
||||
* 标记所有消息为已读
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean markAllAsRead(Long userId);
|
||||
|
||||
/**
|
||||
* 发送系统消息
|
||||
*
|
||||
* @param bo 消息信息
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean sendSystemMessage(AppMessageBo bo);
|
||||
|
||||
/**
|
||||
* 发送个人消息
|
||||
*
|
||||
* @param bo 消息信息
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean sendPersonalMessage(AppMessageBo bo);
|
||||
|
||||
/**
|
||||
* 推送消息到指定用户
|
||||
*
|
||||
* @param bo 消息信息
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean pushMessage(AppMessageBo bo);
|
||||
|
||||
/**
|
||||
* 群发消息
|
||||
*
|
||||
* @param bo 消息信息
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean broadcastMessage(AppMessageBo bo);
|
||||
|
||||
/**
|
||||
* 发送推送通知
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param title 标题
|
||||
* @param content 内容
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean sendPushNotification(Long userId, String title, String content);
|
||||
|
||||
/**
|
||||
* 批量发送推送通知
|
||||
*
|
||||
* @param userIds 用户ID列表
|
||||
* @param title 标题
|
||||
* @param content 内容
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean sendBatchPushNotification(List<Long> userIds, String title, String content);
|
||||
|
||||
/**
|
||||
* 清理过期消息
|
||||
*
|
||||
* @return 清理数量
|
||||
*/
|
||||
Integer cleanExpiredMessages();
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
package org.dromara.member.service;
|
||||
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.member.domain.bo.AppOperLogBo;
|
||||
import org.dromara.member.domain.vo.AppOperLogVo;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端操作日志Service接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppOperLogService {
|
||||
|
||||
/**
|
||||
* 查询App端操作日志
|
||||
*/
|
||||
AppOperLogVo queryById(Long operId);
|
||||
|
||||
/**
|
||||
* 查询App端操作日志列表
|
||||
*/
|
||||
TableDataInfo<AppOperLogVo> queryPageList(AppOperLogBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询App端操作日志列表
|
||||
*/
|
||||
List<AppOperLogVo> queryList(AppOperLogBo bo);
|
||||
|
||||
/**
|
||||
* 新增App端操作日志
|
||||
*/
|
||||
Boolean insertByBo(AppOperLogBo bo);
|
||||
|
||||
/**
|
||||
* 修改App端操作日志
|
||||
*/
|
||||
Boolean updateByBo(AppOperLogBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除App端操作日志信息
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 记录操作日志
|
||||
*
|
||||
* @param title 模块标题
|
||||
* @param businessType 业务类型
|
||||
* @param method 方法名称
|
||||
* @param requestMethod 请求方式
|
||||
* @param operName 操作人员
|
||||
* @param operUrl 请求URL
|
||||
* @param operIp 主机地址
|
||||
* @param operLocation 操作地点
|
||||
* @param operParam 请求参数
|
||||
* @param jsonResult 返回参数
|
||||
* @param status 操作状态
|
||||
* @param errorMsg 错误消息
|
||||
* @param costTime 消耗时间
|
||||
*/
|
||||
void recordOperLog(String title, Integer businessType, String method, String requestMethod,
|
||||
String operName, String operUrl, String operIp, String operLocation,
|
||||
String operParam, String jsonResult, Integer status, String errorMsg, Long costTime);
|
||||
|
||||
/**
|
||||
* 根据操作人查询操作日志
|
||||
*
|
||||
* @param operName 操作人员
|
||||
* @return 操作日志列表
|
||||
*/
|
||||
List<AppOperLogVo> queryByOperName(String operName);
|
||||
|
||||
/**
|
||||
* 清空操作日志
|
||||
*/
|
||||
void cleanOperLog();
|
||||
|
||||
/**
|
||||
* 根据时间范围删除操作日志
|
||||
*
|
||||
* @param beginTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
*/
|
||||
void deleteOperLogByTime(LocalDateTime beginTime, LocalDateTime endTime);
|
||||
|
||||
/**
|
||||
* 获取操作统计信息
|
||||
*
|
||||
* @param operName 操作人员
|
||||
* @param beginTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return 统计信息
|
||||
*/
|
||||
Long getOperLogCount(String operName, LocalDateTime beginTime, LocalDateTime endTime);
|
||||
|
||||
/**
|
||||
* 获取用户行为分析数据
|
||||
*
|
||||
* @param operName 操作人员
|
||||
* @param days 统计天数
|
||||
* @return 行为分析数据
|
||||
*/
|
||||
List<AppOperLogVo> getUserBehaviorAnalysis(String operName, Integer days);
|
||||
|
||||
/**
|
||||
* 获取热门操作统计
|
||||
*
|
||||
* @param days 统计天数
|
||||
* @param limit 返回数量限制
|
||||
* @return 热门操作列表
|
||||
*/
|
||||
List<AppOperLogVo> getPopularOperations(Integer days, Integer limit);
|
||||
|
||||
/**
|
||||
* 获取错误操作统计
|
||||
*
|
||||
* @param days 统计天数
|
||||
* @return 错误操作列表
|
||||
*/
|
||||
List<AppOperLogVo> getErrorOperations(Integer days);
|
||||
|
||||
/**
|
||||
* 批量记录操作日志
|
||||
*
|
||||
* @param operLogs 操作日志列表
|
||||
*/
|
||||
void batchInsertOperLog(List<AppOperLogBo> operLogs);
|
||||
|
||||
/**
|
||||
* 异步记录操作日志
|
||||
*
|
||||
* @param bo 操作日志业务对象
|
||||
*/
|
||||
void asyncRecordOperLog(AppOperLogBo bo);
|
||||
|
||||
}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
package org.dromara.member.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.member.domain.AppRole;
|
||||
import org.dromara.member.domain.bo.AppRoleBo;
|
||||
import org.dromara.member.domain.vo.AppRoleVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* App端角色信息Service接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppRoleService extends IService<AppRole> {
|
||||
|
||||
/**
|
||||
* 查询App端角色信息
|
||||
*
|
||||
* @param roleId App角色ID
|
||||
* @return App端角色信息
|
||||
*/
|
||||
AppRoleVo queryById(Long roleId);
|
||||
|
||||
/**
|
||||
* 查询App端角色信息列表
|
||||
*
|
||||
* @param bo App端角色信息
|
||||
* @param pageQuery 分页查询条件
|
||||
* @return App端角色信息集合
|
||||
*/
|
||||
TableDataInfo<AppRoleVo> queryPageList(AppRoleBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询App端角色信息列表
|
||||
*
|
||||
* @param bo App端角色信息
|
||||
* @return App端角色信息集合
|
||||
*/
|
||||
List<AppRoleVo> queryList(AppRoleBo bo);
|
||||
|
||||
/**
|
||||
* 新增App端角色信息
|
||||
*
|
||||
* @param bo App端角色信息
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean insertByBo(AppRoleBo bo);
|
||||
|
||||
/**
|
||||
* 修改App端角色信息
|
||||
*
|
||||
* @param bo App端角色信息
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean updateByBo(AppRoleBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除App端角色信息
|
||||
*
|
||||
* @param ids 主键集合
|
||||
* @param isValid 是否校验,true-删除前校验,false-不校验
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 根据用户ID查询角色
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色列表
|
||||
*/
|
||||
List<AppRoleVo> selectRolesByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 根据用户ID获取角色权限
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 权限列表
|
||||
*/
|
||||
Set<String> selectRolePermissionByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 查询所有角色
|
||||
*
|
||||
* @return 角色列表
|
||||
*/
|
||||
List<AppRoleVo> selectRoleAll();
|
||||
|
||||
/**
|
||||
* 根据用户ID获取角色选择框列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 选中角色ID列表
|
||||
*/
|
||||
List<Long> selectRoleListByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 校验角色名称是否唯一
|
||||
*
|
||||
* @param roleName 角色名称
|
||||
* @return 结果
|
||||
*/
|
||||
boolean checkRoleNameUnique(String roleName);
|
||||
|
||||
/**
|
||||
* 校验角色权限是否唯一
|
||||
*
|
||||
* @param roleKey 角色权限
|
||||
* @return 结果
|
||||
*/
|
||||
boolean checkRoleKeyUnique(String roleKey);
|
||||
|
||||
/**
|
||||
* 校验角色是否允许操作
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 结果
|
||||
*/
|
||||
boolean checkRoleAllowed(Long roleId);
|
||||
|
||||
/**
|
||||
* 校验角色是否有数据权限
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 结果
|
||||
*/
|
||||
boolean checkRoleDataScope(Long roleId);
|
||||
|
||||
/**
|
||||
* 通过角色ID查询角色使用数量
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 结果
|
||||
*/
|
||||
long countUserRoleByRoleId(Long roleId);
|
||||
|
||||
/**
|
||||
* 取消授权用户角色
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param roleId 角色ID
|
||||
* @return 结果
|
||||
*/
|
||||
boolean deleteAuthUser(Long userId, Long roleId);
|
||||
|
||||
/**
|
||||
* 批量取消授权用户角色
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @param userIds 需要取消授权的用户数据ID
|
||||
* @return 结果
|
||||
*/
|
||||
boolean deleteAuthUsers(Long roleId, Long[] userIds);
|
||||
|
||||
/**
|
||||
* 批量选择授权用户角色
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @param userIds 需要授权的用户数据ID
|
||||
* @return 结果
|
||||
*/
|
||||
boolean insertAuthUsers(Long roleId, Long[] userIds);
|
||||
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
package org.dromara.member.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import org.dromara.member.domain.AppSocialAuth;
|
||||
import org.dromara.member.domain.vo.AppSocialAuthVo;
|
||||
import org.dromara.member.domain.vo.AppUserVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端第三方登录授权Service接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppSocialAuthService extends IService<AppSocialAuth> {
|
||||
|
||||
/**
|
||||
* 查询App端第三方登录授权
|
||||
*
|
||||
* @param id 主键
|
||||
* @return App端第三方登录授权
|
||||
*/
|
||||
AppSocialAuthVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 根据用户ID查询社交认证列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 社交认证列表
|
||||
*/
|
||||
List<AppSocialAuthVo> queryByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 根据平台和openId查询社交认证
|
||||
*
|
||||
* @param platform 平台
|
||||
* @param openId openId
|
||||
* @return 社交认证信息
|
||||
*/
|
||||
AppSocialAuth queryByPlatformAndOpenId(String platform, String openId);
|
||||
|
||||
/**
|
||||
* 根据平台和unionId查询社交认证
|
||||
*
|
||||
* @param platform 平台
|
||||
* @param unionId unionId
|
||||
* @return 社交认证信息
|
||||
*/
|
||||
AppSocialAuth queryByPlatformAndUnionId(String platform, String unionId);
|
||||
|
||||
/**
|
||||
* 新增App端第三方登录授权
|
||||
*
|
||||
* @param appSocialAuth App端第三方登录授权
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean insertAppSocialAuth(AppSocialAuth appSocialAuth);
|
||||
|
||||
/**
|
||||
* 修改App端第三方登录授权
|
||||
*
|
||||
* @param appSocialAuth App端第三方登录授权
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean updateAppSocialAuth(AppSocialAuth appSocialAuth);
|
||||
|
||||
/**
|
||||
* 删除App端第三方登录授权
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean deleteAppSocialAuthById(Long id);
|
||||
|
||||
/**
|
||||
* 根据用户ID删除社交认证
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean deleteByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 更新访问令牌
|
||||
*
|
||||
* @param id 主键
|
||||
* @param accessToken 访问令牌
|
||||
* @param expireIn 过期时间
|
||||
* @param refreshToken 刷新令牌
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean updateAccessToken(Long id, String accessToken, Integer expireIn, String refreshToken);
|
||||
|
||||
/**
|
||||
* 根据用户ID和平台删除绑定关系
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param platform 第三方平台
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean deleteByUserIdAndPlatform(Long userId, String platform);
|
||||
|
||||
/**
|
||||
* 根据平台和openId查询绑定的用户信息
|
||||
*
|
||||
* @param platform 平台
|
||||
* @param openId openId
|
||||
* @return 用户信息
|
||||
*/
|
||||
AppUserVo selectUserByPlatformAndOpenId(String platform, String openId);
|
||||
|
||||
/**
|
||||
* 根据平台和unionId查询绑定的用户信息
|
||||
*
|
||||
* @param platform 平台
|
||||
* @param unionId unionId
|
||||
* @return 用户信息
|
||||
*/
|
||||
AppUserVo selectUserByPlatformAndUnionId(String platform, String unionId);
|
||||
|
||||
/**
|
||||
* 绑定第三方用户
|
||||
*
|
||||
* @param authUserData 授权响应实体
|
||||
*/
|
||||
void socialRegister(AuthUser authUserData);
|
||||
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
package org.dromara.member.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.member.domain.AppUser;
|
||||
import org.dromara.member.domain.bo.AppUserBo;
|
||||
import org.dromara.member.domain.vo.AppUserVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端用户信息Service接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppUserService extends IService<AppUser> {
|
||||
|
||||
/**
|
||||
* 查询App端用户信息
|
||||
*
|
||||
* @param userId App用户ID
|
||||
* @return App端用户信息
|
||||
*/
|
||||
AppUserVo queryById(Long userId);
|
||||
|
||||
/**
|
||||
* 查询App端用户信息列表
|
||||
*
|
||||
* @param bo App端用户信息
|
||||
* @param pageQuery 分页查询条件
|
||||
* @return App端用户信息集合
|
||||
*/
|
||||
TableDataInfo<AppUserVo> queryPageList(AppUserBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询App端用户信息列表
|
||||
*
|
||||
* @param bo App端用户信息
|
||||
* @return App端用户信息集合
|
||||
*/
|
||||
List<AppUserVo> queryList(AppUserBo bo);
|
||||
|
||||
/**
|
||||
* 新增App端用户信息
|
||||
*
|
||||
* @param bo App端用户信息
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean insertByBo(AppUserBo bo);
|
||||
|
||||
/**
|
||||
* 修改App端用户信息
|
||||
*
|
||||
* @param bo App端用户信息
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean updateByBo(AppUserBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除App端用户信息
|
||||
*
|
||||
* @param ids 主键集合
|
||||
* @param isValid 是否校验,true-删除前校验,false-不校验
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 根据用户账号查询用户
|
||||
*
|
||||
* @param userName 用户账号
|
||||
* @return 用户信息
|
||||
*/
|
||||
AppUserVo selectUserByUserName(String userName);
|
||||
|
||||
/**
|
||||
* 根据手机号查询用户信息
|
||||
*
|
||||
* @param phone 手机号
|
||||
* @return 用户信息
|
||||
*/
|
||||
AppUserVo selectUserByPhone(String phone);
|
||||
|
||||
/**
|
||||
* 根据邮箱查询用户信息
|
||||
*
|
||||
* @param email 邮箱
|
||||
* @return 用户信息
|
||||
*/
|
||||
AppUserVo selectUserByEmail(String email);
|
||||
|
||||
/**
|
||||
* 校验用户账号是否唯一
|
||||
*
|
||||
* @param userName 用户账号
|
||||
* @return 结果
|
||||
*/
|
||||
boolean checkUserNameUnique(String userName);
|
||||
|
||||
/**
|
||||
* 校验手机号码是否唯一
|
||||
*
|
||||
* @param phone 手机号码
|
||||
* @return 结果
|
||||
*/
|
||||
boolean checkPhoneUnique(String phone);
|
||||
|
||||
/**
|
||||
* 校验email是否唯一
|
||||
*
|
||||
* @param email 用户邮箱
|
||||
* @return 结果
|
||||
*/
|
||||
boolean checkEmailUnique(String email);
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
*
|
||||
* @param bo 用户信息
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean register(AppUserBo bo);
|
||||
|
||||
/**
|
||||
* 修改用户密码
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param oldPassword 旧密码
|
||||
* @param newPassword 新密码
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean updatePassword(Long userId, String oldPassword, String newPassword);
|
||||
|
||||
/**
|
||||
* 重置用户密码
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param newPassword 新密码
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean resetPassword(Long userId, String newPassword);
|
||||
|
||||
/**
|
||||
* 修改用户状态
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param status 状态
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean updateUserStatus(Long userId, String status);
|
||||
|
||||
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package org.dromara.member.service;
|
||||
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.member.domain.bo.AppVersionBo;
|
||||
import org.dromara.member.domain.vo.AppVersionVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App版本信息Service接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface AppVersionService {
|
||||
|
||||
/**
|
||||
* 查询App版本信息
|
||||
*/
|
||||
AppVersionVo queryById(Long versionId);
|
||||
|
||||
/**
|
||||
* 查询App版本信息列表
|
||||
*/
|
||||
TableDataInfo<AppVersionVo> queryPageList(AppVersionBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询App版本信息列表
|
||||
*/
|
||||
List<AppVersionVo> queryList(AppVersionBo bo);
|
||||
|
||||
/**
|
||||
* 新增App版本信息
|
||||
*/
|
||||
Boolean insertByBo(AppVersionBo bo);
|
||||
|
||||
/**
|
||||
* 修改App版本信息
|
||||
*/
|
||||
Boolean updateByBo(AppVersionBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除App版本信息
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 检查版本更新
|
||||
*/
|
||||
AppVersionVo checkUpdate(String platform, Integer currentVersionCode);
|
||||
|
||||
/**
|
||||
* 获取指定平台的最新版本
|
||||
*/
|
||||
AppVersionVo getLatestVersion(String platform);
|
||||
|
||||
/**
|
||||
* 检查版本号是否唯一
|
||||
*/
|
||||
Boolean checkVersionCodeUnique(AppVersionBo bo);
|
||||
|
||||
/**
|
||||
* 获取版本历史列表
|
||||
*/
|
||||
List<AppVersionVo> getVersionHistory(String platform, Integer limit);
|
||||
|
||||
/**
|
||||
* 检查是否需要强制更新
|
||||
*/
|
||||
Boolean checkForceUpdate(String platform, Integer currentVersionCode);
|
||||
|
||||
/**
|
||||
* 获取版本更新信息
|
||||
*/
|
||||
AppVersionVo getUpdateInfo(String platform, Integer currentVersionCode);
|
||||
|
||||
/**
|
||||
* 批量发布版本
|
||||
*/
|
||||
Boolean batchPublish(List<Long> versionIds);
|
||||
|
||||
/**
|
||||
* 撤回版本
|
||||
*/
|
||||
Boolean withdrawVersion(Long versionId);
|
||||
|
||||
}
|
||||
+333
@@ -0,0 +1,333 @@
|
||||
package org.dromara.member.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.member.domain.AppDevice;
|
||||
import org.dromara.member.domain.bo.AppDeviceBo;
|
||||
import org.dromara.member.domain.vo.AppDeviceVo;
|
||||
import org.dromara.member.exception.DeviceException;
|
||||
import org.dromara.member.mapper.AppDeviceMapper;
|
||||
import org.dromara.member.service.AppDeviceService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端设备信息Service业务层处理
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class AppDeviceServiceImpl extends ServiceImpl<AppDeviceMapper, AppDevice> implements AppDeviceService {
|
||||
|
||||
private final AppDeviceMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询App端设备信息
|
||||
*/
|
||||
@Override
|
||||
public AppDeviceVo queryById(Long deviceId) {
|
||||
return baseMapper.selectVoById(deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询App端设备信息列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<AppDeviceVo> queryPageList(AppDeviceBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<AppDevice> lqw = buildQueryWrapper(bo);
|
||||
Page<AppDeviceVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询App端设备信息列表
|
||||
*/
|
||||
@Override
|
||||
public List<AppDeviceVo> queryList(AppDeviceBo bo) {
|
||||
LambdaQueryWrapper<AppDevice> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<AppDevice> buildQueryWrapper(AppDeviceBo bo) {
|
||||
LambdaQueryWrapper<AppDevice> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getUserId() != null, AppDevice::getUserId, bo.getUserId());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDeviceType()), AppDevice::getDeviceType, bo.getDeviceType());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getDeviceName()), AppDevice::getDeviceName, bo.getDeviceName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getDeviceModel()), AppDevice::getDeviceModel, bo.getDeviceModel());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDeviceBrand()), AppDevice::getDeviceBrand, bo.getDeviceBrand());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getOsVersion()), AppDevice::getOsVersion, bo.getOsVersion());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getAppVersion()), AppDevice::getAppVersion, bo.getAppVersion());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getIsActive()), AppDevice::getIsActive, bo.getIsActive());
|
||||
lqw.orderByDesc(AppDevice::getLastActiveTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增App端设备信息
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(AppDeviceBo bo) {
|
||||
AppDevice add = BeanUtil.toBean(bo, AppDevice.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setDeviceId(add.getDeviceId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改App端设备信息
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(AppDeviceBo bo) {
|
||||
AppDevice update = BeanUtil.toBean(bo, AppDevice.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(AppDevice entity) {
|
||||
// TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除App端设备信息
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询设备列表
|
||||
*/
|
||||
@Override
|
||||
public List<AppDeviceVo> queryByUserId(Long userId) {
|
||||
LambdaQueryWrapper<AppDevice> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppDevice::getUserId, userId);
|
||||
lqw.orderByDesc(AppDevice::getLastActiveTime);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定设备
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean bindDevice(AppDeviceBo bo) {
|
||||
// 检查用户设备数量限制
|
||||
LambdaQueryWrapper<AppDevice> countLqw = Wrappers.lambdaQuery();
|
||||
countLqw.eq(AppDevice::getUserId, bo.getUserId());
|
||||
countLqw.eq(AppDevice::getIsActive, "1");
|
||||
long deviceCount = baseMapper.selectCount(countLqw);
|
||||
if (deviceCount >= 10) { // 限制每个用户最多绑定10台设备
|
||||
throw DeviceException.deviceLimitExceeded(10);
|
||||
}
|
||||
|
||||
// 检查是否已存在相同设备
|
||||
LambdaQueryWrapper<AppDevice> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppDevice::getUserId, bo.getUserId());
|
||||
lqw.eq(AppDevice::getDeviceType, bo.getDeviceType());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getPushToken()), AppDevice::getPushToken, bo.getPushToken());
|
||||
|
||||
AppDevice existDevice = baseMapper.selectOne(lqw);
|
||||
if (existDevice != null) {
|
||||
// 更新现有设备信息
|
||||
existDevice.setDeviceName(bo.getDeviceName());
|
||||
existDevice.setDeviceModel(bo.getDeviceModel());
|
||||
existDevice.setDeviceBrand(bo.getDeviceBrand());
|
||||
existDevice.setOsVersion(bo.getOsVersion());
|
||||
existDevice.setAppVersion(bo.getAppVersion());
|
||||
existDevice.setIsActive("1");
|
||||
existDevice.setLastActiveTime(LocalDateTime.now());
|
||||
boolean result = baseMapper.updateById(existDevice) > 0;
|
||||
if (!result) {
|
||||
throw DeviceException.bindFailed("设备信息更新失败");
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
// 新增设备
|
||||
bo.setIsActive("1");
|
||||
bo.setLastActiveTime(LocalDateTime.now());
|
||||
boolean result = insertByBo(bo);
|
||||
if (!result) {
|
||||
throw DeviceException.bindFailed("设备信息保存失败");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解绑设备
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean unbindDevice(Long deviceId, Long userId) {
|
||||
LambdaQueryWrapper<AppDevice> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppDevice::getDeviceId, deviceId);
|
||||
lqw.eq(AppDevice::getUserId, userId);
|
||||
|
||||
AppDevice device = baseMapper.selectOne(lqw);
|
||||
if (device == null) {
|
||||
throw DeviceException.deviceNotFound(deviceId);
|
||||
}
|
||||
|
||||
boolean result = baseMapper.deleteById(deviceId) > 0;
|
||||
if (!result) {
|
||||
throw DeviceException.unbindFailed("设备删除失败");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备活跃状态
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateActiveStatus(Long deviceId, String isActive) {
|
||||
if (!"0".equals(isActive) && !"1".equals(isActive)) {
|
||||
throw DeviceException.invalidStatus(isActive);
|
||||
}
|
||||
|
||||
AppDevice existDevice = baseMapper.selectById(deviceId);
|
||||
if (existDevice == null) {
|
||||
throw DeviceException.deviceNotFound(deviceId);
|
||||
}
|
||||
|
||||
AppDevice device = new AppDevice();
|
||||
device.setDeviceId(deviceId);
|
||||
device.setIsActive(isActive);
|
||||
if ("1".equals(isActive)) {
|
||||
device.setLastActiveTime(LocalDateTime.now());
|
||||
}
|
||||
return baseMapper.updateById(device) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新推送令牌
|
||||
*/
|
||||
@Override
|
||||
public Boolean updatePushToken(Long deviceId, String pushToken) {
|
||||
if (StringUtils.isBlank(pushToken)) {
|
||||
throw DeviceException.invalidPushToken(pushToken);
|
||||
}
|
||||
|
||||
AppDevice existDevice = baseMapper.selectById(deviceId);
|
||||
if (existDevice == null) {
|
||||
throw DeviceException.deviceNotFound(deviceId);
|
||||
}
|
||||
|
||||
AppDevice device = new AppDevice();
|
||||
device.setDeviceId(deviceId);
|
||||
device.setPushToken(pushToken);
|
||||
device.setLastActiveTime(LocalDateTime.now());
|
||||
return baseMapper.updateById(device) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户活跃设备
|
||||
*/
|
||||
@Override
|
||||
public List<AppDeviceVo> getActiveDevices(Long userId) {
|
||||
LambdaQueryWrapper<AppDevice> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppDevice::getUserId, userId);
|
||||
lqw.eq(AppDevice::getIsActive, "1");
|
||||
lqw.orderByDesc(AppDevice::getLastActiveTime);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理非活跃设备
|
||||
*/
|
||||
@Override
|
||||
public Integer cleanInactiveDevices(Integer days) {
|
||||
if (days == null || days <= 0) {
|
||||
days = 30; // 默认30天
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<AppDevice> lqw = Wrappers.lambdaQuery();
|
||||
lqw.lt(AppDevice::getLastActiveTime, LocalDateTime.now().minusDays(days));
|
||||
lqw.or();
|
||||
lqw.eq(AppDevice::getIsActive, "0");
|
||||
|
||||
List<AppDevice> inactiveDevices = baseMapper.selectList(lqw);
|
||||
if (!inactiveDevices.isEmpty()) {
|
||||
List<Long> ids = inactiveDevices.stream().map(AppDevice::getDeviceId).toList();
|
||||
baseMapper.deleteBatchIds(ids);
|
||||
log.info("清理非活跃设备 {} 个", ids.size());
|
||||
return ids.size();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据推送令牌查询设备
|
||||
*/
|
||||
@Override
|
||||
public AppDeviceVo queryByPushToken(String pushToken) {
|
||||
if (StringUtils.isBlank(pushToken)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<AppDevice> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppDevice::getPushToken, pushToken);
|
||||
lqw.eq(AppDevice::getIsActive, "1");
|
||||
return baseMapper.selectVoOne(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备心跳更新
|
||||
*/
|
||||
@Override
|
||||
public Boolean heartbeat(Long deviceId) {
|
||||
AppDevice device = new AppDevice();
|
||||
device.setDeviceId(deviceId);
|
||||
device.setIsActive("1");
|
||||
device.setLastActiveTime(LocalDateTime.now());
|
||||
return baseMapper.updateById(device) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新设备状态
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean batchUpdateStatus(List<Long> deviceIds, String isActive) {
|
||||
if (ObjectUtil.isEmpty(deviceIds)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AppDevice device = new AppDevice();
|
||||
device.setIsActive(isActive);
|
||||
if ("1".equals(isActive)) {
|
||||
device.setLastActiveTime(LocalDateTime.now());
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<AppDevice> lqw = Wrappers.lambdaQuery();
|
||||
lqw.in(AppDevice::getDeviceId, deviceIds);
|
||||
|
||||
return baseMapper.update(device, lqw) > 0;
|
||||
}
|
||||
|
||||
}
|
||||
+420
@@ -0,0 +1,420 @@
|
||||
package org.dromara.member.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.crypto.digest.DigestUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.oss.core.OssClient;
|
||||
import org.dromara.common.oss.entity.UploadResult;
|
||||
import org.dromara.common.oss.factory.OssFactory;
|
||||
import org.dromara.member.domain.AppFile;
|
||||
import org.dromara.member.domain.bo.AppFileBo;
|
||||
import org.dromara.member.domain.vo.AppFileVo;
|
||||
import org.dromara.member.exception.FileException;
|
||||
import org.dromara.member.mapper.AppFileMapper;
|
||||
import org.dromara.member.service.AppFileService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* App端文件信息Service业务层处理
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class AppFileServiceImpl implements AppFileService {
|
||||
|
||||
private final AppFileMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询App端文件信息
|
||||
*/
|
||||
@Override
|
||||
public AppFileVo queryById(Long fileId) {
|
||||
return baseMapper.selectVoById(fileId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询App端文件信息列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<AppFileVo> queryPageList(AppFileBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<AppFile> lqw = buildQueryWrapper(bo);
|
||||
Page<AppFileVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询App端文件信息列表
|
||||
*/
|
||||
@Override
|
||||
public List<AppFileVo> queryList(AppFileBo bo) {
|
||||
LambdaQueryWrapper<AppFile> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<AppFile> buildQueryWrapper(AppFileBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<AppFile> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getUserId() != null, AppFile::getUserId, bo.getUserId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getFileName()), AppFile::getFileName, bo.getFileName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getOriginalName()), AppFile::getOriginalName, bo.getOriginalName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getFileType()), AppFile::getFileType, bo.getFileType());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getFileSuffix()), AppFile::getFileSuffix, bo.getFileSuffix());
|
||||
lqw.eq(bo.getFileCategory() != null, AppFile::getFileCategory, bo.getFileCategory());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), AppFile::getStatus, bo.getStatus());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getIsPublic()), AppFile::getIsPublic, bo.getIsPublic());
|
||||
lqw.between(params.get("beginTime") != null && params.get("endTime") != null,
|
||||
AppFile::getCreateTime, params.get("beginTime"), params.get("endTime"));
|
||||
lqw.orderByDesc(AppFile::getCreateTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增App端文件信息
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(AppFileBo bo) {
|
||||
AppFile add = BeanUtil.toBean(bo, AppFile.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setFileId(add.getFileId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改App端文件信息
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(AppFileBo bo) {
|
||||
AppFile update = BeanUtil.toBean(bo, AppFile.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(AppFile entity) {
|
||||
// 可以添加一些业务校验逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除App端文件信息
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// 可以添加删除前的校验逻辑
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public AppFileVo uploadFile(MultipartFile file, Long userId, Integer fileCategory) {
|
||||
if (file.isEmpty()) {
|
||||
throw FileException.fileEmpty();
|
||||
}
|
||||
|
||||
// 检查文件大小(限制为100MB)
|
||||
if (file.getSize() > 100 * 1024 * 1024) {
|
||||
throw FileException.fileSizeExceeded(100);
|
||||
}
|
||||
|
||||
try {
|
||||
// 计算文件MD5
|
||||
String fileMd5 = DigestUtil.md5Hex(file.getInputStream());
|
||||
|
||||
// 检查文件是否已存在
|
||||
AppFileVo existFile = checkFileExists(fileMd5, userId);
|
||||
if (existFile != null) {
|
||||
return existFile;
|
||||
}
|
||||
|
||||
// 上传到OSS
|
||||
OssClient ossClient = OssFactory.instance();
|
||||
UploadResult uploadResult = ossClient.uploadSuffix(file.getBytes(), getFileSuffix(file.getOriginalFilename()), file.getContentType());
|
||||
|
||||
// 保存文件信息
|
||||
AppFile appFile = new AppFile();
|
||||
appFile.setUserId(userId);
|
||||
appFile.setFileName(uploadResult.getFilename());
|
||||
appFile.setOriginalName(file.getOriginalFilename());
|
||||
appFile.setFilePath(uploadResult.getFilename());
|
||||
appFile.setFileUrl(uploadResult.getUrl());
|
||||
appFile.setFileSize(file.getSize());
|
||||
appFile.setFileType(file.getContentType());
|
||||
appFile.setFileSuffix(getFileSuffix(file.getOriginalFilename()));
|
||||
appFile.setFileCategory(fileCategory != null ? fileCategory : 6); // 默认为其他
|
||||
appFile.setStorageService(ossClient.getConfigKey());
|
||||
appFile.setStatus("0"); // 正常
|
||||
appFile.setDownloadCount(0L);
|
||||
appFile.setIsPublic("0"); // 默认私有
|
||||
appFile.setFileMd5(fileMd5);
|
||||
|
||||
baseMapper.insert(appFile);
|
||||
return MapstructUtils.convert(appFile, AppFileVo.class);
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("文件上传失败", e);
|
||||
throw FileException.uploadFailed(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传头像
|
||||
*/
|
||||
@Override
|
||||
public AppFileVo uploadAvatar(MultipartFile file, Long userId) {
|
||||
// 检查文件类型
|
||||
String contentType = file.getContentType();
|
||||
if (!isImageFile(contentType)) {
|
||||
throw FileException.unsupportedFileType(contentType);
|
||||
}
|
||||
|
||||
// 检查文件大小(限制为5MB)
|
||||
if (file.getSize() > 5 * 1024 * 1024) {
|
||||
throw FileException.fileSizeExceeded(5);
|
||||
}
|
||||
|
||||
return uploadFile(file, userId, 1); // 头像分类
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量上传文件
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<AppFileVo> batchUploadFiles(MultipartFile[] files, Long userId, Integer fileCategory) {
|
||||
List<AppFileVo> result = new ArrayList<>();
|
||||
for (MultipartFile file : files) {
|
||||
try {
|
||||
AppFileVo fileVo = uploadFile(file, userId, fileCategory);
|
||||
result.add(fileVo);
|
||||
} catch (Exception e) {
|
||||
log.error("批量上传文件失败: {}", file.getOriginalFilename(), e);
|
||||
// 继续处理其他文件
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询文件列表
|
||||
*/
|
||||
@Override
|
||||
public List<AppFileVo> queryByUserId(Long userId, Integer fileCategory) {
|
||||
LambdaQueryWrapper<AppFile> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppFile::getUserId, userId);
|
||||
lqw.eq(fileCategory != null, AppFile::getFileCategory, fileCategory);
|
||||
lqw.eq(AppFile::getStatus, "0"); // 正常状态
|
||||
lqw.orderByDesc(AppFile::getCreateTime);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件分类查询文件列表
|
||||
*/
|
||||
@Override
|
||||
public List<AppFileVo> queryByCategory(Integer fileCategory) {
|
||||
LambdaQueryWrapper<AppFile> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppFile::getFileCategory, fileCategory);
|
||||
lqw.eq(AppFile::getStatus, "0"); // 正常状态
|
||||
lqw.eq(AppFile::getIsPublic, "1"); // 公开文件
|
||||
lqw.orderByDesc(AppFile::getCreateTime);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public AppFileVo downloadFile(Long fileId, Long userId) {
|
||||
AppFile appFile = baseMapper.selectById(fileId);
|
||||
if (appFile == null) {
|
||||
throw FileException.fileNotFound(fileId);
|
||||
}
|
||||
|
||||
// 检查权限
|
||||
if (!appFile.getUserId().equals(userId) && !"1".equals(appFile.getIsPublic())) {
|
||||
throw FileException.accessDenied(fileId);
|
||||
}
|
||||
|
||||
// 更新下载次数
|
||||
appFile.setDownloadCount(appFile.getDownloadCount() + 1);
|
||||
baseMapper.updateById(appFile);
|
||||
|
||||
return MapstructUtils.convert(appFile, AppFileVo.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户文件
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteUserFile(Long fileId, Long userId) {
|
||||
AppFile appFile = baseMapper.selectById(fileId);
|
||||
if (appFile == null) {
|
||||
throw FileException.fileNotFound(fileId);
|
||||
}
|
||||
|
||||
if (!appFile.getUserId().equals(userId)) {
|
||||
throw FileException.accessDenied(fileId);
|
||||
}
|
||||
|
||||
return baseMapper.deleteById(fileId) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除用户文件
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean batchDeleteUserFiles(Collection<Long> fileIds, Long userId) {
|
||||
for (Long fileId : fileIds) {
|
||||
deleteUserFile(fileId, userId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新文件状态
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateFileStatus(Long fileId, String status, Long userId) {
|
||||
AppFile appFile = baseMapper.selectById(fileId);
|
||||
if (appFile == null) {
|
||||
throw new ServiceException("文件不存在");
|
||||
}
|
||||
|
||||
if (!appFile.getUserId().equals(userId)) {
|
||||
throw new ServiceException("无权限修改该文件");
|
||||
}
|
||||
|
||||
appFile.setStatus(status);
|
||||
return baseMapper.updateById(appFile) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户文件统计信息
|
||||
*/
|
||||
@Override
|
||||
public AppFileVo getUserFileStatistics(Long userId) {
|
||||
LambdaQueryWrapper<AppFile> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppFile::getUserId, userId);
|
||||
lqw.eq(AppFile::getStatus, "0");
|
||||
|
||||
List<AppFile> files = baseMapper.selectList(lqw);
|
||||
|
||||
AppFileVo statistics = new AppFileVo();
|
||||
statistics.setUserId(userId);
|
||||
|
||||
if (!files.isEmpty()) {
|
||||
long totalSize = files.stream().mapToLong(AppFile::getFileSize).sum();
|
||||
long totalDownloads = files.stream().mapToLong(AppFile::getDownloadCount).sum();
|
||||
|
||||
statistics.setFileSize(totalSize);
|
||||
statistics.setDownloadCount(totalDownloads);
|
||||
}
|
||||
|
||||
return statistics;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理过期文件
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Integer cleanExpiredFiles(Integer days) {
|
||||
LocalDateTime expiredTime = LocalDateTime.now().minusDays(days);
|
||||
LambdaQueryWrapper<AppFile> lqw = Wrappers.lambdaQuery();
|
||||
lqw.lt(AppFile::getCreateTime, expiredTime);
|
||||
lqw.eq(AppFile::getStatus, "1"); // 已删除状态
|
||||
|
||||
List<AppFile> expiredFiles = baseMapper.selectList(lqw);
|
||||
if (!expiredFiles.isEmpty()) {
|
||||
List<Long> fileIds = expiredFiles.stream().map(AppFile::getFileId).collect(Collectors.toList());
|
||||
baseMapper.deleteBatchIds(fileIds);
|
||||
}
|
||||
|
||||
return expiredFiles.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件是否存在
|
||||
*/
|
||||
@Override
|
||||
public AppFileVo checkFileExists(String fileMd5, Long userId) {
|
||||
LambdaQueryWrapper<AppFile> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppFile::getFileMd5, fileMd5);
|
||||
lqw.eq(AppFile::getUserId, userId);
|
||||
lqw.eq(AppFile::getStatus, "0");
|
||||
|
||||
AppFile existFile = baseMapper.selectOne(lqw);
|
||||
return existFile != null ? MapstructUtils.convert(existFile, AppFileVo.class) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新文件公开状态
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateFilePublicStatus(Long fileId, String isPublic, Long userId) {
|
||||
AppFile appFile = baseMapper.selectById(fileId);
|
||||
if (appFile == null) {
|
||||
throw new ServiceException("文件不存在");
|
||||
}
|
||||
|
||||
if (!appFile.getUserId().equals(userId)) {
|
||||
throw new ServiceException("无权限修改该文件");
|
||||
}
|
||||
|
||||
appFile.setIsPublic(isPublic);
|
||||
return baseMapper.updateById(appFile) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件后缀
|
||||
*/
|
||||
private String getFileSuffix(String fileName) {
|
||||
if (StringUtils.isBlank(fileName)) {
|
||||
return "";
|
||||
}
|
||||
int lastDotIndex = fileName.lastIndexOf(".");
|
||||
return lastDotIndex > 0 ? fileName.substring(lastDotIndex) : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为图片文件
|
||||
*/
|
||||
private boolean isImageFile(String contentType) {
|
||||
return StringUtils.isNotBlank(contentType) &&
|
||||
(contentType.startsWith("image/") ||
|
||||
contentType.equals("application/octet-stream"));
|
||||
}
|
||||
|
||||
}
|
||||
+310
@@ -0,0 +1,310 @@
|
||||
package org.dromara.member.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.member.domain.AppMessage;
|
||||
import org.dromara.member.domain.bo.AppMessageBo;
|
||||
import org.dromara.member.domain.vo.AppMessageVo;
|
||||
import org.dromara.member.mapper.AppMessageMapper;
|
||||
import org.dromara.member.service.AppMessageService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端消息Service业务层处理
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class AppMessageServiceImpl extends ServiceImpl<AppMessageMapper, AppMessage> implements AppMessageService {
|
||||
|
||||
private final AppMessageMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询App端消息
|
||||
*/
|
||||
@Override
|
||||
public AppMessageVo queryById(Long messageId) {
|
||||
return baseMapper.selectVoById(messageId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询App端消息列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<AppMessageVo> queryPageList(AppMessageBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<AppMessage> lqw = buildQueryWrapper(bo);
|
||||
Page<AppMessageVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询App端消息列表
|
||||
*/
|
||||
@Override
|
||||
public List<AppMessageVo> queryList(AppMessageBo bo) {
|
||||
LambdaQueryWrapper<AppMessage> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<AppMessage> buildQueryWrapper(AppMessageBo bo) {
|
||||
LambdaQueryWrapper<AppMessage> lqw = Wrappers.lambdaQuery();
|
||||
lqw.like(StringUtils.isNotBlank(bo.getTitle()), AppMessage::getTitle, bo.getTitle());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getContent()), AppMessage::getContent, bo.getContent());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getMessageType()), AppMessage::getMessageType, bo.getMessageType());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getTargetType()), AppMessage::getTargetType, bo.getTargetType());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getTargetIds()), AppMessage::getTargetIds, bo.getTargetIds());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), AppMessage::getStatus, bo.getStatus());
|
||||
|
||||
// 如果指定了接收者ID,查询该用户相关的消息
|
||||
if (ObjectUtil.isNotNull(bo.getReceiverId())) {
|
||||
lqw.and(wrapper -> wrapper.eq(AppMessage::getTargetType, "all")
|
||||
.or()
|
||||
.and(subWrapper -> subWrapper.eq(AppMessage::getTargetType, "user")
|
||||
.like(AppMessage::getTargetIds, bo.getReceiverId().toString())));
|
||||
}
|
||||
|
||||
lqw.orderByDesc(AppMessage::getCreateTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增App端消息
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(AppMessageBo bo) {
|
||||
AppMessage add = BeanUtil.toBean(bo, AppMessage.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setMessageId(add.getMessageId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改App端消息
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(AppMessageBo bo) {
|
||||
AppMessage update = BeanUtil.toBean(bo, AppMessage.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(AppMessage entity) {
|
||||
// TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除App端消息
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户未读消息数量
|
||||
*/
|
||||
@Override
|
||||
public Long getUnreadCount(Long userId) {
|
||||
LambdaQueryWrapper<AppMessage> lqw = Wrappers.lambdaQuery();
|
||||
lqw.and(wrapper -> wrapper.eq(AppMessage::getTargetType, "user")
|
||||
.like(AppMessage::getTargetIds, userId.toString())
|
||||
.or()
|
||||
.eq(AppMessage::getTargetType, "all"));
|
||||
lqw.eq(AppMessage::getStatus, "1"); // 已发送
|
||||
return baseMapper.selectCount(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记消息为已读
|
||||
*/
|
||||
@Override
|
||||
public Boolean markAsRead(Long messageId, Long userId) {
|
||||
// 由于当前表结构不支持已读状态,这里只是示例实现
|
||||
// 实际项目中可能需要单独的消息阅读记录表
|
||||
log.info("用户 {} 标记消息 {} 为已读", userId, messageId);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量标记消息为已读
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean markAsReadBatch(List<Long> messageIds, Long userId) {
|
||||
// 由于当前表结构不支持已读状态,这里只是示例实现
|
||||
log.info("用户 {} 批量标记消息为已读,消息数量: {}", userId, messageIds.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记所有消息为已读
|
||||
*/
|
||||
@Override
|
||||
public Boolean markAllAsRead(Long userId) {
|
||||
// 由于当前表结构不支持已读状态,这里只是示例实现
|
||||
log.info("用户 {} 标记所有消息为已读", userId);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送系统消息
|
||||
*/
|
||||
@Override
|
||||
public Boolean sendSystemMessage(AppMessageBo bo) {
|
||||
bo.setMessageType("system"); // 系统消息
|
||||
bo.setTargetType("all"); // 全部用户
|
||||
bo.setStatus("0"); // 待发送
|
||||
bo.setSendTime(LocalDateTime.now());
|
||||
return insertByBo(bo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送个人消息
|
||||
*/
|
||||
@Override
|
||||
public Boolean sendPersonalMessage(AppMessageBo bo) {
|
||||
bo.setMessageType("notice"); // 通知消息
|
||||
bo.setTargetType("user"); // 指定用户
|
||||
bo.setStatus("0"); // 待发送
|
||||
bo.setSendTime(LocalDateTime.now());
|
||||
return insertByBo(bo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送消息到指定用户
|
||||
*/
|
||||
@Override
|
||||
public Boolean pushMessage(AppMessageBo bo) {
|
||||
bo.setTargetType("user");
|
||||
bo.setStatus("0"); // 待发送
|
||||
bo.setSendTime(LocalDateTime.now());
|
||||
|
||||
// 先保存消息
|
||||
Boolean result = insertByBo(bo);
|
||||
if (result) {
|
||||
// 发送推送通知
|
||||
String[] userIds = bo.getTargetIds().split(",");
|
||||
for (String userId : userIds) {
|
||||
sendPushNotification(Long.valueOf(userId), bo.getTitle(), bo.getContent());
|
||||
}
|
||||
|
||||
// 更新发送状态
|
||||
AppMessage update = new AppMessage();
|
||||
update.setMessageId(bo.getMessageId());
|
||||
update.setStatus("1"); // 已发送
|
||||
baseMapper.updateById(update);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 群发消息
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean broadcastMessage(AppMessageBo bo) {
|
||||
bo.setMessageType("activity"); // 活动消息
|
||||
bo.setTargetType("all"); // 全部用户
|
||||
bo.setStatus("0"); // 待发送
|
||||
bo.setSendTime(LocalDateTime.now());
|
||||
|
||||
Boolean result = insertByBo(bo);
|
||||
if (result) {
|
||||
// 发送批量推送通知
|
||||
sendBatchPushNotification(null, bo.getTitle(), bo.getContent());
|
||||
|
||||
// 更新发送状态
|
||||
AppMessage update = new AppMessage();
|
||||
update.setMessageId(bo.getMessageId());
|
||||
update.setStatus("1"); // 已发送
|
||||
baseMapper.updateById(update);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送推送通知
|
||||
*/
|
||||
@Override
|
||||
public Boolean sendPushNotification(Long userId, String title, String content) {
|
||||
try {
|
||||
// TODO: 集成第三方推送服务(极光推送、友盟推送等)
|
||||
// 这里只是示例代码,实际需要根据具体的推送服务进行实现
|
||||
log.info("发送推送通知 - 用户ID: {}, 标题: {}, 内容: {}", userId, title, content);
|
||||
|
||||
// 模拟推送成功
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("发送推送通知失败", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量发送推送通知
|
||||
*/
|
||||
@Override
|
||||
public Boolean sendBatchPushNotification(List<Long> userIds, String title, String content) {
|
||||
try {
|
||||
// TODO: 集成第三方推送服务的批量推送接口
|
||||
if (userIds != null) {
|
||||
log.info("批量发送推送通知 - 用户数量: {}, 标题: {}, 内容: {}", userIds.size(), title, content);
|
||||
} else {
|
||||
log.info("全员推送通知 - 标题: {}, 内容: {}", title, content);
|
||||
}
|
||||
|
||||
// 模拟推送成功
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("批量发送推送通知失败", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理过期消息
|
||||
*/
|
||||
@Override
|
||||
public Integer cleanExpiredMessages() {
|
||||
// 清理30天前的已发送消息
|
||||
LambdaQueryWrapper<AppMessage> lqw = Wrappers.lambdaQuery();
|
||||
lqw.lt(AppMessage::getCreateTime, LocalDateTime.now().minusDays(30));
|
||||
lqw.eq(AppMessage::getStatus, "1"); // 已发送
|
||||
|
||||
List<AppMessage> expiredMessages = baseMapper.selectList(lqw);
|
||||
if (!expiredMessages.isEmpty()) {
|
||||
List<Long> ids = expiredMessages.stream().map(AppMessage::getMessageId).toList();
|
||||
baseMapper.deleteBatchIds(ids);
|
||||
log.info("清理过期消息 {} 条", ids.size());
|
||||
return ids.size();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+296
@@ -0,0 +1,296 @@
|
||||
package org.dromara.member.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.member.domain.AppOperLog;
|
||||
import org.dromara.member.domain.bo.AppOperLogBo;
|
||||
import org.dromara.member.domain.vo.AppOperLogVo;
|
||||
import org.dromara.member.mapper.AppOperLogMapper;
|
||||
import org.dromara.member.service.AppOperLogService;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* App端操作日志Service业务层处理
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class AppOperLogServiceImpl extends ServiceImpl<AppOperLogMapper, AppOperLog> implements AppOperLogService {
|
||||
|
||||
private final AppOperLogMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询App端操作日志
|
||||
*/
|
||||
@Override
|
||||
public AppOperLogVo queryById(Long operId) {
|
||||
return baseMapper.selectVoById(operId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询App端操作日志列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<AppOperLogVo> queryPageList(AppOperLogBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<AppOperLog> lqw = buildQueryWrapper(bo);
|
||||
Page<AppOperLogVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询App端操作日志列表
|
||||
*/
|
||||
@Override
|
||||
public List<AppOperLogVo> queryList(AppOperLogBo bo) {
|
||||
LambdaQueryWrapper<AppOperLog> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<AppOperLog> buildQueryWrapper(AppOperLogBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<AppOperLog> lqw = Wrappers.lambdaQuery();
|
||||
lqw.like(StringUtils.isNotBlank(bo.getTitle()), AppOperLog::getTitle, bo.getTitle());
|
||||
lqw.eq(bo.getBusinessType() != null, AppOperLog::getBusinessType, bo.getBusinessType());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getMethod()), AppOperLog::getMethod, bo.getMethod());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getRequestMethod()), AppOperLog::getRequestMethod, bo.getRequestMethod());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getOperName()), AppOperLog::getOperName, bo.getOperName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getOperIp()), AppOperLog::getOperIp, bo.getOperIp());
|
||||
lqw.eq(bo.getStatus() != null, AppOperLog::getStatus, bo.getStatus());
|
||||
lqw.between(params.get("beginTime") != null && params.get("endTime") != null,
|
||||
AppOperLog::getOperTime, params.get("beginTime"), params.get("endTime"));
|
||||
lqw.orderByDesc(AppOperLog::getOperTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增App端操作日志
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(AppOperLogBo bo) {
|
||||
AppOperLog add = MapstructUtils.convert(bo, AppOperLog.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setOperId(add.getOperId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改App端操作日志
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(AppOperLogBo bo) {
|
||||
AppOperLog update = MapstructUtils.convert(bo, AppOperLog.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(AppOperLog entity) {
|
||||
// TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除App端操作日志
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录操作日志
|
||||
*/
|
||||
@Override
|
||||
public void recordOperLog(String title, Integer businessType, String method, String requestMethod,
|
||||
String operName, String operUrl, String operIp, String operLocation,
|
||||
String operParam, String jsonResult, Integer status, String errorMsg, Long costTime) {
|
||||
AppOperLog operLog = new AppOperLog();
|
||||
operLog.setTitle(title);
|
||||
operLog.setBusinessType(businessType);
|
||||
operLog.setMethod(method);
|
||||
operLog.setRequestMethod(requestMethod);
|
||||
operLog.setOperName(operName);
|
||||
operLog.setOperUrl(operUrl);
|
||||
operLog.setOperIp(operIp);
|
||||
operLog.setOperLocation(operLocation);
|
||||
operLog.setOperParam(operParam);
|
||||
operLog.setJsonResult(jsonResult);
|
||||
operLog.setStatus(status);
|
||||
operLog.setErrorMsg(errorMsg);
|
||||
operLog.setOperTime(LocalDateTime.now());
|
||||
operLog.setCostTime(costTime);
|
||||
|
||||
try {
|
||||
baseMapper.insert(operLog);
|
||||
} catch (Exception e) {
|
||||
log.error("记录操作日志失败: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据操作人查询操作日志
|
||||
*/
|
||||
@Override
|
||||
public List<AppOperLogVo> queryByOperName(String operName) {
|
||||
LambdaQueryWrapper<AppOperLog> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StringUtils.isNotBlank(operName), AppOperLog::getOperName, operName);
|
||||
lqw.orderByDesc(AppOperLog::getOperTime);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空操作日志
|
||||
*/
|
||||
@Override
|
||||
public void cleanOperLog() {
|
||||
baseMapper.delete(Wrappers.lambdaQuery());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据时间范围删除操作日志
|
||||
*/
|
||||
@Override
|
||||
public void deleteOperLogByTime(LocalDateTime beginTime, LocalDateTime endTime) {
|
||||
LambdaQueryWrapper<AppOperLog> lqw = Wrappers.lambdaQuery();
|
||||
if (beginTime != null) {
|
||||
lqw.ge(AppOperLog::getOperTime, beginTime);
|
||||
}
|
||||
if (endTime != null) {
|
||||
lqw.le(AppOperLog::getOperTime, endTime);
|
||||
}
|
||||
baseMapper.delete(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作统计信息
|
||||
*/
|
||||
@Override
|
||||
public Long getOperLogCount(String operName, LocalDateTime beginTime, LocalDateTime endTime) {
|
||||
LambdaQueryWrapper<AppOperLog> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StringUtils.isNotBlank(operName), AppOperLog::getOperName, operName);
|
||||
if (beginTime != null) {
|
||||
lqw.ge(AppOperLog::getOperTime, beginTime);
|
||||
}
|
||||
if (endTime != null) {
|
||||
lqw.le(AppOperLog::getOperTime, endTime);
|
||||
}
|
||||
return baseMapper.selectCount(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户行为分析数据
|
||||
*/
|
||||
@Override
|
||||
public List<AppOperLogVo> getUserBehaviorAnalysis(String operName, Integer days) {
|
||||
LambdaQueryWrapper<AppOperLog> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StringUtils.isNotBlank(operName), AppOperLog::getOperName, operName);
|
||||
if (days != null && days > 0) {
|
||||
LocalDateTime startTime = LocalDateTime.now().minusDays(days);
|
||||
lqw.ge(AppOperLog::getOperTime, startTime);
|
||||
}
|
||||
lqw.orderByDesc(AppOperLog::getOperTime);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取热门操作统计
|
||||
*/
|
||||
@Override
|
||||
public List<AppOperLogVo> getPopularOperations(Integer days, Integer limit) {
|
||||
LambdaQueryWrapper<AppOperLog> lqw = Wrappers.lambdaQuery();
|
||||
if (days != null && days > 0) {
|
||||
LocalDateTime startTime = LocalDateTime.now().minusDays(days);
|
||||
lqw.ge(AppOperLog::getOperTime, startTime);
|
||||
}
|
||||
lqw.eq(AppOperLog::getStatus, 0); // 只统计成功的操作
|
||||
lqw.orderByDesc(AppOperLog::getOperTime);
|
||||
|
||||
List<AppOperLogVo> allLogs = baseMapper.selectVoList(lqw);
|
||||
|
||||
// 按操作标题分组统计
|
||||
Map<String, Long> operationCount = allLogs.stream()
|
||||
.collect(Collectors.groupingBy(AppOperLogVo::getTitle, Collectors.counting()));
|
||||
|
||||
// 返回前N个热门操作
|
||||
return allLogs.stream()
|
||||
.collect(Collectors.groupingBy(AppOperLogVo::getTitle))
|
||||
.entrySet().stream()
|
||||
.sorted((e1, e2) -> Long.compare(e2.getValue().size(), e1.getValue().size()))
|
||||
.limit(limit != null ? limit : 10)
|
||||
.flatMap(entry -> entry.getValue().stream().limit(1))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误操作统计
|
||||
*/
|
||||
@Override
|
||||
public List<AppOperLogVo> getErrorOperations(Integer days) {
|
||||
LambdaQueryWrapper<AppOperLog> lqw = Wrappers.lambdaQuery();
|
||||
if (days != null && days > 0) {
|
||||
LocalDateTime startTime = LocalDateTime.now().minusDays(days);
|
||||
lqw.ge(AppOperLog::getOperTime, startTime);
|
||||
}
|
||||
lqw.eq(AppOperLog::getStatus, 1); // 只查询异常操作
|
||||
lqw.orderByDesc(AppOperLog::getOperTime);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量记录操作日志
|
||||
*/
|
||||
@Override
|
||||
public void batchInsertOperLog(List<AppOperLogBo> operLogs) {
|
||||
if (operLogs == null || operLogs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<AppOperLog> logs = operLogs.stream()
|
||||
.map(bo -> MapstructUtils.convert(bo, AppOperLog.class))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
try {
|
||||
this.saveBatch(logs);
|
||||
} catch (Exception e) {
|
||||
log.error("批量记录操作日志失败: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步记录操作日志
|
||||
*/
|
||||
@Async
|
||||
@Override
|
||||
public void asyncRecordOperLog(AppOperLogBo bo) {
|
||||
try {
|
||||
insertByBo(bo);
|
||||
} catch (Exception e) {
|
||||
log.error("异步记录操作日志失败: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
package org.dromara.member.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.member.domain.AppRole;
|
||||
import org.dromara.member.domain.AppUserRole;
|
||||
import org.dromara.member.domain.bo.AppRoleBo;
|
||||
import org.dromara.member.domain.vo.AppRoleVo;
|
||||
import org.dromara.member.mapper.AppRoleMapper;
|
||||
import org.dromara.member.mapper.AppUserRoleMapper;
|
||||
import org.dromara.member.service.AppRoleService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* App端角色信息Service业务层处理
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Service
|
||||
public class AppRoleServiceImpl extends ServiceImpl<AppRoleMapper, AppRole> implements AppRoleService {
|
||||
|
||||
@Autowired
|
||||
private AppUserRoleMapper userRoleMapper;
|
||||
|
||||
/**
|
||||
* 查询App端角色信息
|
||||
*/
|
||||
@Override
|
||||
public AppRoleVo queryById(Long roleId) {
|
||||
return baseMapper.selectVoById(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询App端角色信息列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<AppRoleVo> queryPageList(AppRoleBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<AppRole> lqw = buildQueryWrapper(bo);
|
||||
Page<AppRoleVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询App端角色信息列表
|
||||
*/
|
||||
@Override
|
||||
public List<AppRoleVo> queryList(AppRoleBo bo) {
|
||||
LambdaQueryWrapper<AppRole> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<AppRole> buildQueryWrapper(AppRoleBo bo) {
|
||||
LambdaQueryWrapper<AppRole> lqw = Wrappers.lambdaQuery();
|
||||
lqw.like(StringUtils.isNotBlank(bo.getRoleName()), AppRole::getRoleName, bo.getRoleName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getRoleKey()), AppRole::getRoleKey, bo.getRoleKey());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), AppRole::getStatus, bo.getStatus());
|
||||
lqw.orderByAsc(AppRole::getRoleSort);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增App端角色信息
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(AppRoleBo bo) {
|
||||
AppRole add = BeanUtil.toBean(bo, AppRole.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setRoleId(add.getRoleId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改App端角色信息
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(AppRoleBo bo) {
|
||||
AppRole update = BeanUtil.toBean(bo, AppRole.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(AppRole entity) {
|
||||
// TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除App端角色信息
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// 校验角色是否存在用户关联
|
||||
for (Long id : ids) {
|
||||
long count = countUserRoleByRoleId(id);
|
||||
if (count > 0) {
|
||||
AppRoleVo role = queryById(id);
|
||||
throw new RuntimeException(String.format("角色%s已分配用户,不能删除", role.getRoleName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询角色
|
||||
*/
|
||||
@Override
|
||||
public List<AppRoleVo> selectRolesByUserId(Long userId) {
|
||||
return baseMapper.selectRolesByUserId(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID获取角色权限
|
||||
*/
|
||||
@Override
|
||||
public Set<String> selectRolePermissionByUserId(Long userId) {
|
||||
Set<String> perms = baseMapper.selectRolePermissionByUserId(userId);
|
||||
return perms;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有角色
|
||||
*/
|
||||
@Override
|
||||
public List<AppRoleVo> selectRoleAll() {
|
||||
return baseMapper.selectRoleAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID获取角色选择框列表
|
||||
*/
|
||||
@Override
|
||||
public List<Long> selectRoleListByUserId(Long userId) {
|
||||
return baseMapper.selectRoleListByUserId(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验角色名称是否唯一
|
||||
*/
|
||||
@Override
|
||||
public boolean checkRoleNameUnique(String roleName) {
|
||||
return baseMapper.checkRoleNameUnique(roleName) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验角色权限是否唯一
|
||||
*/
|
||||
@Override
|
||||
public boolean checkRoleKeyUnique(String roleKey) {
|
||||
return baseMapper.checkRoleKeyUnique(roleKey) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验角色是否允许操作
|
||||
*/
|
||||
@Override
|
||||
public boolean checkRoleAllowed(Long roleId) {
|
||||
return roleId != null && roleId != 1L;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验角色是否有数据权限
|
||||
*/
|
||||
@Override
|
||||
public boolean checkRoleDataScope(Long roleId) {
|
||||
return roleId != null && roleId != 1L;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过角色ID查询角色使用数量
|
||||
*/
|
||||
@Override
|
||||
public long countUserRoleByRoleId(Long roleId) {
|
||||
return userRoleMapper.countUserRoleByRoleId(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消授权用户角色
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean deleteAuthUser(Long userId, Long roleId) {
|
||||
LambdaQueryWrapper<AppUserRole> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.eq(AppUserRole::getUserId, userId)
|
||||
.eq(AppUserRole::getRoleId, roleId);
|
||||
return userRoleMapper.delete(wrapper) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量取消授权用户角色
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean deleteAuthUsers(Long roleId, Long[] userIds) {
|
||||
LambdaQueryWrapper<AppUserRole> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.eq(AppUserRole::getRoleId, roleId)
|
||||
.in(AppUserRole::getUserId, Arrays.asList(userIds));
|
||||
return userRoleMapper.delete(wrapper) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量选择授权用户角色
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean insertAuthUsers(Long roleId, Long[] userIds) {
|
||||
// 新增用户与角色管理
|
||||
List<AppUserRole> list = Arrays.stream(userIds).map(userId -> {
|
||||
AppUserRole ur = new AppUserRole();
|
||||
ur.setUserId(userId);
|
||||
ur.setRoleId(roleId);
|
||||
return ur;
|
||||
}).collect(Collectors.toList());
|
||||
return userRoleMapper.batchUserRole(list) > 0;
|
||||
}
|
||||
|
||||
}
|
||||
+273
@@ -0,0 +1,273 @@
|
||||
package org.dromara.member.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.member.domain.AppSocialAuth;
|
||||
import org.dromara.member.domain.vo.AppSocialAuthVo;
|
||||
import org.dromara.member.domain.vo.AppUserVo;
|
||||
import org.dromara.member.mapper.AppSocialAuthMapper;
|
||||
import org.dromara.member.service.AppSocialAuthService;
|
||||
import org.dromara.member.service.AppUserService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端第三方登录授权Service业务层处理
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class AppSocialAuthServiceImpl extends ServiceImpl<AppSocialAuthMapper, AppSocialAuth> implements AppSocialAuthService {
|
||||
|
||||
private final AppSocialAuthMapper baseMapper;
|
||||
private final AppUserService appUserService;
|
||||
|
||||
/**
|
||||
* 查询App端第三方登录授权
|
||||
*/
|
||||
@Override
|
||||
public AppSocialAuthVo queryById(Long id) {
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询社交认证列表
|
||||
*/
|
||||
@Override
|
||||
public List<AppSocialAuthVo> queryByUserId(Long userId) {
|
||||
LambdaQueryWrapper<AppSocialAuth> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AppSocialAuth::getUserId, userId)
|
||||
.eq(AppSocialAuth::getDelFlag, "0")
|
||||
.orderByDesc(AppSocialAuth::getCreateTime);
|
||||
return baseMapper.selectVoList(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据平台和openId查询社交认证
|
||||
*/
|
||||
@Override
|
||||
public AppSocialAuth queryByPlatformAndOpenId(String platform, String openId) {
|
||||
if (StringUtils.isBlank(platform) || StringUtils.isBlank(openId)) {
|
||||
return null;
|
||||
}
|
||||
LambdaQueryWrapper<AppSocialAuth> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AppSocialAuth::getPlatform, platform)
|
||||
.eq(AppSocialAuth::getOpenId, openId)
|
||||
.eq(AppSocialAuth::getDelFlag, "0")
|
||||
.last("LIMIT 1");
|
||||
return baseMapper.selectOne(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据平台和unionId查询社交认证
|
||||
*/
|
||||
@Override
|
||||
public AppSocialAuth queryByPlatformAndUnionId(String platform, String unionId) {
|
||||
if (StringUtils.isBlank(platform) || StringUtils.isBlank(unionId)) {
|
||||
return null;
|
||||
}
|
||||
LambdaQueryWrapper<AppSocialAuth> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AppSocialAuth::getPlatform, platform)
|
||||
.eq(AppSocialAuth::getUnionId, unionId)
|
||||
.eq(AppSocialAuth::getDelFlag, "0")
|
||||
.last("LIMIT 1");
|
||||
return baseMapper.selectOne(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增App端第三方登录授权
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertAppSocialAuth(AppSocialAuth appSocialAuth) {
|
||||
appSocialAuth.setDelFlag("0");
|
||||
appSocialAuth.setCreateTime(new Date());
|
||||
return baseMapper.insert(appSocialAuth) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改App端第三方登录授权
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateAppSocialAuth(AppSocialAuth appSocialAuth) {
|
||||
appSocialAuth.setUpdateTime(new Date());
|
||||
return baseMapper.updateById(appSocialAuth) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除App端第三方登录授权
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteAppSocialAuthById(Long id) {
|
||||
AppSocialAuth appSocialAuth = new AppSocialAuth();
|
||||
appSocialAuth.setId(id);
|
||||
appSocialAuth.setDelFlag("2");
|
||||
appSocialAuth.setUpdateTime(new Date());
|
||||
return baseMapper.updateById(appSocialAuth) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID删除社交认证
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteByUserId(Long userId) {
|
||||
LambdaQueryWrapper<AppSocialAuth> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AppSocialAuth::getUserId, userId);
|
||||
List<AppSocialAuth> list = baseMapper.selectList(wrapper);
|
||||
if (list.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
AppSocialAuth updateEntity = new AppSocialAuth();
|
||||
updateEntity.setDelFlag("2");
|
||||
updateEntity.setUpdateTime(new Date());
|
||||
|
||||
return baseMapper.update(updateEntity, wrapper) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新访问令牌
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateAccessToken(Long id, String accessToken, Integer expireIn, String refreshToken) {
|
||||
AppSocialAuth appSocialAuth = new AppSocialAuth();
|
||||
appSocialAuth.setId(id);
|
||||
appSocialAuth.setAccessToken(accessToken);
|
||||
appSocialAuth.setExpireIn(expireIn);
|
||||
appSocialAuth.setRefreshToken(refreshToken);
|
||||
appSocialAuth.setUpdateTime(new Date());
|
||||
return baseMapper.updateById(appSocialAuth) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteByUserIdAndPlatform(Long userId, String platform) {
|
||||
LambdaQueryWrapper<AppSocialAuth> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AppSocialAuth::getUserId, userId)
|
||||
.eq(AppSocialAuth::getPlatform, platform)
|
||||
.eq(AppSocialAuth::getDelFlag, "0");
|
||||
return baseMapper.delete(wrapper) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppUserVo selectUserByPlatformAndOpenId(String platform, String openId) {
|
||||
if (StringUtils.isBlank(platform) || StringUtils.isBlank(openId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 根据平台和openId查询社交认证记录
|
||||
AppSocialAuth socialAuth = queryByPlatformAndOpenId(platform, openId);
|
||||
if (socialAuth == null || socialAuth.getUserId() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 根据userId查询用户信息
|
||||
return appUserService.queryById(socialAuth.getUserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppUserVo selectUserByPlatformAndUnionId(String platform, String unionId) {
|
||||
if (StringUtils.isBlank(platform) || StringUtils.isBlank(unionId)) {
|
||||
return null;
|
||||
}
|
||||
AppSocialAuth socialAuth = queryByPlatformAndUnionId(platform, unionId);
|
||||
if (socialAuth == null || socialAuth.getUserId() == null) {
|
||||
return null;
|
||||
}
|
||||
return appUserService.queryById(socialAuth.getUserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void socialRegister(me.zhyd.oauth.model.AuthUser authUserData) {
|
||||
if (authUserData == null) {
|
||||
throw new org.dromara.common.core.exception.ServiceException("第三方用户信息不能为空");
|
||||
}
|
||||
|
||||
String platform = authUserData.getSource();
|
||||
String openId = authUserData.getUuid();
|
||||
Long userId = org.dromara.common.satoken.utils.LoginHelper.getUserId();
|
||||
|
||||
if (StringUtils.isBlank(platform) || StringUtils.isBlank(openId)) {
|
||||
throw new org.dromara.common.core.exception.ServiceException("第三方平台信息不完整");
|
||||
}
|
||||
|
||||
log.info("开始绑定第三方账号,用户ID: {}, 平台: {}, openId: {}", userId, platform, openId);
|
||||
|
||||
// 检查是否已经绑定过该第三方账号
|
||||
AppSocialAuth existingSocialAuth = queryByPlatformAndOpenId(platform, openId);
|
||||
if (existingSocialAuth != null) {
|
||||
if (!userId.equals(existingSocialAuth.getUserId())) {
|
||||
log.warn("第三方账号已被其他用户绑定,平台: {}, openId: {}, 绑定用户: {}", platform, openId, existingSocialAuth.getUserId());
|
||||
throw new org.dromara.common.core.exception.ServiceException("此第三方账号已经被其他用户绑定!");
|
||||
} else {
|
||||
log.info("第三方账号已绑定当前用户,无需重复绑定,平台: {}, openId: {}", platform, openId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查当前用户是否已经绑定过该平台的账号
|
||||
List<AppSocialAuthVo> userSocialAuths = queryByUserId(userId);
|
||||
boolean alreadyBound = userSocialAuths.stream()
|
||||
.anyMatch(auth -> platform.equals(auth.getPlatform()));
|
||||
|
||||
if (alreadyBound) {
|
||||
// 如果已经绑定过该平台,则更新绑定信息
|
||||
log.info("用户已绑定该平台账号,更新绑定信息,用户ID: {}, 平台: {}", userId, platform);
|
||||
AppSocialAuth updateAuth = userSocialAuths.stream()
|
||||
.filter(auth -> platform.equals(auth.getPlatform()))
|
||||
.map(vo -> {
|
||||
AppSocialAuth auth = new AppSocialAuth();
|
||||
auth.setId(vo.getId());
|
||||
auth.setUserId(userId);
|
||||
auth.setPlatform(platform);
|
||||
auth.setPlatformUid(authUserData.getUuid());
|
||||
auth.setOpenId(openId);
|
||||
auth.setUnionId(authUserData.getToken() != null ? authUserData.getToken().getUnionId() : null);
|
||||
auth.setAccessToken(authUserData.getToken() != null ? authUserData.getToken().getAccessToken() : null);
|
||||
auth.setExpireIn(authUserData.getToken() != null ? authUserData.getToken().getExpireIn() : null);
|
||||
auth.setRefreshToken(authUserData.getToken() != null ? authUserData.getToken().getRefreshToken() : null);
|
||||
auth.setScope(authUserData.getToken() != null ? authUserData.getToken().getScope() : null);
|
||||
return auth;
|
||||
})
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (updateAuth != null) {
|
||||
boolean success = updateAppSocialAuth(updateAuth);
|
||||
if (success) {
|
||||
log.info("更新第三方账号绑定成功,用户ID: {}, 平台: {}", userId, platform);
|
||||
} else {
|
||||
log.error("更新第三方账号绑定失败,用户ID: {}, 平台: {}", userId, platform);
|
||||
throw new org.dromara.common.core.exception.ServiceException("更新绑定信息失败");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 新增绑定记录
|
||||
log.info("新增第三方账号绑定,用户ID: {}, 平台: {}", userId, platform);
|
||||
AppSocialAuth newAuth = new AppSocialAuth();
|
||||
newAuth.setUserId(userId);
|
||||
newAuth.setPlatform(platform);
|
||||
newAuth.setPlatformUid(authUserData.getUuid());
|
||||
newAuth.setOpenId(openId);
|
||||
newAuth.setUnionId(authUserData.getToken() != null ? authUserData.getToken().getUnionId() : null);
|
||||
newAuth.setAccessToken(authUserData.getToken() != null ? authUserData.getToken().getAccessToken() : null);
|
||||
newAuth.setExpireIn(authUserData.getToken() != null ? authUserData.getToken().getExpireIn() : null);
|
||||
newAuth.setRefreshToken(authUserData.getToken() != null ? authUserData.getToken().getRefreshToken() : null);
|
||||
newAuth.setScope(authUserData.getToken() != null ? authUserData.getToken().getScope() : null);
|
||||
|
||||
boolean success = insertAppSocialAuth(newAuth);
|
||||
if (success) {
|
||||
log.info("新增第三方账号绑定成功,用户ID: {}, 平台: {}", userId, platform);
|
||||
} else {
|
||||
log.error("新增第三方账号绑定失败,用户ID: {}, 平台: {}", userId, platform);
|
||||
throw new org.dromara.common.core.exception.ServiceException("绑定第三方账号失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
package org.dromara.member.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.crypto.digest.BCrypt;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.member.domain.AppUser;
|
||||
import org.dromara.member.domain.AppUserRole;
|
||||
import org.dromara.member.domain.bo.AppUserBo;
|
||||
import org.dromara.member.domain.vo.AppUserVo;
|
||||
import org.dromara.member.mapper.AppUserMapper;
|
||||
import org.dromara.member.mapper.AppUserRoleMapper;
|
||||
import org.dromara.member.service.AppUserService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App端用户信息Service业务层处理
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AppUserServiceImpl extends ServiceImpl<AppUserMapper, AppUser> implements AppUserService {
|
||||
|
||||
private final AppUserRoleMapper appUserRoleMapper;
|
||||
|
||||
|
||||
/**
|
||||
* 查询App端用户信息
|
||||
*/
|
||||
@Override
|
||||
public AppUserVo queryById(Long userId) {
|
||||
return baseMapper.selectVoById(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询App端用户信息列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<AppUserVo> queryPageList(AppUserBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<AppUser> lqw = buildQueryWrapper(bo);
|
||||
Page<AppUserVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询App端用户信息列表
|
||||
*/
|
||||
@Override
|
||||
public List<AppUserVo> queryList(AppUserBo bo) {
|
||||
LambdaQueryWrapper<AppUser> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<AppUser> buildQueryWrapper(AppUserBo bo) {
|
||||
LambdaQueryWrapper<AppUser> lqw = Wrappers.lambdaQuery();
|
||||
lqw.like(StringUtils.isNotBlank(bo.getUserName()), AppUser::getUserName, bo.getUserName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getNickName()), AppUser::getNickName, bo.getNickName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getPhone()), AppUser::getPhone, bo.getPhone());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getEmail()), AppUser::getEmail, bo.getEmail());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getSex()), AppUser::getSex, bo.getSex());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), AppUser::getStatus, bo.getStatus());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增App端用户信息
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(AppUserBo bo) {
|
||||
AppUser add = BeanUtil.toBean(bo, AppUser.class);
|
||||
validEntityBeforeSave(add);
|
||||
// 加密密码
|
||||
if (StringUtils.isNotBlank(add.getPassword())) {
|
||||
add.setPassword(BCrypt.hashpw(add.getPassword()));
|
||||
}
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setUserId(add.getUserId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改App端用户信息
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(AppUserBo bo) {
|
||||
AppUser update = BeanUtil.toBean(bo, AppUser.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(AppUser entity) {
|
||||
// TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除App端用户信息
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户账号查询用户信息
|
||||
*/
|
||||
@Override
|
||||
public AppUserVo selectUserByUserName(String userName) {
|
||||
return baseMapper.selectUserByUserName(userName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据手机号查询用户信息
|
||||
*/
|
||||
@Override
|
||||
public AppUserVo selectUserByPhone(String phone) {
|
||||
return baseMapper.selectUserByPhone(phone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据邮箱查询用户信息
|
||||
*/
|
||||
@Override
|
||||
public AppUserVo selectUserByEmail(String email) {
|
||||
return baseMapper.selectUserByEmail(email);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验用户账号是否唯一
|
||||
*/
|
||||
@Override
|
||||
public boolean checkUserNameUnique(String userName) {
|
||||
return baseMapper.checkUserNameUnique(userName) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验手机号码是否唯一
|
||||
*/
|
||||
@Override
|
||||
public boolean checkPhoneUnique(String phone) {
|
||||
return baseMapper.checkPhoneUnique(phone) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验email是否唯一
|
||||
*/
|
||||
@Override
|
||||
public boolean checkEmailUnique(String email) {
|
||||
return baseMapper.checkEmailUnique(email) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean register(AppUserBo bo) {
|
||||
// 校验账号唯一性
|
||||
if (!checkUserNameUnique(bo.getUserName())) {
|
||||
throw new RuntimeException("用户账号已存在");
|
||||
}
|
||||
// 校验手机号唯一性
|
||||
if (StringUtils.isNotBlank(bo.getPhone()) && !checkPhoneUnique(bo.getPhone())) {
|
||||
throw new RuntimeException("手机号已存在");
|
||||
}
|
||||
// 校验邮箱唯一性
|
||||
if (StringUtils.isNotBlank(bo.getEmail()) && !checkEmailUnique(bo.getEmail())) {
|
||||
throw new RuntimeException("邮箱已存在");
|
||||
}
|
||||
boolean result = insertByBo(bo);
|
||||
if (result) {
|
||||
// 分配默认角色
|
||||
AppUserRole userRole = new AppUserRole();
|
||||
userRole.setUserId(bo.getUserId());
|
||||
userRole.setRoleId(1L); // 默认角色ID为1 (App普通用户)
|
||||
appUserRoleMapper.insert(userRole);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户密码
|
||||
*/
|
||||
@Override
|
||||
public Boolean updatePassword(Long userId, String oldPassword, String newPassword) {
|
||||
AppUser user = baseMapper.selectById(userId);
|
||||
if (ObjectUtil.isNull(user)) {
|
||||
throw new RuntimeException("用户不存在");
|
||||
}
|
||||
if (!BCrypt.checkpw(oldPassword, user.getPassword())) {
|
||||
throw new RuntimeException("旧密码错误");
|
||||
}
|
||||
user.setPassword(BCrypt.hashpw(newPassword));
|
||||
return baseMapper.updateById(user) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置用户密码
|
||||
*/
|
||||
@Override
|
||||
public Boolean resetPassword(Long userId, String newPassword) {
|
||||
AppUser user = new AppUser();
|
||||
user.setUserId(userId);
|
||||
user.setPassword(BCrypt.hashpw(newPassword));
|
||||
return baseMapper.updateById(user) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户状态
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateUserStatus(Long userId, String status) {
|
||||
return baseMapper.update(null,
|
||||
new LambdaUpdateWrapper<AppUser>()
|
||||
.set(AppUser::getStatus, status)
|
||||
.eq(AppUser::getUserId, userId)) > 0;
|
||||
}
|
||||
|
||||
}
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
package org.dromara.member.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.member.domain.AppVersion;
|
||||
import org.dromara.member.domain.bo.AppVersionBo;
|
||||
import org.dromara.member.domain.vo.AppVersionVo;
|
||||
import org.dromara.member.exception.VersionException;
|
||||
import org.dromara.member.mapper.AppVersionMapper;
|
||||
import org.dromara.member.service.AppVersionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App版本信息Service业务层处理
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class AppVersionServiceImpl extends ServiceImpl<AppVersionMapper, AppVersion> implements AppVersionService {
|
||||
|
||||
private final AppVersionMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询App版本信息
|
||||
*/
|
||||
@Override
|
||||
public AppVersionVo queryById(Long versionId) {
|
||||
return baseMapper.selectVoById(versionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询App版本信息列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<AppVersionVo> queryPageList(AppVersionBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<AppVersion> lqw = buildQueryWrapper(bo);
|
||||
Page<AppVersionVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询App版本信息列表
|
||||
*/
|
||||
@Override
|
||||
public List<AppVersionVo> queryList(AppVersionBo bo) {
|
||||
LambdaQueryWrapper<AppVersion> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<AppVersion> buildQueryWrapper(AppVersionBo bo) {
|
||||
LambdaQueryWrapper<AppVersion> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getVersionCode() != null, AppVersion::getVersionCode, bo.getVersionCode());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getVersionName()), AppVersion::getVersionName, bo.getVersionName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getPlatform()), AppVersion::getPlatform, bo.getPlatform());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getIsForce()), AppVersion::getIsForce, bo.getIsForce());
|
||||
lqw.orderByDesc(AppVersion::getVersionCode);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增App版本信息
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(AppVersionBo bo) {
|
||||
AppVersion add = BeanUtil.toBean(bo, AppVersion.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setVersionId(add.getVersionId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改App版本信息
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(AppVersionBo bo) {
|
||||
AppVersion update = BeanUtil.toBean(bo, AppVersion.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(AppVersion entity) {
|
||||
// 校验版本号唯一性
|
||||
if (entity.getVersionCode() != null && StringUtils.isNotBlank(entity.getPlatform())) {
|
||||
LambdaQueryWrapper<AppVersion> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppVersion::getVersionCode, entity.getVersionCode());
|
||||
lqw.eq(AppVersion::getPlatform, entity.getPlatform());
|
||||
if (entity.getVersionId() != null) {
|
||||
lqw.ne(AppVersion::getVersionId, entity.getVersionId());
|
||||
}
|
||||
|
||||
long count = baseMapper.selectCount(lqw);
|
||||
if (count > 0) {
|
||||
throw new RuntimeException("该平台下版本号已存在");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除App版本信息
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查版本更新
|
||||
*/
|
||||
@Override
|
||||
public AppVersionVo checkUpdate(String platform, Integer currentVersionCode) {
|
||||
if (StringUtils.isBlank(platform)) {
|
||||
throw VersionException.unsupportedPlatform(platform);
|
||||
}
|
||||
if (currentVersionCode == null || currentVersionCode <= 0) {
|
||||
throw VersionException.invalidVersionCode(currentVersionCode);
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<AppVersion> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppVersion::getPlatform, platform);
|
||||
lqw.gt(AppVersion::getVersionCode, currentVersionCode);
|
||||
lqw.orderByDesc(AppVersion::getVersionCode);
|
||||
lqw.last("LIMIT 1");
|
||||
|
||||
return baseMapper.selectVoOne(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定平台的最新版本
|
||||
*/
|
||||
@Override
|
||||
public AppVersionVo getLatestVersion(String platform) {
|
||||
if (StringUtils.isBlank(platform)) {
|
||||
throw VersionException.unsupportedPlatform(platform);
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<AppVersion> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppVersion::getPlatform, platform);
|
||||
lqw.orderByDesc(AppVersion::getVersionCode);
|
||||
lqw.last("LIMIT 1");
|
||||
|
||||
AppVersionVo result = baseMapper.selectVoOne(lqw);
|
||||
if (result == null) {
|
||||
throw VersionException.versionNotFound("平台 " + platform + " 暂无可用版本");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查版本号是否唯一
|
||||
*/
|
||||
@Override
|
||||
public Boolean checkVersionCodeUnique(AppVersionBo bo) {
|
||||
if (bo.getVersionCode() == null || bo.getVersionCode() <= 0) {
|
||||
throw VersionException.invalidVersionCode(bo.getVersionCode());
|
||||
}
|
||||
if (StringUtils.isBlank(bo.getPlatform())) {
|
||||
throw VersionException.unsupportedPlatform(bo.getPlatform());
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<AppVersion> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppVersion::getVersionCode, bo.getVersionCode());
|
||||
lqw.eq(AppVersion::getPlatform, bo.getPlatform());
|
||||
if (bo.getVersionId() != null) {
|
||||
lqw.ne(AppVersion::getVersionId, bo.getVersionId());
|
||||
}
|
||||
|
||||
boolean isUnique = baseMapper.selectCount(lqw) == 0;
|
||||
if (!isUnique) {
|
||||
throw VersionException.versionCodeDuplicate(bo.getVersionCode());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取版本历史列表
|
||||
*/
|
||||
@Override
|
||||
public List<AppVersionVo> getVersionHistory(String platform, Integer limit) {
|
||||
if (StringUtils.isBlank(platform)) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
if (limit == null || limit <= 0) {
|
||||
limit = 10; // 默认返回10个版本
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<AppVersion> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppVersion::getPlatform, platform);
|
||||
lqw.orderByDesc(AppVersion::getVersionCode);
|
||||
lqw.last("LIMIT " + limit);
|
||||
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否需要强制更新
|
||||
*/
|
||||
@Override
|
||||
public Boolean checkForceUpdate(String platform, Integer currentVersionCode) {
|
||||
if (StringUtils.isBlank(platform)) {
|
||||
throw VersionException.unsupportedPlatform(platform);
|
||||
}
|
||||
if (currentVersionCode == null || currentVersionCode <= 0) {
|
||||
throw VersionException.invalidVersionCode(currentVersionCode);
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<AppVersion> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppVersion::getPlatform, platform);
|
||||
lqw.gt(AppVersion::getVersionCode, currentVersionCode);
|
||||
lqw.eq(AppVersion::getIsForce, "1");
|
||||
|
||||
return baseMapper.selectCount(lqw) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取版本更新信息
|
||||
*/
|
||||
@Override
|
||||
public AppVersionVo getUpdateInfo(String platform, Integer currentVersionCode) {
|
||||
AppVersionVo latestVersion = checkUpdate(platform, currentVersionCode);
|
||||
if (latestVersion == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查是否有强制更新版本
|
||||
Boolean forceUpdate = checkForceUpdate(platform, currentVersionCode);
|
||||
if (forceUpdate) {
|
||||
// 如果有强制更新,返回最新的强制更新版本
|
||||
LambdaQueryWrapper<AppVersion> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(AppVersion::getPlatform, platform);
|
||||
lqw.gt(AppVersion::getVersionCode, currentVersionCode);
|
||||
lqw.eq(AppVersion::getIsForce, "1");
|
||||
lqw.orderByDesc(AppVersion::getVersionCode);
|
||||
lqw.last("LIMIT 1");
|
||||
|
||||
AppVersionVo forceVersion = baseMapper.selectVoOne(lqw);
|
||||
return forceVersion != null ? forceVersion : latestVersion;
|
||||
}
|
||||
|
||||
return latestVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量发布版本
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean batchPublish(List<Long> versionIds) {
|
||||
if (ObjectUtil.isEmpty(versionIds)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 这里可以添加发布逻辑,比如更新状态等
|
||||
log.info("批量发布版本: {}", versionIds);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤回版本
|
||||
*/
|
||||
@Override
|
||||
public Boolean withdrawVersion(Long versionId) {
|
||||
if (versionId == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 这里可以添加撤回逻辑,比如更新状态等
|
||||
log.info("撤回版本: {}", versionId);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package org.dromara.member.utils;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
import java.util.Base64;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* JWT工具类
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public class JwtUtil {
|
||||
private final String secret;
|
||||
|
||||
public JwtUtil(String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
public String generateToken(String subject, long ttlSeconds, String jti) {
|
||||
long now = Instant.now().getEpochSecond();
|
||||
long exp = now + ttlSeconds;
|
||||
Map<String, Object> header = new LinkedHashMap<>();
|
||||
header.put("alg", "HS256");
|
||||
header.put("typ", "JWT");
|
||||
Map<String, Object> payload = new LinkedHashMap<>();
|
||||
payload.put("iss", "ruoyi-app");
|
||||
payload.put("sub", subject);
|
||||
payload.put("iat", now);
|
||||
payload.put("exp", exp);
|
||||
payload.put("jti", jti == null ? UUID.randomUUID().toString() : jti);
|
||||
String h = base64Url(Json.write(header));
|
||||
String p = base64Url(Json.write(payload));
|
||||
String signing = h + "." + p;
|
||||
String sig = base64Url(hmacSha256(signing, secret));
|
||||
return signing + "." + sig;
|
||||
}
|
||||
|
||||
public boolean verify(String token) {
|
||||
try {
|
||||
String[] parts = token.split("\\.");
|
||||
if (parts.length != 3) return false;
|
||||
String signing = parts[0] + "." + parts[1];
|
||||
String calc = base64Url(hmacSha256(signing, secret));
|
||||
return slowEquals(calc, parts[2]);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> parsePayload(String token) {
|
||||
String[] parts = token.split("\\.");
|
||||
if (parts.length != 3) return Map.of();
|
||||
String json = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8);
|
||||
return Json.read(json);
|
||||
}
|
||||
|
||||
private static boolean slowEquals(String a, String b) {
|
||||
if (a == null || b == null) return false;
|
||||
if (a.length() != b.length()) return false;
|
||||
int r = 0;
|
||||
for (int i = 0; i < a.length(); i++) r |= a.charAt(i) ^ b.charAt(i);
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
private static byte[] hmacSha256(String data, String key) {
|
||||
try {
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
|
||||
return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String base64Url(String s) {
|
||||
return Base64.getUrlEncoder().withoutPadding().encodeToString(s.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private static String base64Url(byte[] b) {
|
||||
return Base64.getUrlEncoder().withoutPadding().encodeToString(b);
|
||||
}
|
||||
|
||||
static class Json {
|
||||
public static String write(Map<String, Object> map) {
|
||||
StringBuilder sb = new StringBuilder("{");
|
||||
boolean first = true;
|
||||
for (Map.Entry<String, Object> e : map.entrySet()) {
|
||||
if (!first) sb.append(",");
|
||||
sb.append("\"").append(e.getKey()).append("\":");
|
||||
Object v = e.getValue();
|
||||
if (v instanceof Number || v instanceof Boolean) {
|
||||
sb.append(v.toString());
|
||||
} else {
|
||||
sb.append("\"").append(String.valueOf(v).replace("\"", "\\\"")).append("\"");
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<String, Object> read(String json) {
|
||||
try {
|
||||
return org.dromara.common.json.utils.JsonUtils.parseObject(json, Map.class);
|
||||
} catch (Exception e) {
|
||||
return Map.of();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.member.mapper.AppDeviceMapper">
|
||||
|
||||
<resultMap type="org.dromara.member.domain.AppDevice" id="AppDeviceResult">
|
||||
<id property="deviceId" column="device_id"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="deviceType" column="device_type"/>
|
||||
<result property="deviceName" column="device_name"/>
|
||||
<result property="deviceModel" column="device_model"/>
|
||||
<result property="deviceBrand" column="device_brand"/>
|
||||
<result property="osVersion" column="os_version"/>
|
||||
<result property="appVersion" column="app_version"/>
|
||||
<result property="pushToken" column="push_token"/>
|
||||
<result property="isActive" column="is_active"/>
|
||||
<result property="lastActiveTime" column="last_active_time"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap type="org.dromara.member.domain.vo.AppDeviceVo" id="AppDeviceVoResult">
|
||||
<id property="deviceId" column="device_id"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="deviceType" column="device_type"/>
|
||||
<result property="deviceName" column="device_name"/>
|
||||
<result property="deviceModel" column="device_model"/>
|
||||
<result property="deviceBrand" column="device_brand"/>
|
||||
<result property="osVersion" column="os_version"/>
|
||||
<result property="appVersion" column="app_version"/>
|
||||
<result property="pushToken" column="push_token"/>
|
||||
<result property="isActive" column="is_active"/>
|
||||
<result property="lastActiveTime" column="last_active_time"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectAppDeviceVo">
|
||||
select device_id,
|
||||
user_id,
|
||||
device_type,
|
||||
device_name,
|
||||
device_model,
|
||||
device_brand,
|
||||
os_version,
|
||||
app_version,
|
||||
push_token,
|
||||
is_active,
|
||||
last_active_time,
|
||||
create_time,
|
||||
update_time
|
||||
from app_device
|
||||
</sql>
|
||||
|
||||
<!-- 查询设备列表 -->
|
||||
<select id="selectAppDeviceList" parameterType="AppDevice" resultMap="AppDeviceVoResult">
|
||||
<include refid="selectAppDeviceVo"/>
|
||||
<where>
|
||||
<if test="userId != null">and user_id = #{userId}</if>
|
||||
<if test="deviceType != null and deviceType != ''">and device_type = #{deviceType}</if>
|
||||
<if test="deviceName != null and deviceName != ''">and device_name like concat('%', #{deviceName}, '%')</if>
|
||||
<if test="isActive != null">and is_active = #{isActive}</if>
|
||||
</where>
|
||||
order by create_time desc
|
||||
</select>
|
||||
|
||||
<!-- 根据设备ID查询设备信息 -->
|
||||
<select id="selectAppDeviceByDeviceId" parameterType="Long" resultMap="AppDeviceVoResult">
|
||||
<include refid="selectAppDeviceVo"/>
|
||||
where device_id = #{deviceId}
|
||||
</select>
|
||||
|
||||
<!-- 根据用户ID查询设备列表 -->
|
||||
<select id="selectAppDeviceByUserId" parameterType="Long" resultMap="AppDeviceVoResult">
|
||||
<include refid="selectAppDeviceVo"/>
|
||||
where user_id = #{userId} and is_active = '1'
|
||||
order by last_active_time desc
|
||||
</select>
|
||||
|
||||
<!-- 根据推送令牌查询设备 -->
|
||||
<select id="selectAppDeviceByPushToken" parameterType="String" resultMap="AppDeviceResult">
|
||||
<include refid="selectAppDeviceVo"/>
|
||||
where push_token = #{pushToken} and is_active = '1'
|
||||
</select>
|
||||
|
||||
<!-- 新增设备信息 -->
|
||||
<insert id="insertAppDevice" parameterType="org.dromara.member.domain.AppDevice" useGeneratedKeys="true"
|
||||
keyProperty="deviceId">
|
||||
insert into app_device
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="userId != null">user_id,</if>
|
||||
<if test="deviceType != null and deviceType != ''">device_type,</if>
|
||||
<if test="deviceName != null and deviceName != ''">device_name,</if>
|
||||
<if test="deviceModel != null and deviceModel != ''">device_model,</if>
|
||||
<if test="deviceBrand != null and deviceBrand != ''">device_brand,</if>
|
||||
<if test="osVersion != null and osVersion != ''">os_version,</if>
|
||||
<if test="appVersion != null and appVersion != ''">app_version,</if>
|
||||
<if test="pushToken != null and pushToken != ''">push_token,</if>
|
||||
<if test="isActive != null">is_active,</if>
|
||||
<if test="lastActiveTime != null">last_active_time,</if>
|
||||
<if test="createTime != null">create_time,</if>
|
||||
<if test="updateTime != null">update_time,</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="userId != null">#{userId},</if>
|
||||
<if test="deviceType != null and deviceType != ''">#{deviceType},</if>
|
||||
<if test="deviceName != null and deviceName != ''">#{deviceName},</if>
|
||||
<if test="deviceModel != null and deviceModel != ''">#{deviceModel},</if>
|
||||
<if test="deviceBrand != null and deviceBrand != ''">#{deviceBrand},</if>
|
||||
<if test="osVersion != null and osVersion != ''">#{osVersion},</if>
|
||||
<if test="appVersion != null and appVersion != ''">#{appVersion},</if>
|
||||
<if test="pushToken != null and pushToken != ''">#{pushToken},</if>
|
||||
<if test="isActive != null">#{isActive},</if>
|
||||
<if test="lastActiveTime != null">#{lastActiveTime},</if>
|
||||
<if test="createTime != null">#{createTime},</if>
|
||||
<if test="updateTime != null">#{updateTime},</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<!-- 修改设备信息 -->
|
||||
<update id="updateAppDevice" parameterType="org.dromara.member.domain.AppDevice">
|
||||
update app_device
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="deviceType != null and deviceType != ''">device_type = #{deviceType},</if>
|
||||
<if test="deviceName != null and deviceName != ''">device_name = #{deviceName},</if>
|
||||
<if test="deviceModel != null and deviceModel != ''">device_model = #{deviceModel},</if>
|
||||
<if test="deviceBrand != null and deviceBrand != ''">device_brand = #{deviceBrand},</if>
|
||||
<if test="osVersion != null and osVersion != ''">os_version = #{osVersion},</if>
|
||||
<if test="appVersion != null and appVersion != ''">app_version = #{appVersion},</if>
|
||||
<if test="pushToken != null and pushToken != ''">push_token = #{pushToken},</if>
|
||||
<if test="isActive != null">is_active = #{isActive},</if>
|
||||
<if test="lastActiveTime != null">last_active_time = #{lastActiveTime},</if>
|
||||
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||
</trim>
|
||||
where device_id = #{deviceId}
|
||||
</update>
|
||||
|
||||
<!-- 删除设备信息 -->
|
||||
<delete id="deleteAppDeviceByDeviceId" parameterType="Long">
|
||||
delete
|
||||
from app_device
|
||||
where device_id = #{deviceId}
|
||||
</delete>
|
||||
|
||||
<!-- 批量删除设备信息 -->
|
||||
<delete id="deleteAppDeviceByDeviceIds" parameterType="String">
|
||||
delete from app_device where device_id in
|
||||
<foreach item="deviceId" collection="array" open="(" separator="," close=")">
|
||||
#{deviceId}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<!-- 更新设备活跃状态 -->
|
||||
<update id="updateDeviceActiveStatus">
|
||||
update app_device
|
||||
set is_active = #{isActive},
|
||||
last_active_time = #{lastActiveTime}
|
||||
where device_id = #{deviceId}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,166 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.member.mapper.AppFileMapper">
|
||||
|
||||
<resultMap type="org.dromara.member.domain.AppFile" id="AppFileResult">
|
||||
<result property="fileId" column="file_id"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="fileName" column="file_name"/>
|
||||
<result property="originalName" column="original_name"/>
|
||||
<result property="filePath" column="file_path"/>
|
||||
<result property="fileUrl" column="file_url"/>
|
||||
<result property="fileSize" column="file_size"/>
|
||||
<result property="fileType" column="file_type"/>
|
||||
<result property="fileSuffix" column="file_suffix"/>
|
||||
<result property="fileCategory" column="file_category"/>
|
||||
<result property="storageService" column="storage_service"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="downloadCount" column="download_count"/>
|
||||
<result property="isPublic" column="is_public"/>
|
||||
<result property="fileMd5" column="file_md5"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectAppFileVo">
|
||||
select file_id,
|
||||
user_id,
|
||||
file_name,
|
||||
original_name,
|
||||
file_path,
|
||||
file_url,
|
||||
file_size,
|
||||
file_type,
|
||||
file_suffix,
|
||||
file_category,
|
||||
storage_service,
|
||||
status,
|
||||
download_count,
|
||||
is_public,
|
||||
file_md5,
|
||||
remark,
|
||||
create_by,
|
||||
create_time,
|
||||
update_by,
|
||||
update_time
|
||||
from app_file
|
||||
</sql>
|
||||
|
||||
<select id="selectAppFileList" parameterType="org.dromara.member.domain.AppFile" resultMap="AppFileResult">
|
||||
<include refid="selectAppFileVo"/>
|
||||
<where>
|
||||
<if test="userId != null ">and user_id = #{userId}</if>
|
||||
<if test="fileName != null and fileName != ''">and file_name like concat('%', #{fileName}, '%')</if>
|
||||
<if test="originalName != null and originalName != ''">and original_name like concat('%', #{originalName},
|
||||
'%')
|
||||
</if>
|
||||
<if test="filePath != null and filePath != ''">and file_path = #{filePath}</if>
|
||||
<if test="fileUrl != null and fileUrl != ''">and file_url = #{fileUrl}</if>
|
||||
<if test="fileSize != null ">and file_size = #{fileSize}</if>
|
||||
<if test="fileType != null and fileType != ''">and file_type = #{fileType}</if>
|
||||
<if test="fileSuffix != null and fileSuffix != ''">and file_suffix = #{fileSuffix}</if>
|
||||
<if test="fileCategory != null ">and file_category = #{fileCategory}</if>
|
||||
<if test="storageService != null and storageService != ''">and storage_service = #{storageService}</if>
|
||||
<if test="status != null and status != ''">and status = #{status}</if>
|
||||
<if test="downloadCount != null ">and download_count = #{downloadCount}</if>
|
||||
<if test="isPublic != null and isPublic != ''">and is_public = #{isPublic}</if>
|
||||
<if test="fileMd5 != null and fileMd5 != ''">and file_md5 = #{fileMd5}</if>
|
||||
</where>
|
||||
order by create_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectAppFileByFileId" parameterType="Long" resultMap="AppFileResult">
|
||||
<include refid="selectAppFileVo"/>
|
||||
where file_id = #{fileId}
|
||||
</select>
|
||||
|
||||
<insert id="insertAppFile" parameterType="org.dromara.member.domain.AppFile" useGeneratedKeys="true"
|
||||
keyProperty="fileId">
|
||||
insert into app_file
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="userId != null">user_id,</if>
|
||||
<if test="fileName != null and fileName != ''">file_name,</if>
|
||||
<if test="originalName != null and originalName != ''">original_name,</if>
|
||||
<if test="filePath != null and filePath != ''">file_path,</if>
|
||||
<if test="fileUrl != null and fileUrl != ''">file_url,</if>
|
||||
<if test="fileSize != null">file_size,</if>
|
||||
<if test="fileType != null and fileType != ''">file_type,</if>
|
||||
<if test="fileSuffix != null and fileSuffix != ''">file_suffix,</if>
|
||||
<if test="fileCategory != null">file_category,</if>
|
||||
<if test="storageService != null and storageService != ''">storage_service,</if>
|
||||
<if test="status != null and status != ''">status,</if>
|
||||
<if test="downloadCount != null">download_count,</if>
|
||||
<if test="isPublic != null and isPublic != ''">is_public,</if>
|
||||
<if test="fileMd5 != null and fileMd5 != ''">file_md5,</if>
|
||||
<if test="remark != null">remark,</if>
|
||||
<if test="createBy != null">create_by,</if>
|
||||
<if test="createTime != null">create_time,</if>
|
||||
<if test="updateBy != null">update_by,</if>
|
||||
<if test="updateTime != null">update_time,</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="userId != null">#{userId},</if>
|
||||
<if test="fileName != null and fileName != ''">#{fileName},</if>
|
||||
<if test="originalName != null and originalName != ''">#{originalName},</if>
|
||||
<if test="filePath != null and filePath != ''">#{filePath},</if>
|
||||
<if test="fileUrl != null and fileUrl != ''">#{fileUrl},</if>
|
||||
<if test="fileSize != null">#{fileSize},</if>
|
||||
<if test="fileType != null and fileType != ''">#{fileType},</if>
|
||||
<if test="fileSuffix != null and fileSuffix != ''">#{fileSuffix},</if>
|
||||
<if test="fileCategory != null">#{fileCategory},</if>
|
||||
<if test="storageService != null and storageService != ''">#{storageService},</if>
|
||||
<if test="status != null and status != ''">#{status},</if>
|
||||
<if test="downloadCount != null">#{downloadCount},</if>
|
||||
<if test="isPublic != null and isPublic != ''">#{isPublic},</if>
|
||||
<if test="fileMd5 != null and fileMd5 != ''">#{fileMd5},</if>
|
||||
<if test="remark != null">#{remark},</if>
|
||||
<if test="createBy != null">#{createBy},</if>
|
||||
<if test="createTime != null">#{createTime},</if>
|
||||
<if test="updateBy != null">#{updateBy},</if>
|
||||
<if test="updateTime != null">#{updateTime},</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<update id="updateAppFile" parameterType="org.dromara.member.domain.AppFile">
|
||||
update app_file
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="userId != null">user_id = #{userId},</if>
|
||||
<if test="fileName != null and fileName != ''">file_name = #{fileName},</if>
|
||||
<if test="originalName != null and originalName != ''">original_name = #{originalName},</if>
|
||||
<if test="filePath != null and filePath != ''">file_path = #{filePath},</if>
|
||||
<if test="fileUrl != null and fileUrl != ''">file_url = #{fileUrl},</if>
|
||||
<if test="fileSize != null">file_size = #{fileSize},</if>
|
||||
<if test="fileType != null and fileType != ''">file_type = #{fileType},</if>
|
||||
<if test="fileSuffix != null and fileSuffix != ''">file_suffix = #{fileSuffix},</if>
|
||||
<if test="fileCategory != null">file_category = #{fileCategory},</if>
|
||||
<if test="storageService != null and storageService != ''">storage_service = #{storageService},</if>
|
||||
<if test="status != null and status != ''">status = #{status},</if>
|
||||
<if test="downloadCount != null">download_count = #{downloadCount},</if>
|
||||
<if test="isPublic != null and isPublic != ''">is_public = #{isPublic},</if>
|
||||
<if test="fileMd5 != null and fileMd5 != ''">file_md5 = #{fileMd5},</if>
|
||||
<if test="remark != null">remark = #{remark},</if>
|
||||
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||
</trim>
|
||||
where file_id = #{fileId}
|
||||
</update>
|
||||
|
||||
<delete id="deleteAppFileByFileId" parameterType="Long">
|
||||
delete
|
||||
from app_file
|
||||
where file_id = #{fileId}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteAppFileByFileIds" parameterType="String">
|
||||
delete from app_file where file_id in
|
||||
<foreach item="fileId" collection="array" open="(" separator="," close=")">
|
||||
#{fileId}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,128 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.member.mapper.AppLoginLogMapper">
|
||||
|
||||
<resultMap type="org.dromara.member.domain.AppLoginLog" id="AppLoginLogResult">
|
||||
<id property="infoId" column="info_id"/>
|
||||
<result property="userName" column="user_name"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="ipaddr" column="ipaddr"/>
|
||||
<result property="loginLocation" column="login_location"/>
|
||||
<result property="browser" column="browser"/>
|
||||
<result property="os" column="os"/>
|
||||
<result property="msg" column="msg"/>
|
||||
<result property="loginTime" column="login_time"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap type="org.dromara.member.domain.vo.AppLoginLogVo" id="AppLoginLogVoResult">
|
||||
<id property="infoId" column="info_id"/>
|
||||
<result property="userName" column="user_name"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="ipaddr" column="ipaddr"/>
|
||||
<result property="loginLocation" column="login_location"/>
|
||||
<result property="browser" column="browser"/>
|
||||
<result property="os" column="os"/>
|
||||
<result property="msg" column="msg"/>
|
||||
<result property="loginTime" column="login_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectAppLoginLogVo">
|
||||
select info_id,
|
||||
user_name,
|
||||
status,
|
||||
ipaddr,
|
||||
login_location,
|
||||
browser,
|
||||
os,
|
||||
msg,
|
||||
login_time
|
||||
from app_login_log
|
||||
</sql>
|
||||
|
||||
<!-- 查询登录日志列表 -->
|
||||
<select id="selectAppLoginLogList" parameterType="AppLoginLog" resultMap="AppLoginLogVoResult">
|
||||
<include refid="selectAppLoginLogVo"/>
|
||||
<where>
|
||||
<if test="userName != null and userName != ''">and user_name like concat('%', #{userName}, '%')</if>
|
||||
<if test="status != null and status != ''">and status = #{status}</if>
|
||||
<if test="ipaddr != null and ipaddr != ''">and ipaddr like concat('%', #{ipaddr}, '%')</if>
|
||||
<if test="loginLocation != null and loginLocation != ''">and login_location like concat('%',
|
||||
#{loginLocation}, '%')
|
||||
</if>
|
||||
<if test="params.beginTime != null and params.beginTime != ''">and login_time >= #{params.beginTime}</if>
|
||||
<if test="params.endTime != null and params.endTime != ''">and login_time <= #{params.endTime}</if>
|
||||
</where>
|
||||
order by login_time desc
|
||||
</select>
|
||||
|
||||
<!-- 根据ID查询登录日志 -->
|
||||
<select id="selectAppLoginLogByInfoId" parameterType="Long" resultMap="AppLoginLogVoResult">
|
||||
<include refid="selectAppLoginLogVo"/>
|
||||
where info_id = #{infoId}
|
||||
</select>
|
||||
|
||||
<!-- 根据用户名查询登录日志 -->
|
||||
<select id="selectAppLoginLogByUserName" parameterType="String" resultMap="AppLoginLogVoResult">
|
||||
<include refid="selectAppLoginLogVo"/>
|
||||
where user_name = #{userName}
|
||||
order by login_time desc
|
||||
</select>
|
||||
|
||||
<!-- 新增登录日志 -->
|
||||
<insert id="insertAppLoginLog" parameterType="org.dromara.member.domain.AppLoginLog" useGeneratedKeys="true"
|
||||
keyProperty="infoId">
|
||||
insert into app_login_log
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="userName != null and userName != ''">user_name,</if>
|
||||
<if test="status != null and status != ''">status,</if>
|
||||
<if test="ipaddr != null and ipaddr != ''">ipaddr,</if>
|
||||
<if test="loginLocation != null and loginLocation != ''">login_location,</if>
|
||||
<if test="browser != null and browser != ''">browser,</if>
|
||||
<if test="os != null and os != ''">os,</if>
|
||||
<if test="msg != null and msg != ''">msg,</if>
|
||||
<if test="loginTime != null">login_time,</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="userName != null and userName != ''">#{userName},</if>
|
||||
<if test="status != null and status != ''">#{status},</if>
|
||||
<if test="ipaddr != null and ipaddr != ''">#{ipaddr},</if>
|
||||
<if test="loginLocation != null and loginLocation != ''">#{loginLocation},</if>
|
||||
<if test="browser != null and browser != ''">#{browser},</if>
|
||||
<if test="os != null and os != ''">#{os},</if>
|
||||
<if test="msg != null and msg != ''">#{msg},</if>
|
||||
<if test="loginTime != null">#{loginTime},</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<!-- 删除登录日志 -->
|
||||
<delete id="deleteAppLoginLogByInfoId" parameterType="Long">
|
||||
delete
|
||||
from app_login_log
|
||||
where info_id = #{infoId}
|
||||
</delete>
|
||||
|
||||
<!-- 批量删除登录日志 -->
|
||||
<delete id="deleteAppLoginLogByInfoIds" parameterType="String">
|
||||
delete from app_login_log where info_id in
|
||||
<foreach item="infoId" collection="array" open="(" separator="," close=")">
|
||||
#{infoId}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<!-- 清空登录日志 -->
|
||||
<delete id="cleanAppLoginLog">
|
||||
truncate table app_login_log
|
||||
</delete>
|
||||
|
||||
<!-- 根据时间范围删除登录日志 -->
|
||||
<delete id="deleteAppLoginLogByTime">
|
||||
delete from app_login_log
|
||||
<where>
|
||||
<if test="beginTime != null and beginTime != ''">and login_time >= #{beginTime}</if>
|
||||
<if test="endTime != null and endTime != ''">and login_time <= #{endTime}</if>
|
||||
</where>
|
||||
</delete>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,175 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.member.mapper.AppMessageMapper">
|
||||
|
||||
<resultMap type="org.dromara.member.domain.AppMessage" id="AppMessageResult">
|
||||
<result property="messageId" column="message_id"/>
|
||||
<result property="title" column="title"/>
|
||||
<result property="content" column="content"/>
|
||||
<result property="messageType" column="message_type"/>
|
||||
<result property="pushTarget" column="push_target"/>
|
||||
<result property="targetIds" column="target_ids"/>
|
||||
<result property="sendTime" column="send_time"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap type="org.dromara.member.domain.vo.AppMessageVo" id="AppMessageVoResult">
|
||||
<result property="messageId" column="message_id"/>
|
||||
<result property="title" column="title"/>
|
||||
<result property="content" column="content"/>
|
||||
<result property="messageType" column="message_type"/>
|
||||
<result property="pushTarget" column="push_target"/>
|
||||
<result property="targetIds" column="target_ids"/>
|
||||
<result property="sendTime" column="send_time"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectAppMessageVo">
|
||||
select message_id,
|
||||
title,
|
||||
content,
|
||||
message_type,
|
||||
push_target,
|
||||
target_ids,
|
||||
send_time,
|
||||
status,
|
||||
create_by,
|
||||
create_time,
|
||||
update_by,
|
||||
update_time,
|
||||
remark
|
||||
from app_message
|
||||
</sql>
|
||||
|
||||
<select id="selectMessagesByUserId" parameterType="Long" resultMap="AppMessageResult">
|
||||
<include refid="selectAppMessageVo"/>
|
||||
where (push_target = 'user' and FIND_IN_SET(#{userId}, target_ids))
|
||||
or push_target = 'all'
|
||||
order by send_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectMessagesByRoleId" parameterType="Long" resultMap="AppMessageResult">
|
||||
<include refid="selectAppMessageVo"/>
|
||||
where push_target = 'role' and FIND_IN_SET(#{roleId}, target_ids)
|
||||
order by send_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectMessagesForAll" resultMap="AppMessageResult">
|
||||
<include refid="selectAppMessageVo"/>
|
||||
where push_target = 'all'
|
||||
order by send_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectAppMessageList" parameterType="AppMessage" resultMap="AppMessageVoResult">
|
||||
<include refid="selectAppMessageVo"/>
|
||||
<where>
|
||||
<if test="title != null and title != ''">and title like concat('%', #{title}, '%')</if>
|
||||
<if test="messageType != null and messageType != ''">and message_type = #{messageType}</if>
|
||||
<if test="pushTarget != null and pushTarget != ''">and push_target = #{pushTarget}</if>
|
||||
<if test="status != null and status != ''">and status = #{status}</if>
|
||||
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
|
||||
and date_format(send_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d')
|
||||
</if>
|
||||
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
|
||||
and date_format(send_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d')
|
||||
</if>
|
||||
</where>
|
||||
order by send_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectAppMessageByMessageId" parameterType="Long" resultMap="AppMessageVoResult">
|
||||
<include refid="selectAppMessageVo"/>
|
||||
where message_id = #{messageId}
|
||||
</select>
|
||||
|
||||
<select id="selectAppMessageByStatus" parameterType="String" resultMap="AppMessageVoResult">
|
||||
<include refid="selectAppMessageVo"/>
|
||||
where status = #{status}
|
||||
order by send_time desc
|
||||
</select>
|
||||
|
||||
<insert id="insertAppMessage" parameterType="AppMessage" useGeneratedKeys="true" keyProperty="messageId">
|
||||
insert into app_message
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="title != null and title != ''">title,</if>
|
||||
<if test="content != null">content,</if>
|
||||
<if test="messageType != null and messageType != ''">message_type,</if>
|
||||
<if test="pushTarget != null and pushTarget != ''">push_target,</if>
|
||||
<if test="targetIds != null">target_ids,</if>
|
||||
<if test="sendTime != null">send_time,</if>
|
||||
<if test="status != null">status,</if>
|
||||
<if test="createBy != null">create_by,</if>
|
||||
<if test="remark != null">remark,</if>
|
||||
create_time
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="title != null and title != ''">#{title},</if>
|
||||
<if test="content != null">#{content},</if>
|
||||
<if test="messageType != null and messageType != ''">#{messageType},</if>
|
||||
<if test="pushTarget != null and pushTarget != ''">#{pushTarget},</if>
|
||||
<if test="targetIds != null">#{targetIds},</if>
|
||||
<if test="sendTime != null">#{sendTime},</if>
|
||||
<if test="status != null">#{status},</if>
|
||||
<if test="createBy != null">#{createBy},</if>
|
||||
<if test="remark != null">#{remark},</if>
|
||||
sysdate()
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<update id="updateAppMessage" parameterType="AppMessage">
|
||||
update app_message
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="title != null and title != ''">title = #{title},</if>
|
||||
<if test="content != null">content = #{content},</if>
|
||||
<if test="messageType != null and messageType != ''">message_type = #{messageType},</if>
|
||||
<if test="pushTarget != null and pushTarget != ''">push_target = #{pushTarget},</if>
|
||||
<if test="targetIds != null">target_ids = #{targetIds},</if>
|
||||
<if test="sendTime != null">send_time = #{sendTime},</if>
|
||||
<if test="status != null">status = #{status},</if>
|
||||
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||
<if test="remark != null">remark = #{remark},</if>
|
||||
update_time = sysdate()
|
||||
</trim>
|
||||
where message_id = #{messageId}
|
||||
</update>
|
||||
|
||||
<update id="updateMessageStatus" parameterType="AppMessage">
|
||||
update app_message
|
||||
set status = #{status},
|
||||
update_by = #{updateBy},
|
||||
update_time = sysdate()
|
||||
where message_id = #{messageId}
|
||||
</update>
|
||||
|
||||
<delete id="deleteAppMessageByMessageId" parameterType="Long">
|
||||
delete
|
||||
from app_message
|
||||
where message_id = #{messageId}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteAppMessageByMessageIds" parameterType="String">
|
||||
delete from app_message where message_id in
|
||||
<foreach item="messageId" collection="array" open="(" separator="," close=")">
|
||||
#{messageId}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<delete id="deleteAppMessageByStatus" parameterType="String">
|
||||
delete
|
||||
from app_message
|
||||
where status = #{status}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,159 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.member.mapper.AppOperLogMapper">
|
||||
|
||||
<resultMap type="org.dromara.member.domain.AppOperLog" id="AppOperLogResult">
|
||||
<id property="operId" column="oper_id"/>
|
||||
<result property="title" column="title"/>
|
||||
<result property="businessType" column="business_type"/>
|
||||
<result property="method" column="method"/>
|
||||
<result property="requestMethod" column="request_method"/>
|
||||
<result property="operName" column="oper_name"/>
|
||||
<result property="operUrl" column="oper_url"/>
|
||||
<result property="operIp" column="oper_ip"/>
|
||||
<result property="operLocation" column="oper_location"/>
|
||||
<result property="operParam" column="oper_param"/>
|
||||
<result property="jsonResult" column="json_result"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="errorMsg" column="error_msg"/>
|
||||
<result property="operTime" column="oper_time"/>
|
||||
<result property="costTime" column="cost_time"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap type="org.dromara.member.domain.vo.AppOperLogVo" id="AppOperLogVoResult">
|
||||
<id property="operId" column="oper_id"/>
|
||||
<result property="title" column="title"/>
|
||||
<result property="businessType" column="business_type"/>
|
||||
<result property="method" column="method"/>
|
||||
<result property="requestMethod" column="request_method"/>
|
||||
<result property="operName" column="oper_name"/>
|
||||
<result property="operUrl" column="oper_url"/>
|
||||
<result property="operIp" column="oper_ip"/>
|
||||
<result property="operLocation" column="oper_location"/>
|
||||
<result property="operParam" column="oper_param"/>
|
||||
<result property="jsonResult" column="json_result"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="errorMsg" column="error_msg"/>
|
||||
<result property="operTime" column="oper_time"/>
|
||||
<result property="costTime" column="cost_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectAppOperLogVo">
|
||||
select oper_id,
|
||||
title,
|
||||
business_type,
|
||||
method,
|
||||
request_method,
|
||||
oper_name,
|
||||
oper_url,
|
||||
oper_ip,
|
||||
oper_location,
|
||||
oper_param,
|
||||
json_result,
|
||||
status,
|
||||
error_msg,
|
||||
oper_time,
|
||||
cost_time
|
||||
from app_oper_log
|
||||
</sql>
|
||||
|
||||
<!-- 查询操作日志列表 -->
|
||||
<select id="selectAppOperLogList" parameterType="AppOperLog" resultMap="AppOperLogVoResult">
|
||||
<include refid="selectAppOperLogVo"/>
|
||||
<where>
|
||||
<if test="title != null and title != ''">and title like concat('%', #{title}, '%')</if>
|
||||
<if test="businessType != null">and business_type = #{businessType}</if>
|
||||
<if test="method != null and method != ''">and method like concat('%', #{method}, '%')</if>
|
||||
<if test="requestMethod != null and requestMethod != ''">and request_method = #{requestMethod}</if>
|
||||
<if test="operName != null and operName != ''">and oper_name like concat('%', #{operName}, '%')</if>
|
||||
<if test="operIp != null and operIp != ''">and oper_ip like concat('%', #{operIp}, '%')</if>
|
||||
<if test="status != null">and status = #{status}</if>
|
||||
<if test="params.beginTime != null and params.beginTime != ''">and oper_time >= #{params.beginTime}</if>
|
||||
<if test="params.endTime != null and params.endTime != ''">and oper_time <= #{params.endTime}</if>
|
||||
</where>
|
||||
order by oper_time desc
|
||||
</select>
|
||||
|
||||
<!-- 根据ID查询操作日志 -->
|
||||
<select id="selectAppOperLogByOperId" parameterType="Long" resultMap="AppOperLogVoResult">
|
||||
<include refid="selectAppOperLogVo"/>
|
||||
where oper_id = #{operId}
|
||||
</select>
|
||||
|
||||
<!-- 根据操作人查询操作日志 -->
|
||||
<select id="selectAppOperLogByOperName" parameterType="String" resultMap="AppOperLogVoResult">
|
||||
<include refid="selectAppOperLogVo"/>
|
||||
where oper_name = #{operName}
|
||||
order by oper_time desc
|
||||
</select>
|
||||
|
||||
<!-- 新增操作日志 -->
|
||||
<insert id="insertAppOperLog" parameterType="org.dromara.member.domain.AppOperLog" useGeneratedKeys="true"
|
||||
keyProperty="operId">
|
||||
insert into app_oper_log
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="title != null and title != ''">title,</if>
|
||||
<if test="businessType != null">business_type,</if>
|
||||
<if test="method != null and method != ''">method,</if>
|
||||
<if test="requestMethod != null and requestMethod != ''">request_method,</if>
|
||||
<if test="operName != null and operName != ''">oper_name,</if>
|
||||
<if test="operUrl != null and operUrl != ''">oper_url,</if>
|
||||
<if test="operIp != null and operIp != ''">oper_ip,</if>
|
||||
<if test="operLocation != null and operLocation != ''">oper_location,</if>
|
||||
<if test="operParam != null and operParam != ''">oper_param,</if>
|
||||
<if test="jsonResult != null and jsonResult != ''">json_result,</if>
|
||||
<if test="status != null">status,</if>
|
||||
<if test="errorMsg != null and errorMsg != ''">error_msg,</if>
|
||||
<if test="operTime != null">oper_time,</if>
|
||||
<if test="costTime != null">cost_time,</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="title != null and title != ''">#{title},</if>
|
||||
<if test="businessType != null">#{businessType},</if>
|
||||
<if test="method != null and method != ''">#{method},</if>
|
||||
<if test="requestMethod != null and requestMethod != ''">#{requestMethod},</if>
|
||||
<if test="operName != null and operName != ''">#{operName},</if>
|
||||
<if test="operUrl != null and operUrl != ''">#{operUrl},</if>
|
||||
<if test="operIp != null and operIp != ''">#{operIp},</if>
|
||||
<if test="operLocation != null and operLocation != ''">#{operLocation},</if>
|
||||
<if test="operParam != null and operParam != ''">#{operParam},</if>
|
||||
<if test="jsonResult != null and jsonResult != ''">#{jsonResult},</if>
|
||||
<if test="status != null">#{status},</if>
|
||||
<if test="errorMsg != null and errorMsg != ''">#{errorMsg},</if>
|
||||
<if test="operTime != null">#{operTime},</if>
|
||||
<if test="costTime != null">#{costTime},</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<!-- 删除操作日志 -->
|
||||
<delete id="deleteAppOperLogByOperId" parameterType="Long">
|
||||
delete
|
||||
from app_oper_log
|
||||
where oper_id = #{operId}
|
||||
</delete>
|
||||
|
||||
<!-- 批量删除操作日志 -->
|
||||
<delete id="deleteAppOperLogByOperIds" parameterType="String">
|
||||
delete from app_oper_log where oper_id in
|
||||
<foreach item="operId" collection="array" open="(" separator="," close=")">
|
||||
#{operId}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<!-- 清空操作日志 -->
|
||||
<delete id="cleanAppOperLog">
|
||||
truncate table app_oper_log
|
||||
</delete>
|
||||
|
||||
<!-- 根据时间范围删除操作日志 -->
|
||||
<delete id="deleteAppOperLogByTime">
|
||||
delete from app_oper_log
|
||||
<where>
|
||||
<if test="beginTime != null and beginTime != ''">and oper_time >= #{beginTime}</if>
|
||||
<if test="endTime != null and endTime != ''">and oper_time <= #{endTime}</if>
|
||||
</where>
|
||||
</delete>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.member.mapper.AppRoleMapper">
|
||||
|
||||
<resultMap type="org.dromara.member.domain.AppRole" id="AppRoleResult">
|
||||
<id property="roleId" column="role_id"/>
|
||||
<result property="roleName" column="role_name"/>
|
||||
<result property="roleKey" column="role_key"/>
|
||||
<result property="roleSort" column="role_sort"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap type="org.dromara.member.domain.vo.AppRoleVo" id="AppRoleVoResult">
|
||||
<id property="roleId" column="role_id"/>
|
||||
<result property="roleName" column="role_name"/>
|
||||
<result property="roleKey" column="role_key"/>
|
||||
<result property="roleSort" column="role_sort"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectAppRoleVo">
|
||||
select distinct r.role_id,
|
||||
r.role_name,
|
||||
r.role_key,
|
||||
r.role_sort,
|
||||
r.status,
|
||||
r.del_flag,
|
||||
r.create_time,
|
||||
r.remark
|
||||
from app_role r
|
||||
left join app_user_role ur on ur.role_id = r.role_id
|
||||
left join app_user u on u.user_id = ur.user_id
|
||||
</sql>
|
||||
|
||||
<select id="selectRolesByUserId" parameterType="Long" resultMap="AppRoleVoResult">
|
||||
<include refid="selectAppRoleVo"/>
|
||||
WHERE r.del_flag = '0' and ur.user_id = #{userId}
|
||||
</select>
|
||||
|
||||
<select id="selectRolePermissionByUserId" parameterType="Long" resultType="String">
|
||||
select distinct r.role_key
|
||||
from app_role r
|
||||
left join app_user_role ur on ur.role_id = r.role_id
|
||||
WHERE r.del_flag = '0'
|
||||
and ur.user_id = #{userId}
|
||||
</select>
|
||||
|
||||
<select id="selectRoleAll" resultMap="AppRoleVoResult">
|
||||
<include refid="selectAppRoleVo"/>
|
||||
where r.del_flag = '0'
|
||||
</select>
|
||||
|
||||
<select id="selectRoleListByUserId" parameterType="Long" resultType="Long">
|
||||
select r.role_id
|
||||
from app_role r
|
||||
left join app_user_role ur on ur.role_id = r.role_id
|
||||
left join app_user u on u.user_id = ur.user_id
|
||||
where u.user_id = #{userId}
|
||||
</select>
|
||||
|
||||
<select id="checkRoleNameUnique" parameterType="String" resultType="int">
|
||||
select count(1)
|
||||
from app_role r
|
||||
where r.role_name = #{roleName}
|
||||
and r.del_flag = '0'
|
||||
</select>
|
||||
|
||||
<select id="checkRoleKeyUnique" parameterType="String" resultType="int">
|
||||
select count(1)
|
||||
from app_role r
|
||||
where r.role_key = #{roleKey}
|
||||
and r.del_flag = '0'
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,186 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.member.mapper.AppSocialAuthMapper">
|
||||
|
||||
<resultMap type="org.dromara.member.domain.AppSocialAuth" id="AppSocialAuthResult">
|
||||
<id property="id" column="id"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="platform" column="platform"/>
|
||||
<result property="platformUid" column="platform_uid"/>
|
||||
<result property="openId" column="open_id"/>
|
||||
<result property="unionId" column="union_id"/>
|
||||
<result property="accessToken" column="access_token"/>
|
||||
<result property="expireIn" column="expire_in"/>
|
||||
<result property="refreshToken" column="refresh_token"/>
|
||||
<result property="scope" column="scope"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap type="org.dromara.member.domain.vo.AppSocialAuthVo" id="AppSocialAuthVoResult">
|
||||
<id property="id" column="id"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="platform" column="platform"/>
|
||||
<result property="platformUid" column="platform_uid"/>
|
||||
<result property="openId" column="open_id"/>
|
||||
<result property="unionId" column="union_id"/>
|
||||
<result property="accessToken" column="access_token"/>
|
||||
<result property="expireIn" column="expire_in"/>
|
||||
<result property="refreshToken" column="refresh_token"/>
|
||||
<result property="scope" column="scope"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectAppSocialAuthVo">
|
||||
select id,
|
||||
user_id,
|
||||
platform,
|
||||
platform_uid,
|
||||
open_id,
|
||||
union_id,
|
||||
access_token,
|
||||
expire_in,
|
||||
refresh_token,
|
||||
scope,
|
||||
del_flag,
|
||||
create_by,
|
||||
create_time,
|
||||
update_by,
|
||||
update_time
|
||||
from app_social_auth
|
||||
</sql>
|
||||
|
||||
<!-- 查询社交认证列表 -->
|
||||
<select id="selectAppSocialAuthList" parameterType="AppSocialAuth" resultMap="AppSocialAuthVoResult">
|
||||
<include refid="selectAppSocialAuthVo"/>
|
||||
<where>
|
||||
<if test="userId != null">and user_id = #{userId}</if>
|
||||
<if test="platform != null and platform != ''">and platform = #{platform}</if>
|
||||
<if test="platformUid != null and platformUid != ''">and platform_uid = #{platformUid}</if>
|
||||
<if test="openId != null and openId != ''">and open_id = #{openId}</if>
|
||||
<if test="unionId != null and unionId != ''">and union_id = #{unionId}</if>
|
||||
and del_flag = '0'
|
||||
</where>
|
||||
order by create_time desc
|
||||
</select>
|
||||
|
||||
<!-- 根据ID查询社交认证 -->
|
||||
<select id="selectAppSocialAuthById" parameterType="Long" resultMap="AppSocialAuthVoResult">
|
||||
<include refid="selectAppSocialAuthVo"/>
|
||||
where id = #{id} and del_flag = '0'
|
||||
</select>
|
||||
|
||||
<!-- 根据用户ID查询社交认证列表 -->
|
||||
<select id="selectAppSocialAuthByUserId" parameterType="Long" resultMap="AppSocialAuthVoResult">
|
||||
<include refid="selectAppSocialAuthVo"/>
|
||||
where user_id = #{userId} and del_flag = '0'
|
||||
order by create_time desc
|
||||
</select>
|
||||
|
||||
<!-- 根据平台和openId查询社交认证 -->
|
||||
<select id="selectAppSocialAuthByPlatformAndOpenId" resultMap="AppSocialAuthResult">
|
||||
<include refid="selectAppSocialAuthVo"/>
|
||||
where platform = #{platform} and open_id = #{openId} and del_flag = '0'
|
||||
</select>
|
||||
|
||||
<!-- 根据平台和unionId查询社交认证 -->
|
||||
<select id="selectAppSocialAuthByPlatformAndUnionId" resultMap="AppSocialAuthResult">
|
||||
<include refid="selectAppSocialAuthVo"/>
|
||||
where platform = #{platform} and union_id = #{unionId} and del_flag = '0'
|
||||
</select>
|
||||
|
||||
<!-- 新增社交认证 -->
|
||||
<insert id="insertAppSocialAuth" parameterType="org.dromara.member.domain.AppSocialAuth" useGeneratedKeys="true"
|
||||
keyProperty="id">
|
||||
insert into app_social_auth
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="userId != null">user_id,</if>
|
||||
<if test="platform != null and platform != ''">platform,</if>
|
||||
<if test="platformUid != null and platformUid != ''">platform_uid,</if>
|
||||
<if test="openId != null and openId != ''">open_id,</if>
|
||||
<if test="unionId != null and unionId != ''">union_id,</if>
|
||||
<if test="accessToken != null and accessToken != ''">access_token,</if>
|
||||
<if test="expireIn != null">expire_in,</if>
|
||||
<if test="refreshToken != null and refreshToken != ''">refresh_token,</if>
|
||||
<if test="scope != null and scope != ''">scope,</if>
|
||||
<if test="delFlag != null and delFlag != ''">del_flag,</if>
|
||||
<if test="createBy != null and createBy != ''">create_by,</if>
|
||||
<if test="createTime != null">create_time,</if>
|
||||
<if test="updateBy != null and updateBy != ''">update_by,</if>
|
||||
<if test="updateTime != null">update_time,</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="userId != null">#{userId},</if>
|
||||
<if test="platform != null and platform != ''">#{platform},</if>
|
||||
<if test="platformUid != null and platformUid != ''">#{platformUid},</if>
|
||||
<if test="openId != null and openId != ''">#{openId},</if>
|
||||
<if test="unionId != null and unionId != ''">#{unionId},</if>
|
||||
<if test="accessToken != null and accessToken != ''">#{accessToken},</if>
|
||||
<if test="expireIn != null">#{expireIn},</if>
|
||||
<if test="refreshToken != null and refreshToken != ''">#{refreshToken},</if>
|
||||
<if test="scope != null and scope != ''">#{scope},</if>
|
||||
<if test="delFlag != null and delFlag != ''">#{delFlag},</if>
|
||||
<if test="createBy != null and createBy != ''">#{createBy},</if>
|
||||
<if test="createTime != null">#{createTime},</if>
|
||||
<if test="updateBy != null and updateBy != ''">#{updateBy},</if>
|
||||
<if test="updateTime != null">#{updateTime},</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<!-- 修改社交认证 -->
|
||||
<update id="updateAppSocialAuth" parameterType="org.dromara.member.domain.AppSocialAuth">
|
||||
update app_social_auth
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="userId != null">user_id = #{userId},</if>
|
||||
<if test="platform != null and platform != ''">platform = #{platform},</if>
|
||||
<if test="platformUid != null and platformUid != ''">platform_uid = #{platformUid},</if>
|
||||
<if test="openId != null and openId != ''">open_id = #{openId},</if>
|
||||
<if test="unionId != null and unionId != ''">union_id = #{unionId},</if>
|
||||
<if test="accessToken != null and accessToken != ''">access_token = #{accessToken},</if>
|
||||
<if test="expireIn != null">expire_in = #{expireIn},</if>
|
||||
<if test="refreshToken != null and refreshToken != ''">refresh_token = #{refreshToken},</if>
|
||||
<if test="scope != null and scope != ''">scope = #{scope},</if>
|
||||
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
|
||||
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||
</trim>
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
<!-- 删除社交认证 -->
|
||||
<update id="deleteAppSocialAuthById" parameterType="Long">
|
||||
update app_social_auth
|
||||
set del_flag = '2'
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
<!-- 批量删除社交认证 -->
|
||||
<update id="deleteAppSocialAuthByIds" parameterType="String">
|
||||
update app_social_auth set del_flag = '2' where id in
|
||||
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
<!-- 根据用户ID删除社交认证 -->
|
||||
<update id="deleteAppSocialAuthByUserId" parameterType="Long">
|
||||
update app_social_auth
|
||||
set del_flag = '2'
|
||||
where user_id = #{userId}
|
||||
</update>
|
||||
|
||||
<!-- 更新访问令牌 -->
|
||||
<update id="updateAccessToken">
|
||||
update app_social_auth
|
||||
set access_token = #{accessToken},
|
||||
expire_in = #{expireIn},
|
||||
refresh_token = #{refreshToken},
|
||||
update_time = #{updateTime}
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.member.mapper.AppUserMapper">
|
||||
|
||||
<resultMap type="org.dromara.member.domain.AppUser" id="AppUserResult">
|
||||
<id property="userId" column="user_id"/>
|
||||
<result property="userName" column="user_name"/>
|
||||
<result property="nickName" column="nick_name"/>
|
||||
<result property="phone" column="phone"/>
|
||||
<result property="email" column="email"/>
|
||||
<result property="sex" column="sex"/>
|
||||
<result property="avatar" column="avatar"/>
|
||||
<result property="password" column="password"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="loginIp" column="login_ip"/>
|
||||
<result property="loginDate" column="login_date"/>
|
||||
<result property="registerTime" column="register_time"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
|
||||
<resultMap type="org.dromara.member.domain.vo.AppUserVo" id="AppUserResultVo">
|
||||
<id property="userId" column="user_id"/>
|
||||
<result property="userName" column="user_name"/>
|
||||
<result property="nickName" column="nick_name"/>
|
||||
<result property="phone" column="phone"/>
|
||||
<result property="email" column="email"/>
|
||||
<result property="sex" column="sex"/>
|
||||
<result property="avatar" column="avatar"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="loginIp" column="login_ip"/>
|
||||
<result property="loginDate" column="login_date"/>
|
||||
<result property="registerTime" column="register_time"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectAppUserVo">
|
||||
select user_id,
|
||||
user_name,
|
||||
nick_name,
|
||||
phone,
|
||||
email,
|
||||
sex,
|
||||
avatar,
|
||||
password,
|
||||
status,
|
||||
del_flag,
|
||||
login_ip,
|
||||
login_date,
|
||||
register_time,
|
||||
create_by,
|
||||
create_time,
|
||||
update_by,
|
||||
update_time,
|
||||
remark
|
||||
from app_user
|
||||
</sql>
|
||||
|
||||
<select id="selectUserByUserName" parameterType="String" resultMap="AppUserResultVo">
|
||||
<include refid="selectAppUserVo"/>
|
||||
where user_name = #{userName} and del_flag = '0'
|
||||
</select>
|
||||
|
||||
<select id="selectUserByPhone" parameterType="String" resultMap="AppUserResultVo">
|
||||
<include refid="selectAppUserVo"/>
|
||||
where phone = #{phone} and del_flag = '0'
|
||||
</select>
|
||||
|
||||
<select id="selectUserByEmail" parameterType="String" resultMap="AppUserResultVo">
|
||||
<include refid="selectAppUserVo"/>
|
||||
where email = #{email} and del_flag = '0'
|
||||
</select>
|
||||
|
||||
<select id="checkUserNameUnique" parameterType="String" resultType="int">
|
||||
select count(*)
|
||||
from app_user
|
||||
where user_name = #{userName}
|
||||
and del_flag = '0'
|
||||
</select>
|
||||
|
||||
<select id="checkPhoneUnique" parameterType="String" resultType="int">
|
||||
select count(*)
|
||||
from app_user
|
||||
where phone = #{phone}
|
||||
and del_flag = '0'
|
||||
</select>
|
||||
|
||||
<select id="checkEmailUnique" parameterType="String" resultType="int">
|
||||
select count(*)
|
||||
from app_user
|
||||
where email = #{email}
|
||||
and del_flag = '0'
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,153 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.member.mapper.AppUserMessageMapper">
|
||||
|
||||
<resultMap type="org.dromara.member.domain.AppUserMessage" id="AppUserMessageResult">
|
||||
<id property="id" column="id"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="messageId" column="message_id"/>
|
||||
<result property="isRead" column="is_read"/>
|
||||
<result property="readTime" column="read_time"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap type="org.dromara.member.domain.vo.AppUserMessageVo" id="AppUserMessageVoResult">
|
||||
<id property="id" column="id"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="messageId" column="message_id"/>
|
||||
<result property="isRead" column="is_read"/>
|
||||
<result property="readTime" column="read_time"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectAppUserMessageVo">
|
||||
select user_message_id, user_id, message_id, is_read, read_time, create_time
|
||||
from app_user_message
|
||||
</sql>
|
||||
|
||||
<select id="selectAppUserMessageList" parameterType="AppUserMessage" resultMap="AppUserMessageVoResult">
|
||||
<include refid="selectAppUserMessageVo"/>
|
||||
<where>
|
||||
<if test="userId != null">and user_id = #{userId}</if>
|
||||
<if test="messageId != null">and message_id = #{messageId}</if>
|
||||
<if test="isRead != null">and is_read = #{isRead}</if>
|
||||
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
|
||||
and date_format(create_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d')
|
||||
</if>
|
||||
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
|
||||
and date_format(create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d')
|
||||
</if>
|
||||
</where>
|
||||
order by create_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectAppUserMessageByUserMessageId" parameterType="Long" resultMap="AppUserMessageVoResult">
|
||||
<include refid="selectAppUserMessageVo"/>
|
||||
where user_message_id = #{userMessageId}
|
||||
</select>
|
||||
|
||||
<select id="selectAppUserMessageByUserId" parameterType="Long" resultMap="AppUserMessageVoResult">
|
||||
<include refid="selectAppUserMessageVo"/>
|
||||
where user_id = #{userId}
|
||||
order by create_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectUnreadMessagesByUserId" parameterType="Long" resultMap="AppUserMessageVoResult">
|
||||
<include refid="selectAppUserMessageVo"/>
|
||||
where user_id = #{userId} and is_read = 0
|
||||
order by create_time desc
|
||||
</select>
|
||||
|
||||
<select id="countUnreadMessagesByUserId" parameterType="Long" resultType="int">
|
||||
select count(1)
|
||||
from app_user_message
|
||||
where user_id = #{userId}
|
||||
and is_read = 0
|
||||
</select>
|
||||
|
||||
<select id="selectAppUserMessageByUserIdAndMessageId" resultMap="AppUserMessageVoResult">
|
||||
<include refid="selectAppUserMessageVo"/>
|
||||
where user_id = #{userId} and message_id = #{messageId}
|
||||
</select>
|
||||
|
||||
<insert id="insertAppUserMessage" parameterType="AppUserMessage" useGeneratedKeys="true"
|
||||
keyProperty="userMessageId">
|
||||
insert into app_user_message
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="userId != null">user_id,</if>
|
||||
<if test="messageId != null">message_id,</if>
|
||||
<if test="isRead != null">is_read,</if>
|
||||
<if test="readTime != null">read_time,</if>
|
||||
create_time
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="userId != null">#{userId},</if>
|
||||
<if test="messageId != null">#{messageId},</if>
|
||||
<if test="isRead != null">#{isRead},</if>
|
||||
<if test="readTime != null">#{readTime},</if>
|
||||
sysdate()
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<insert id="batchInsertAppUserMessage" parameterType="java.util.List">
|
||||
insert into app_user_message(user_id, message_id, is_read, create_time)
|
||||
values
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.userId}, #{item.messageId}, #{item.isRead}, sysdate())
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<update id="updateAppUserMessage" parameterType="AppUserMessage">
|
||||
update app_user_message
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="userId != null">user_id = #{userId},</if>
|
||||
<if test="messageId != null">message_id = #{messageId},</if>
|
||||
<if test="isRead != null">is_read = #{isRead},</if>
|
||||
<if test="readTime != null">read_time = #{readTime},</if>
|
||||
</trim>
|
||||
where user_message_id = #{userMessageId}
|
||||
</update>
|
||||
|
||||
<update id="markAsRead" parameterType="Long">
|
||||
update app_user_message
|
||||
set is_read = 1,
|
||||
read_time = sysdate()
|
||||
where user_message_id = #{userMessageId}
|
||||
</update>
|
||||
|
||||
<update id="markAllAsReadByUserId" parameterType="Long">
|
||||
update app_user_message
|
||||
set is_read = 1,
|
||||
read_time = sysdate()
|
||||
where user_id = #{userId}
|
||||
and is_read = 0
|
||||
</update>
|
||||
|
||||
<delete id="deleteAppUserMessageByUserMessageId" parameterType="Long">
|
||||
delete
|
||||
from app_user_message
|
||||
where user_message_id = #{userMessageId}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteAppUserMessageByUserMessageIds" parameterType="String">
|
||||
delete from app_user_message where user_message_id in
|
||||
<foreach item="userMessageId" collection="array" open="(" separator="," close=")">
|
||||
#{userMessageId}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<delete id="deleteAppUserMessageByUserId" parameterType="Long">
|
||||
delete
|
||||
from app_user_message
|
||||
where user_id = #{userId}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteAppUserMessageByMessageId" parameterType="Long">
|
||||
delete
|
||||
from app_user_message
|
||||
where message_id = #{messageId}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.member.mapper.AppUserRoleMapper">
|
||||
|
||||
<resultMap type="org.dromara.member.domain.AppUserRole" id="AppUserRoleResult">
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="roleId" column="role_id"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 通过用户ID删除用户和角色关联 -->
|
||||
<delete id="deleteUserRoleByUserId" parameterType="Long">
|
||||
delete
|
||||
from app_user_role
|
||||
where user_id = #{userId}
|
||||
</delete>
|
||||
|
||||
<!-- 批量删除用户和角色关联 -->
|
||||
<delete id="deleteUserRole" parameterType="Long">
|
||||
delete from app_user_role where user_id in
|
||||
<foreach collection="array" item="userId" open="(" separator="," close=")">
|
||||
#{userId}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<!-- 通过角色ID查询角色使用数量 -->
|
||||
<select id="countUserRoleByRoleId" parameterType="Long" resultType="int">
|
||||
select count(1)
|
||||
from app_user_role
|
||||
where role_id = #{roleId}
|
||||
</select>
|
||||
|
||||
<!-- 批量新增用户角色信息 -->
|
||||
<insert id="batchUserRole">
|
||||
insert into app_user_role(user_id, role_id) values
|
||||
<foreach item="item" index="index" collection="list" separator=",">
|
||||
(#{item.userId}, #{item.roleId})
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.member.mapper.AppVersionMapper">
|
||||
|
||||
<resultMap type="org.dromara.member.domain.AppVersion" id="AppVersionResult">
|
||||
<id property="versionId" column="version_id"/>
|
||||
<result property="versionCode" column="version_code"/>
|
||||
<result property="versionName" column="version_name"/>
|
||||
<result property="updateContent" column="update_content"/>
|
||||
<result property="downloadUrl" column="download_url"/>
|
||||
<result property="isForce" column="is_force"/>
|
||||
<result property="platform" column="platform"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap type="org.dromara.member.domain.vo.AppVersionVo" id="AppVersionVoResult">
|
||||
<id property="versionId" column="version_id"/>
|
||||
<result property="versionCode" column="version_code"/>
|
||||
<result property="versionName" column="version_name"/>
|
||||
<result property="updateContent" column="update_content"/>
|
||||
<result property="downloadUrl" column="download_url"/>
|
||||
<result property="isForce" column="is_force"/>
|
||||
<result property="platform" column="platform"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectAppVersionVo">
|
||||
select version_id,
|
||||
version_code,
|
||||
version_name,
|
||||
update_content,
|
||||
download_url,
|
||||
is_force,
|
||||
platform,
|
||||
create_time
|
||||
from app_version
|
||||
</sql>
|
||||
|
||||
<select id="selectAppVersionList" parameterType="AppVersion" resultMap="AppVersionVoResult">
|
||||
<include refid="selectAppVersionVo"/>
|
||||
<where>
|
||||
<if test="versionName != null and versionName != ''">and version_name like concat('%', #{versionName},
|
||||
'%')
|
||||
</if>
|
||||
<if test="versionCode != null and versionCode != ''">and version_code = #{versionCode}</if>
|
||||
<if test="platform != null and platform != ''">and platform = #{platform}</if>
|
||||
<if test="isForce != null">and is_force = #{isForce}</if>
|
||||
</where>
|
||||
order by create_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectAppVersionByVersionId" parameterType="Long" resultMap="AppVersionVoResult">
|
||||
<include refid="selectAppVersionVo"/>
|
||||
where version_id = #{versionId}
|
||||
</select>
|
||||
|
||||
<select id="selectLatestVersionByPlatform" parameterType="String" resultMap="AppVersionVoResult">
|
||||
<include refid="selectAppVersionVo"/>
|
||||
where platform = #{platform}
|
||||
order by version_code desc
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
<select id="checkVersionCodeUnique" parameterType="AppVersion" resultType="int">
|
||||
select count(1) from app_version
|
||||
where version_code = #{versionCode} and platform = #{platform}
|
||||
<if test="versionId != null and versionId != 0">and version_id != #{versionId}</if>
|
||||
</select>
|
||||
|
||||
<insert id="insertAppVersion" parameterType="AppVersion" useGeneratedKeys="true" keyProperty="versionId">
|
||||
insert into app_version
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="versionCode != null and versionCode != ''">version_code,</if>
|
||||
<if test="versionName != null and versionName != ''">version_name,</if>
|
||||
<if test="updateContent != null">update_content,</if>
|
||||
<if test="downloadUrl != null">download_url,</if>
|
||||
<if test="isForce != null">is_force,</if>
|
||||
<if test="platform != null and platform != ''">platform,</if>
|
||||
create_time
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="versionCode != null and versionCode != ''">#{versionCode},</if>
|
||||
<if test="versionName != null and versionName != ''">#{versionName},</if>
|
||||
<if test="updateContent != null">#{updateContent},</if>
|
||||
<if test="downloadUrl != null">#{downloadUrl},</if>
|
||||
<if test="isForce != null">#{isForce},</if>
|
||||
<if test="platform != null and platform != ''">#{platform},</if>
|
||||
sysdate()
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<update id="updateAppVersion" parameterType="AppVersion">
|
||||
update app_version
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="versionCode != null and versionCode != ''">version_code = #{versionCode},</if>
|
||||
<if test="versionName != null and versionName != ''">version_name = #{versionName},</if>
|
||||
<if test="updateContent != null">update_content = #{updateContent},</if>
|
||||
<if test="downloadUrl != null">download_url = #{downloadUrl},</if>
|
||||
<if test="isForce != null">is_force = #{isForce},</if>
|
||||
<if test="platform != null and platform != ''">platform = #{platform},</if>
|
||||
</trim>
|
||||
where version_id = #{versionId}
|
||||
</update>
|
||||
|
||||
<delete id="deleteAppVersionByVersionId" parameterType="Long">
|
||||
delete
|
||||
from app_version
|
||||
where version_id = #{versionId}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteAppVersionByVersionIds" parameterType="String">
|
||||
delete from app_version where version_id in
|
||||
<foreach item="versionId" collection="array" open="(" separator="," close=")">
|
||||
#{versionId}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user