Compare commits
267 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fee60ef208 | |||
| c11bc40b2b | |||
| 56e0fea50a | |||
| 84d4d8e118 | |||
| bd85cca154 | |||
| eb76349932 | |||
| c8ca54f026 | |||
| 691efec9f7 | |||
| 482b1c4d12 | |||
| 9152b81092 | |||
| caaa969acb | |||
| 37fd40f6bc | |||
| eed9b2a0dd | |||
| 0e55d4f4f8 | |||
| 6b18623b7f | |||
| 16fe20ea48 | |||
| baedf074be | |||
| d84528ee14 | |||
| 51be61b741 | |||
| 8a36c99ec7 | |||
| 6264571059 | |||
| 77745360f6 | |||
| 567bda85a6 | |||
| 3ba933257e | |||
| 1e37d646d2 | |||
| b79e7f15a5 | |||
| 769de337e7 | |||
| 8525c5399e | |||
| bb861d1138 | |||
| 2350df80a3 | |||
| 0e217db2ba | |||
| d9a489d99d | |||
| c509e75d4c | |||
| a5ac267277 | |||
| 01c93c3adf | |||
| 10ccf471c5 | |||
| 5afec37b36 | |||
| 7f0a0a43a8 | |||
| fd57b0f92f | |||
| 22c370c7fb | |||
| 1f6a85e17b | |||
| 410860689d | |||
| 8948581e47 | |||
| fc2144b708 | |||
| 4b336dfd8e | |||
| 167e3eed85 | |||
| 0a92ac5e67 | |||
| a460ec3ecb | |||
| 1d249222fa | |||
| 0b33a011a2 | |||
| e9024508ef | |||
| 66d4345339 | |||
| 32a84d6155 | |||
| 0e7e4dbb80 | |||
| cd2fca31e2 | |||
| c424bc0ca8 | |||
| 010132f237 | |||
| 91188fe1a0 | |||
| a5cdf202f1 | |||
| a30fb508de | |||
| aa792a10b1 | |||
| bcdd99eb4a | |||
| 50c1f73901 | |||
| 0d93550e43 | |||
| 3b05b235bc | |||
| 2fa9950933 | |||
| 76bd360e92 | |||
| f459579768 | |||
| cb388c8e85 | |||
| b26c158c84 | |||
| 26f6a38c6b | |||
| e80ff782e7 | |||
| 44110bd059 | |||
| 9bc5869abd | |||
| 2b25c63f4e | |||
| 5f259398a2 | |||
| ddc1cddcb9 | |||
| a0a6040437 | |||
| f46f56e5b0 | |||
| b6a9c87e2a | |||
| ddb28dc5c8 | |||
| 92e2c99b89 | |||
| a6cf439160 | |||
| b0a0785501 | |||
| a22fa10cb8 | |||
| 200346ee71 | |||
| efa1a331bb | |||
| 49d46c391a | |||
| 69c9c00c16 | |||
| 226518b3a4 | |||
| e265d9620b | |||
| 4180aa5567 | |||
| e7bc4f312a | |||
| 6d15e1fa32 | |||
| aa8a171ccc | |||
| 6e7adc20cb | |||
| 5bb10fe988 | |||
| 37acc6ebae | |||
| ac911e41e1 | |||
| 4f69fb5d3a | |||
| 61eb0c7177 | |||
| 1f07dde9d2 | |||
| 822d5e8207 | |||
| 0125a6598c | |||
| 173a6145af | |||
| 8d66f53be5 | |||
| 0c83d79684 | |||
| 91741b3224 | |||
| 4a7e7c2595 | |||
| 49c3e34b23 | |||
| 4686861ad2 | |||
| 10a6b8fc57 | |||
| 92a7db0031 | |||
| 2072a3cbc9 | |||
| c903ff31e3 | |||
| 8f96db1483 | |||
| 13323608a9 | |||
| 6a88008a51 | |||
| 0b96c77838 | |||
| a2e22e1478 | |||
| 18928deb2e | |||
| e44e0e662e | |||
| eaf7faa12b | |||
| 6b2c8ec70c | |||
| 126251e113 | |||
| 04814bbd89 | |||
| dc52c30581 | |||
| 32250adc85 | |||
| afcecc3c73 | |||
| 333c63bb62 | |||
| bc6c88d89d | |||
| f1b8d3b47d | |||
| 4453f13b37 | |||
| 53316b0b71 | |||
| 1697bd8fef | |||
| f034ce1b1a | |||
| 21a3f1e166 | |||
| a3555407a1 | |||
| 711bf01e62 | |||
| 27ba31bf4f | |||
| a71bc7d6b2 | |||
| d4c7fa2fc1 | |||
| ab09d4a524 | |||
| 8ec6f213d4 | |||
| bebca3004d | |||
| 103837e0f3 | |||
| 4d011a2a51 | |||
| 4011874184 | |||
| cd55670218 | |||
| 59c86e3aca | |||
| f1232e7981 | |||
| 4d7af16b05 | |||
| 510fb3814f | |||
| 8d89747fe4 | |||
| 6063523f30 | |||
| e9fe435aef | |||
| 1a88fca5b6 | |||
| 658663c61a | |||
| e8a5668da4 | |||
| 7380a37431 | |||
| cc80a97dba | |||
| 41dd169a97 | |||
| 5dd48e50a0 | |||
| f77d753264 | |||
| fe84dea084 | |||
| 8fc86bebff | |||
| 73a8bf4a35 | |||
| d662c8dec1 | |||
| 4e8c2178ba | |||
| 9e3968cbda | |||
| 44fee2cf6e | |||
| 13610a7bb6 | |||
| f29fa0b508 | |||
| 79b5eb0836 | |||
| b36951a4fb | |||
| 97901204b7 | |||
| c43bf99629 | |||
| 0ea7bf55b3 | |||
| c0e6c171a6 | |||
| b75d12cb83 | |||
| 9bc848dd96 | |||
| d18238dbab | |||
| 63761c9d3a | |||
| ca489012f5 | |||
| 14439a203b | |||
| 92e340ae09 | |||
| 3de354c111 | |||
| e67f42f033 | |||
| 8589fd38e0 | |||
| 99eb3bcb7f | |||
| 09eb23318e | |||
| f0084754ca | |||
| cc0c7f374e | |||
| f42644e836 | |||
| d4dc0a25c7 | |||
| b4fc7db6d0 | |||
| 69a53a5f2a | |||
| 84c53c545f | |||
| cbfec821da | |||
| d26d0a4ae5 | |||
| 6d9be42340 | |||
| 71bc4b45dc | |||
| 35abd199bc | |||
| e7cc44c502 | |||
| d96de82d5f | |||
| 6745fecc6f | |||
| b188e3dcb9 | |||
| ccada6c25d | |||
| 83c78c96dd | |||
| 2bf333cc90 | |||
| f51ae91df0 | |||
| 51a987670c | |||
| dff81402bb | |||
| 672f0e7514 | |||
| a3ff0accb6 | |||
| c14f984d89 | |||
| 8503e7a69f | |||
| aceb2811ef | |||
| e3843fdad8 | |||
| 49c4ba8652 | |||
| e80a44320a | |||
| e3098cf8d9 | |||
| 7a6f346404 | |||
| 612e4a428c | |||
| fbfaea3926 | |||
| 7ee83372b6 | |||
| db52846a6c | |||
| 8105b62737 | |||
| a2d00e3ab7 | |||
| 09b9e92585 | |||
| 243b9066cf | |||
| 461e4e6457 | |||
| e4d90c4252 | |||
| 4cead507ae | |||
| e6b21e3a49 | |||
| d434b2084f | |||
| c55aa8f97a | |||
| a059ab9e00 | |||
| 80e0289e4b | |||
| 66489db865 | |||
| 7a1f3c787f | |||
| 0174e14455 | |||
| e01f90088f | |||
| 9f394d71a1 | |||
| 1273f011b4 | |||
| 67eb497114 | |||
| 54772ded8f | |||
| 94eb1b7141 | |||
| 7b742c1701 | |||
| 2d23f468df | |||
| d18ce96c45 | |||
| 04bed3ba3d | |||
| 70623c5712 | |||
| 73877d675a | |||
| e9d29ef2df | |||
| 186feb98da | |||
| 4d3b8caf21 | |||
| a89a69b145 | |||
| 50fa31c6ad | |||
| b1e3fabea3 | |||
| ac70ccf30f | |||
| 211afafeaf | |||
| 01ab4d2b4f | |||
| 1971f3031c | |||
| a746c1be84 | |||
| fba23a61e7 | |||
| 2ab2593f45 |
+2
-1
@@ -1,10 +1,11 @@
|
|||||||
######################################################################
|
######################################################################
|
||||||
# Build Tools
|
# Build Tools
|
||||||
|
|
||||||
|
/logs
|
||||||
.gradle
|
.gradle
|
||||||
/build/
|
/build/
|
||||||
!gradle/wrapper/gradle-wrapper.jar
|
!gradle/wrapper/gradle-wrapper.jar
|
||||||
|
.DS_Store
|
||||||
target/
|
target/
|
||||||
!.mvn/wrapper/maven-wrapper.jar
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
|
||||||
|
|||||||
@@ -1,228 +0,0 @@
|
|||||||
**严肃声明:现在、未来都不会有商业版本,所有功能全部开源!**
|
|
||||||
|
|
||||||
**拒绝虚假开源,售卖商业版,程序员不骗程序员!!**
|
|
||||||
|
|
||||||
**「我喜欢写代码,乐此不疲」**
|
|
||||||
**「我喜欢做开源,以此为乐」**
|
|
||||||
|
|
||||||
## 🐯 平台简介
|
|
||||||
|
|
||||||
**芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。
|
|
||||||
|
|
||||||
> 有任何问题,或者想要的功能,可以在 _Issues_ 中提给艿艿。
|
|
||||||
>
|
|
||||||
> 😜 给项目点点 Star 吧,这对我们真的很重要!
|
|
||||||
|
|
||||||
* 前端采用 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) ,正在支持 Vue 3 + ElementUI Plus 最新方案。
|
|
||||||
* 后端采用 Spring Boot、MySQL + MyBatis Plus、Redis + Redisson。
|
|
||||||
* 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统。
|
|
||||||
* 支持加载动态权限菜单,按钮级别权限控制,本地缓存提升性能。
|
|
||||||
* 支持 SaaS 多租户系统,可自定义每个租户的权限,提供透明化的多租户底层封装。
|
|
||||||
* 工作流使用 Activiti + Flowable,支持动态表单、在线设计流程、多种任务分配方式。
|
|
||||||
* 高效率开发,使用代码生成器可以一键生成前后端代码 + 单元测试 + Swagger 接口文档 + Validator 参数校验。
|
|
||||||
* 集成微信小程序、微信公众号、企业微信、钉钉等三方登陆,集成支付宝、微信等支付与退款。
|
|
||||||
* 集成阿里云、腾讯云、云片等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务。
|
|
||||||
|
|
||||||
| 项目名 | 说明 | 传说门 |
|
|
||||||
|--------------------|------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
|
|
||||||
| `ruoyi-vue-pro` | Spring Boot 多模块 | **[Gitee](https://gitee.com/zhijiantianya/ruoyi-vue-pro)** [Github](https://github.com/YunaiV/ruoyi-vue-pro) |
|
|
||||||
| `ruoyi-vue-cloud` | Spring Cloud 微服务 | **[Gitee](https://gitee.com/zhijiantianya/ruoyi-vue-cloud)** [Github](https://github.com/YunaiV/onemall) |
|
|
||||||
| `Spring-Boot-Labs` | Spring Boot & Cloud 入门 | **[Gitee](https://gitee.com/zhijiantianya/SpringBoot-Labs)** [Github](https://github.com/YunaiV/SpringBoot-Labs) |
|
|
||||||
|
|
||||||
## 🐶 在线体验
|
|
||||||
|
|
||||||
演示地址:<http://dashboard.yudao.iocoder.cn>
|
|
||||||
* 账号密码:admin/admin123
|
|
||||||
|
|
||||||
文档地址:<http://www.iocoder.cn/categories/Yudao/>
|
|
||||||
* [《如何搭建环境》](http://www.iocoder.cn/categories/Yudao/?yudao)
|
|
||||||
|
|
||||||
> 未来会补充文档和视频,方便胖友冲冲冲!
|
|
||||||
|
|
||||||
## 🐼 内置功能
|
|
||||||
|
|
||||||
分成多种内置功能:
|
|
||||||
* 系统功能
|
|
||||||
* 工作流程
|
|
||||||
* 支付系统
|
|
||||||
* 商城系统
|
|
||||||
* 基础设施
|
|
||||||
|
|
||||||
> 友情提示:本项目基于 RuoYi-Vue 修改,**重构优化**后端的代码,**美化**前端的界面。
|
|
||||||
>
|
|
||||||
> * 额外新增的功能,我们使用 🚀 标记。
|
|
||||||
> * 重新实现的功能,我们使用 ⭐️ 标记。
|
|
||||||
|
|
||||||
🙂 所有功能,都通过 **单元测试** 保证高质量。
|
|
||||||
|
|
||||||
### 系统功能
|
|
||||||
|
|
||||||
| | 功能 | 描述 |
|
|
||||||
|-----|-------|---------------------------------|
|
|
||||||
| | 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置 |
|
|
||||||
| ⭐️ | 在线用户 | 当前系统中活跃用户状态监控,支持手动踢下线 |
|
|
||||||
| | 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 |
|
|
||||||
| | 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等,本地缓存提供性能 |
|
|
||||||
| | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 |
|
|
||||||
| | 岗位管理 | 配置系统用户所属担任职务 |
|
|
||||||
| 🚀 | 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能 |
|
|
||||||
| 🚀 | 租户套餐 | 配置租户套餐,自定每个租户的菜单、操作、按钮的权限 |
|
|
||||||
| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 |
|
|
||||||
| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、云片等主流短信平台 |
|
|
||||||
| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 |
|
|
||||||
| ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 |
|
|
||||||
| 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 |
|
|
||||||
| | 通知公告 | 系统通知公告信息发布维护 |
|
|
||||||
|
|
||||||
### 工作流程
|
|
||||||
|
|
||||||
| | 功能 | 描述 |
|
|
||||||
|-----|-------|----------------------------------------|
|
|
||||||
| 🚀 | 流程模型 | 配置工作流的流程模型,支持文件导入与在线设计流程图,提供 7 种任务分配规则 |
|
|
||||||
| 🚀 | 流程表单 | 拖动表单元素生成相应的工作流表单,覆盖 Element UI 所有的表单组件 |
|
|
||||||
| 🚀 | 用户分组 | 自定义用户分组,可用于工作流的审批分组 |
|
|
||||||
| 🚀 | 我的流程 | 查看我发起的工作流程,支持新建、取消流程等操作,高亮流程图、审批时间线 |
|
|
||||||
| 🚀 | 待办任务 | 查看自己【未】审批的工作任务,支持通过、不通过、转发、委派、退回等操作 |
|
|
||||||
| 🚀 | 已办任务 | 查看自己【已】审批的工作任务,未来会支持回退操作 |
|
|
||||||
| 🚀 | OA 请假 | 作为业务自定义接入工作流的使用示例,只需创建请求对应的工作流程,即可进行审批 |
|
|
||||||
|
|
||||||
### 支付系统
|
|
||||||
|
|
||||||
| | 功能 | 描述 |
|
|
||||||
|-----|------|---------------------------|
|
|
||||||
| 🚀 | 商户信息 | 管理商户信息,支持 Saas 场景下的多商户功能 |
|
|
||||||
| 🚀 | 应用信息 | 配置商户的应用信息,对接支付宝、微信等多个支付渠道 |
|
|
||||||
| 🚀 | 支付订单 | 查看用户发起的支付宝、微信等的【支付】订单 |
|
|
||||||
| 🚀 | 退款订单 | 查看用户发起的支付宝、微信等的【退款】订单 |
|
|
||||||
|
|
||||||
ps:核心功能已经实现,正在对接微信小程序中...
|
|
||||||
|
|
||||||
### 商城系统
|
|
||||||
|
|
||||||
正在开发中,大体计划如下:
|
|
||||||
* 2022 Q2 => 完成对 <https://github.com/YunaiV/onemall> 的迁移,作为 onemall 的 Spring Boot 单体版本。
|
|
||||||
* 2022 Q4 => 完成对 <https://github.com/YunaiV/onemall>> 的重构,作为 onemall 的 Spring Cloud 微服务版本。
|
|
||||||
|
|
||||||
### 会员中心
|
|
||||||
|
|
||||||
正在开发中,大体计划如下:
|
|
||||||
* 2021 Q1 =》完成对 <https://github.com/YunaiV/onemall> 的迁移
|
|
||||||
|
|
||||||
### 基础设施
|
|
||||||
|
|
||||||
| | 功能 | 描述 |
|
|
||||||
|-----|----------|----------------------------------------------|
|
|
||||||
| 🚀 | 代码生成 | 前后端代码的生成(Java、Vue、SQL、单元测试),支持 CRUD 下载 |
|
|
||||||
| 🚀 | 系统接口 | 基于 Swagger 自动生成相关的 RESTful API 接口文档 |
|
|
||||||
| 🚀 | 数据库文档 | 基于 Screw 自动生成数据库文档,支持导出 Word、HTML、MD 格式 |
|
|
||||||
| | 表单构建 | 拖动表单元素生成相应的 HTML 代码,支持导出 JSON、Vue 文件 |
|
|
||||||
| 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 |
|
|
||||||
| ⭐️ | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 |
|
|
||||||
| 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 |
|
|
||||||
| 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 |
|
|
||||||
| | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 |
|
|
||||||
| | Redis 监控 | 监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |
|
|
||||||
| 🚀 | 消息队列 | 基于 Redis 实现消息队列,Stream 提供集群消费,Pub/Sub 提供广播消费 |
|
|
||||||
| 🚀 | Java 监控 | 基于 Spring Boot Admin 实现 Java 应用的监控 |
|
|
||||||
| 🚀 | 链路追踪 | 接入 SkyWalking 组件,实现链路追踪 |
|
|
||||||
| 🚀 | 日志中心 | 接入 SkyWalking 组件,实现日志中心 |
|
|
||||||
| 🚀 | 分布式锁 | 基于 Redis 实现分布式锁,满足并发场景 |
|
|
||||||
| 🚀 | 幂等组件 | 基于 Redis 实现幂等组件,解决重复请求问题 |
|
|
||||||
| 🚀 | 服务保障 | 基于 Resilience4j 实现服务的稳定性,包括限流、熔断等功能 |
|
|
||||||
| 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 |
|
|
||||||
| 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 |
|
|
||||||
|
|
||||||
## 🐨 技术栈
|
|
||||||
|
|
||||||
| 项目 | 说明 |
|
|
||||||
|-----------------------|--------------------|
|
|
||||||
| `yudao-dependencies` | Maven 依赖版本管理 |
|
|
||||||
| `yudao-framework` | Java 框架拓展 |
|
|
||||||
| `yudao-server` | 管理后台 + 用户 APP 的服务端 |
|
|
||||||
| `yudao-admin-ui` | 管理后台的 UI 界面 |
|
|
||||||
| `yudao-user-ui` | 用户 APP 的 UI 界面 |
|
|
||||||
| `yudao-module-system` | 系统功能的 Module 模块 |
|
|
||||||
| `yudao-module-member` | 会员中心的 Module 模块 |
|
|
||||||
| `yudao-module-infra` | 基础设施的 Module 模块 |
|
|
||||||
| `yudao-module-tool` | 研发工具的 Module 模块 |
|
|
||||||
| `yudao-module-bpm` | 工作流程的 Module 模块 |
|
|
||||||
| `yudao-module-pay` | 支付系统的 Module 模块 |
|
|
||||||
|
|
||||||
### 后端
|
|
||||||
|
|
||||||
| 框架 | 说明 | 版本 | 学习指南 |
|
|
||||||
|---------------------------------------------------------------------------------------------|------------------|----------|----------------------------------------------------------------|
|
|
||||||
| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.5.10 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |
|
|
||||||
| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 | |
|
|
||||||
| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.8 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
|
|
||||||
| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.1 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
|
|
||||||
| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.5.0 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
|
|
||||||
| [Redis](https://redis.io/) | key-value 数据库 | 5.0 | |
|
|
||||||
| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.16.8 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
|
|
||||||
| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.16 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
|
|
||||||
| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.5.5 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
|
|
||||||
| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.2 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
|
|
||||||
| [Activiti](https://github.com/Activiti/Activiti) | 工作流引擎 | 7.1.0.M6 | [文档](TODO) |
|
|
||||||
| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
|
|
||||||
| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.2 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
|
|
||||||
| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.0 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |
|
|
||||||
| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.5.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
|
|
||||||
| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.4.2 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
|
|
||||||
| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.12.6 | |
|
|
||||||
| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.4.1 | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
|
|
||||||
| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.16.14 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
|
|
||||||
| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.7.2 | - |
|
|
||||||
| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 3.9.0 | - |
|
|
||||||
|
|
||||||
### 前端
|
|
||||||
|
|
||||||
| 框架 | 说明 | 版本 |
|
|
||||||
|------------------------------------------------------------------------------|---------------|--------|
|
|
||||||
| [Vue](https://cn.vuejs.org/index.html) | JavaScript 框架 | 2.6.12 |
|
|
||||||
| [Vue Element Admin](https://panjiachen.github.io/vue-element-admin-site/zh/) | 后台前端解决方案 | - |
|
|
||||||
|
|
||||||
## 🐷 演示图
|
|
||||||
|
|
||||||
### 系统功能
|
|
||||||
|
|
||||||
| 模块 | biu | biu | biu |
|
|
||||||
|----------|--------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------|
|
|
||||||
| 登录 & 首页 |  |  |  |
|
|
||||||
| 用户 |  |  | - |
|
|
||||||
| 租户 & 套餐 |  |  | - |
|
|
||||||
| 部门 & 岗位 |  |  | - |
|
|
||||||
| 菜单 & 角色 |  |  | - |
|
|
||||||
| 审计日志 |  |  | - |
|
|
||||||
| 短信 |  |  |  |
|
|
||||||
| 字典 |  |  | - |
|
|
||||||
| 错误码 & 通知 |  |  | - |
|
|
||||||
|
|
||||||
### 工作流程
|
|
||||||
|
|
||||||
| 模块 | biu | biu | biu |
|
|
||||||
|---------|------------------------------------------------------------------------|------------------------------------------------------------------------|------------------------------------------------------------------------|
|
|
||||||
| 流程模型 |  |  |  |
|
|
||||||
| 表单 & 分组 |  |  | - |
|
|
||||||
| 我的流程 |  |  |  |
|
|
||||||
| 待办 & 已办 |  |  |  |
|
|
||||||
| OA 请假 |  |  |  |
|
|
||||||
|
|
||||||
### 支付系统
|
|
||||||
|
|
||||||
| 模块 | biu | biu | biu |
|
|
||||||
|---------|------------------------------------------------------------------|------------------------------------------------------------------------|------------------------------------------------------------------------|
|
|
||||||
| 商家 & 应用 |  |  |  |
|
|
||||||
| 支付 & 退款 |  |  | --- |
|
|
||||||
|
|
||||||
### 基础设施
|
|
||||||
|
|
||||||
| 模块 | biu | biu | biu |
|
|
||||||
|---------------|----------------------------------------------------------------------|--------------------------------------------------------------------|------------------------------------------------------------------|
|
|
||||||
| 代码生成 |  |  | - |
|
|
||||||
| 文档 |  |  | - |
|
|
||||||
| 文件 & 配置 |  |  |  |
|
|
||||||
| 定时任务 |  |  | - |
|
|
||||||
| API 日志 |  |  | - |
|
|
||||||
| MySQL & Redis |  |  | - |
|
|
||||||
| 监控平台 |  |  |  |
|
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
rsync -v ../yudao-server/target/yudao-server.jar root@47.108.56.75:/www/wwwroot/yudao/yudao-server.jar
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "zsw-farm",
|
||||||
|
"lockfileVersion": 2,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {}
|
||||||
|
}
|
||||||
@@ -13,12 +13,13 @@
|
|||||||
<!-- Server 主项目 -->
|
<!-- Server 主项目 -->
|
||||||
<module>yudao-server</module>
|
<module>yudao-server</module>
|
||||||
<!-- 各种 module 拓展 -->
|
<!-- 各种 module 拓展 -->
|
||||||
<module>yudao-module-member</module>
|
|
||||||
<module>yudao-module-bpm</module>
|
<module>yudao-module-bpm</module>
|
||||||
|
<module>yudao-module-member</module>
|
||||||
<module>yudao-module-system</module>
|
<module>yudao-module-system</module>
|
||||||
<module>yudao-module-infra</module>
|
<module>yudao-module-infra</module>
|
||||||
<module>yudao-module-pay</module>
|
<module>yudao-module-pay</module>
|
||||||
<module>zsw-farm</module>
|
<module>zsw-bxg</module>
|
||||||
|
<module>zsw-spi</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<name>${project.artifactId}</name>
|
<name>${project.artifactId}</name>
|
||||||
@@ -48,6 +49,12 @@
|
|||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<version>2.7.4</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
@@ -60,6 +67,9 @@
|
|||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>${maven-surefire-plugin.version}</version>
|
<version>${maven-surefire-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<!-- maven-compiler-plugin 插件,解决 Lombok + MapStruct 组合 -->
|
<!-- maven-compiler-plugin 插件,解决 Lombok + MapStruct 组合 -->
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|||||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
BIN
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
只需要 vue_pro 和 vue_pro_bxg 两个数据库
|
||||||
Binary file not shown.
Binary file not shown.
@@ -14,6 +14,7 @@
|
|||||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
<skipTest>true</skipTest>
|
||||||
<revision>1.6.2-snapshot</revision>
|
<revision>1.6.2-snapshot</revision>
|
||||||
<!-- 统一依赖管理 -->
|
<!-- 统一依赖管理 -->
|
||||||
<spring.boot.version>2.5.10</spring.boot.version>
|
<spring.boot.version>2.5.10</spring.boot.version>
|
||||||
@@ -22,7 +23,7 @@
|
|||||||
<swagger-annotations.version>1.5.22</swagger-annotations.version>
|
<swagger-annotations.version>1.5.22</swagger-annotations.version>
|
||||||
<servlet.versoin>2.5</servlet.versoin>
|
<servlet.versoin>2.5</servlet.versoin>
|
||||||
<!-- DB 相关 -->
|
<!-- DB 相关 -->
|
||||||
<mysql.version>5.1.46</mysql.version>
|
<mysql.version>8.0.23</mysql.version>
|
||||||
<druid.version>1.2.8</druid.version>
|
<druid.version>1.2.8</druid.version>
|
||||||
<mybatis-plus.version>3.4.3.4</mybatis-plus.version>
|
<mybatis-plus.version>3.4.3.4</mybatis-plus.version>
|
||||||
<dynamic-datasource.version>3.5.0</dynamic-datasource.version>
|
<dynamic-datasource.version>3.5.0</dynamic-datasource.version>
|
||||||
@@ -47,7 +48,7 @@
|
|||||||
<!-- 工具类相关 -->
|
<!-- 工具类相关 -->
|
||||||
<lombok.version>1.18.20</lombok.version>
|
<lombok.version>1.18.20</lombok.version>
|
||||||
<mapstruct.version>1.4.1.Final</mapstruct.version>
|
<mapstruct.version>1.4.1.Final</mapstruct.version>
|
||||||
<hutool.version>5.6.1</hutool.version>
|
<hutool.version>5.8.0.M1</hutool.version>
|
||||||
<easyexcel.verion>2.2.7</easyexcel.verion>
|
<easyexcel.verion>2.2.7</easyexcel.verion>
|
||||||
<velocity.version>2.2</velocity.version>
|
<velocity.version>2.2</velocity.version>
|
||||||
<screw.version>1.0.5</screw.version>
|
<screw.version>1.0.5</screw.version>
|
||||||
|
|||||||
@@ -127,6 +127,12 @@
|
|||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>transmittable-thread-local</artifactId>
|
<artifactId>transmittable-thread-local</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.pagehelper</groupId>
|
||||||
|
<artifactId>pagehelper</artifactId>
|
||||||
|
<version>5.3.0</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
+119
@@ -0,0 +1,119 @@
|
|||||||
|
|
||||||
|
package cn.iocoder.yudao.framework.common.exception;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API 响应码
|
||||||
|
* @author hupeng
|
||||||
|
* @date 2020-04-30
|
||||||
|
*/
|
||||||
|
public enum ApiCode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作成功
|
||||||
|
**/
|
||||||
|
SUCCESS(200, "操作成功"),
|
||||||
|
/**
|
||||||
|
* 登录状态失效 请重新登录
|
||||||
|
**/
|
||||||
|
UNAUTHORIZED(401, "登录状态失效 请重新登录"),
|
||||||
|
/**
|
||||||
|
* 没有权限
|
||||||
|
**/
|
||||||
|
NOT_PERMISSION(403, "没有权限"),
|
||||||
|
/**
|
||||||
|
* 你请求的资源不存在
|
||||||
|
**/
|
||||||
|
NOT_FOUND(404, "你请求的资源不存在"),
|
||||||
|
/**
|
||||||
|
* 操作失败
|
||||||
|
**/
|
||||||
|
FAIL(500, "操作失败"),
|
||||||
|
/**
|
||||||
|
* 登录失败
|
||||||
|
**/
|
||||||
|
LOGIN_EXCEPTION(4000, "登录失败"),
|
||||||
|
/**
|
||||||
|
* 系统异常
|
||||||
|
**/
|
||||||
|
SYSTEM_EXCEPTION(5000, "系统异常"),
|
||||||
|
/**
|
||||||
|
* 请求参数校验异常
|
||||||
|
**/
|
||||||
|
PARAMETER_EXCEPTION(5001, "请求参数校验异常"),
|
||||||
|
/**
|
||||||
|
* 请求参数解析异常
|
||||||
|
**/
|
||||||
|
PARAMETER_PARSE_EXCEPTION(5002, "请求参数解析异常"),
|
||||||
|
/**
|
||||||
|
* HTTP内容类型异常
|
||||||
|
**/
|
||||||
|
HTTP_MEDIA_TYPE_EXCEPTION(5003, "HTTP内容类型异常"),
|
||||||
|
/**
|
||||||
|
* 系统处理异常
|
||||||
|
**/
|
||||||
|
YSHOP_SYSTEM_EXCEPTION(5100, "系统处理异常"),
|
||||||
|
/**
|
||||||
|
* 业务处理异常
|
||||||
|
**/
|
||||||
|
BUSINESS_EXCEPTION(5101, "业务处理异常"),
|
||||||
|
/**
|
||||||
|
* 数据库处理异常
|
||||||
|
**/
|
||||||
|
DAO_EXCEPTION(5102, "数据库处理异常"),
|
||||||
|
/**
|
||||||
|
* 验证码校验异常
|
||||||
|
**/
|
||||||
|
VERIFICATION_CODE_EXCEPTION(5103, "验证码校验异常"),
|
||||||
|
/**
|
||||||
|
* 登录授权异常
|
||||||
|
**/
|
||||||
|
AUTHENTICATION_EXCEPTION(5104, "登录授权异常"),
|
||||||
|
/**
|
||||||
|
* 没有访问权限
|
||||||
|
**/
|
||||||
|
UNAUTHENTICATED_EXCEPTION(5105, "没有访问权限"),
|
||||||
|
/**
|
||||||
|
* 没有访问权限
|
||||||
|
**/
|
||||||
|
UNAUTHORIZED_EXCEPTION(5106, "没有访问权限"),
|
||||||
|
/**
|
||||||
|
* JWT Token解析异常
|
||||||
|
**/
|
||||||
|
JWTDECODE_EXCEPTION(5107, "Token解析异常"),
|
||||||
|
|
||||||
|
HTTP_REQUEST_METHOD_NOT_SUPPORTED_EXCEPTION(5108, "METHOD NOT SUPPORTED"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问次数受限制
|
||||||
|
**/
|
||||||
|
BAD_LIMIT_EXCEPTION(5109, "访问次数受限制"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int code;
|
||||||
|
private final String message;
|
||||||
|
|
||||||
|
ApiCode(final int code, final String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApiCode getApiCode(int code) {
|
||||||
|
ApiCode[] ecs = ApiCode.values();
|
||||||
|
for (ApiCode ec : ecs) {
|
||||||
|
if (ec.getCode() == code) {
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
package cn.iocoder.yudao.framework.common.exception;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义异常
|
||||||
|
* @author hupeng
|
||||||
|
* @date 2020-04-30
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ShopException extends RuntimeException{
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -2470461654663264392L;
|
||||||
|
|
||||||
|
private Integer errorCode;
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public ShopException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShopException(String message) {
|
||||||
|
super(message);
|
||||||
|
this.errorCode = ApiCode.FAIL.getCode();
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShopException(Integer errorCode, String message) {
|
||||||
|
super(message);
|
||||||
|
this.errorCode = errorCode;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShopException(ApiCode apiCode) {
|
||||||
|
super(apiCode.getMessage());
|
||||||
|
this.errorCode = apiCode.getCode();
|
||||||
|
this.message = apiCode.getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShopException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShopException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+3
@@ -36,6 +36,9 @@ public interface GlobalErrorCodeConstants {
|
|||||||
|
|
||||||
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
|
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
|
||||||
|
|
||||||
|
//农作物出入管理
|
||||||
|
ErrorCode CROP_RECORD_CANT_NEGATIVE = new ErrorCode(10001, "出库失败,农作物库存小于出库数量");
|
||||||
|
|
||||||
static boolean isMatch(Integer code) {
|
static boolean isMatch(Integer code) {
|
||||||
return code != null
|
return code != null
|
||||||
&& code >= SUCCESS.getCode() && code <= UNKNOWN.getCode();
|
&& code >= SUCCESS.getCode() && code <= UNKNOWN.getCode();
|
||||||
|
|||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.page;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel(value = "PageDTO", description = "分页对象")
|
||||||
|
public class PageDTO implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ApiModelProperty("页码")
|
||||||
|
private Integer pageNum = 1;
|
||||||
|
|
||||||
|
@ApiModelProperty("每页数量")
|
||||||
|
private Integer pageSize = 10;
|
||||||
|
|
||||||
|
@ApiModelProperty("搜索关键字")
|
||||||
|
private String searchKey;
|
||||||
|
}
|
||||||
+98
@@ -0,0 +1,98 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.page;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import com.github.pagehelper.PageHelper;
|
||||||
|
import com.github.pagehelper.PageInfo;
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页工具类
|
||||||
|
*
|
||||||
|
* @author xggz <yyimba@qq.com>
|
||||||
|
* @since 2021/6/4 11:50
|
||||||
|
*/
|
||||||
|
@UtilityClass
|
||||||
|
public class PageUtil<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换PageHelper插件的分页数据
|
||||||
|
*
|
||||||
|
* @param pageInfo
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public <T> PageVO<T> convertPageInfo(PageInfo<T> pageInfo) {
|
||||||
|
return BeanUtil.copyProperties(pageInfo, PageVO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换PageHelper插件的分页数据
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public <T> PageVO<T> convertPageInfo(List<T> list) {
|
||||||
|
return BeanUtil.copyProperties(new PageInfo<T>(list), PageVO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制分页数据
|
||||||
|
*
|
||||||
|
* @param sourcePage
|
||||||
|
* @param results
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public <T> PageVO<T> copyPage(Object sourcePage, List<T> results) {
|
||||||
|
PageVO<T> targetPage = BeanUtil.copyProperties(sourcePage, PageVO.class);
|
||||||
|
targetPage.setList(results);
|
||||||
|
return targetPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回空白的分页对象
|
||||||
|
*
|
||||||
|
* @param pageNum
|
||||||
|
* @param pageSize
|
||||||
|
* @param dataClass
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public <T> PageVO<T> emptyPage(Integer pageNum, Integer pageSize, Class<T> dataClass) {
|
||||||
|
PageVO page = new PageVO<>();
|
||||||
|
page.setPageNum(pageNum);
|
||||||
|
page.setPageSize(pageSize);
|
||||||
|
page.setSize(0);
|
||||||
|
page.setPages(0);
|
||||||
|
page.setTotal(0);
|
||||||
|
page.setHasNextPage(false);
|
||||||
|
page.setHasPreviousPage(false);
|
||||||
|
page.setList(new ArrayList());
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回空白的分页对象
|
||||||
|
*
|
||||||
|
* @param pageDTO
|
||||||
|
* @param dataClass
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public <T> PageVO<T> emptyPage(PageDTO pageDTO, Class<T> dataClass) {
|
||||||
|
return emptyPage(pageDTO.getPageNum(), pageDTO.getPageSize(), dataClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用PageHelper设置分页参数
|
||||||
|
*
|
||||||
|
* @param pageDTO
|
||||||
|
*/
|
||||||
|
public void startPage(PageDTO pageDTO) {
|
||||||
|
PageHelper.startPage(pageDTO.getPageNum(), pageDTO.getPageSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
package cn.iocoder.yudao.framework.common.page;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页结果
|
||||||
|
*
|
||||||
|
* @author xggz <yyimba@qq.com>
|
||||||
|
* @since 2021/6/4 10:53
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel(value = "PageVO", description = "分页结果")
|
||||||
|
public class PageVO<T> implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ApiModelProperty("当前页")
|
||||||
|
private int pageNum;
|
||||||
|
|
||||||
|
@ApiModelProperty("每页的数量")
|
||||||
|
private int pageSize;
|
||||||
|
|
||||||
|
@ApiModelProperty("当前页的数量")
|
||||||
|
private int size;
|
||||||
|
|
||||||
|
@ApiModelProperty("总页数")
|
||||||
|
private int pages;
|
||||||
|
|
||||||
|
@ApiModelProperty("是否有前一页")
|
||||||
|
private boolean hasPreviousPage = false;
|
||||||
|
|
||||||
|
@ApiModelProperty("是否有后一页")
|
||||||
|
private boolean hasNextPage = false;
|
||||||
|
|
||||||
|
@ApiModelProperty("总记录数")
|
||||||
|
private long total;
|
||||||
|
|
||||||
|
@ApiModelProperty("结果集")
|
||||||
|
private List<T> list;
|
||||||
|
}
|
||||||
+225
@@ -0,0 +1,225 @@
|
|||||||
|
|
||||||
|
package cn.iocoder.yudao.framework.common.pojo;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.ApiCode;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API 返回结果
|
||||||
|
* @author hupeng
|
||||||
|
* @date 2020-04-30
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ApiResult<T> implements Serializable {
|
||||||
|
private static final long serialVersionUID = 8004487252556526569L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应码
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "响应码")
|
||||||
|
private int status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否成功
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "是否成功:成功true,失败false")
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应消息
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "响应消息")
|
||||||
|
private String msg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总条数
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "总条数")
|
||||||
|
private Integer total;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总页数
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "总页数")
|
||||||
|
private Integer totalPage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应数据
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "响应数据")
|
||||||
|
private T data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应时间
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "响应时间")
|
||||||
|
//@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||||
|
private Date time;
|
||||||
|
|
||||||
|
public ApiResult() {
|
||||||
|
time = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApiResult<Boolean> result(boolean flag){
|
||||||
|
if (flag){
|
||||||
|
return ok();
|
||||||
|
}
|
||||||
|
return fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApiResult<Boolean> result(ApiCode apiCode){
|
||||||
|
return result(apiCode,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ApiResult<T> result(ApiCode apiCode, T data){
|
||||||
|
return result(apiCode,null,data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ApiResult<T> resultPage(Integer total, Integer totalPage, T data){
|
||||||
|
return (ApiResult<T>) ApiResult.builder()
|
||||||
|
.total(total)
|
||||||
|
.totalPage(totalPage)
|
||||||
|
.status(200)
|
||||||
|
.msg(null)
|
||||||
|
.data(data)
|
||||||
|
.success(true)
|
||||||
|
.time(new Date())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static <T> ApiResult<T> result(ApiCode apiCode, String message, T data){
|
||||||
|
boolean success = false;
|
||||||
|
if (apiCode.getCode() == ApiCode.SUCCESS.getCode()){
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(message)){
|
||||||
|
message = apiCode.getMessage();
|
||||||
|
}
|
||||||
|
return (ApiResult<T>) ApiResult.builder()
|
||||||
|
.status(apiCode.getCode())
|
||||||
|
.msg(message)
|
||||||
|
.data(data)
|
||||||
|
.success(success)
|
||||||
|
.time(new Date())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApiResult<Boolean> ok(){
|
||||||
|
return ok(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ApiResult<T> ok(T data){
|
||||||
|
return result(ApiCode.SUCCESS,data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ApiResult<T> ok(T data, String message){
|
||||||
|
return result(ApiCode.SUCCESS,message,data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApiResult<Map<String,Object>> okMap(String key, Object value){
|
||||||
|
Map<String,Object> map = new HashMap<>(1);
|
||||||
|
map.put(key,value);
|
||||||
|
return ok(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApiResult<Boolean> fail(ApiCode apiCode){
|
||||||
|
return result(apiCode,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApiResult<String> fail(String message){
|
||||||
|
return result(ApiCode.FAIL,message,null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ApiResult<T> fail(ApiCode apiCode, T data){
|
||||||
|
if (ApiCode.SUCCESS == apiCode){
|
||||||
|
throw new RuntimeException("失败结果状态码不能为" + ApiCode.SUCCESS.getCode());
|
||||||
|
}
|
||||||
|
return result(apiCode,data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApiResult<String> fail(Integer errorCode, String message){
|
||||||
|
return new ApiResult<String>()
|
||||||
|
.setSuccess(false)
|
||||||
|
.setStatus(errorCode)
|
||||||
|
.setMsg(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApiResult<Map<String,Object>> fail(String key, Object value){
|
||||||
|
Map<String,Object> map = new HashMap<>(1);
|
||||||
|
map.put(key,value);
|
||||||
|
return result(ApiCode.FAIL,map);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ApiResult<T> resultPage(T t, int limit){
|
||||||
|
List<Object> list = (List<Object>) t;
|
||||||
|
int count = list.size() / limit;
|
||||||
|
if (list.size() == 0) {
|
||||||
|
return (ApiResult<T>) ApiResult.builder()
|
||||||
|
.total(0)
|
||||||
|
.totalPage(0)
|
||||||
|
.status(200)
|
||||||
|
.msg(null)
|
||||||
|
.data(list)
|
||||||
|
.success(true)
|
||||||
|
.time(new Date())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
if (list.size() <= limit) {
|
||||||
|
return (ApiResult<T>) ApiResult.builder()
|
||||||
|
.total(list.size())
|
||||||
|
.totalPage(1)
|
||||||
|
.status(200)
|
||||||
|
.msg(null)
|
||||||
|
.data(list)
|
||||||
|
.success(true)
|
||||||
|
.time(new Date())
|
||||||
|
.build();
|
||||||
|
} else if (count % limit == 0) {
|
||||||
|
return (ApiResult<T>) ApiResult.builder()
|
||||||
|
.total(list.size())
|
||||||
|
.totalPage(count)
|
||||||
|
.status(200)
|
||||||
|
.msg(null)
|
||||||
|
.data(list)
|
||||||
|
.success(true)
|
||||||
|
.time(new Date())
|
||||||
|
.build();
|
||||||
|
} else {
|
||||||
|
return (ApiResult<T>) ApiResult.builder()
|
||||||
|
.total(list.size())
|
||||||
|
.totalPage(count+1)
|
||||||
|
.status(200)
|
||||||
|
.msg(null)
|
||||||
|
.data(list)
|
||||||
|
.success(true)
|
||||||
|
.time(new Date())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApiResult<Boolean> fail() {
|
||||||
|
return fail(ApiCode.FAIL);
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -21,10 +21,10 @@ public class PageParam implements Serializable {
|
|||||||
@Min(value = 1, message = "页码最小值为 1")
|
@Min(value = 1, message = "页码最小值为 1")
|
||||||
private Integer pageNo = PAGE_NO;
|
private Integer pageNo = PAGE_NO;
|
||||||
|
|
||||||
@ApiModelProperty(value = "每页条数,最大值为 100", required = true, example = "10")
|
@ApiModelProperty(value = "每页条数,最大值为 500", required = true, example = "10")
|
||||||
@NotNull(message = "每页条数不能为空")
|
@NotNull(message = "每页条数不能为空")
|
||||||
@Min(value = 1, message = "页码最小值为 1")
|
@Min(value = 1, message = "页码最小值为 1")
|
||||||
@Max(value = 100, message = "页码最大值为 100")
|
@Max(value = 500, message = "页码最大值为 500")
|
||||||
private Integer pageSize = PAGE_SIZE;
|
private Integer pageSize = PAGE_SIZE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,10 @@
|
|||||||
<artifactId>yudao-spring-boot-starter-test</artifactId>
|
<artifactId>yudao-spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.data</groupId>
|
||||||
|
<artifactId>spring-data-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
+16
-3
@@ -2,10 +2,10 @@ package cn.iocoder.yudao.framework.datapermission.core.dept.rule;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService;
|
|
||||||
import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
|
import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService;
|
||||||
|
import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
|
||||||
import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule;
|
import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
||||||
@@ -13,7 +13,7 @@ import cn.iocoder.yudao.framework.security.core.LoginUser;
|
|||||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.sf.jsqlparser.expression.Alias;
|
import net.sf.jsqlparser.expression.Alias;
|
||||||
import net.sf.jsqlparser.expression.Expression;
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
@@ -23,6 +23,7 @@ import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
|||||||
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
|
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
|
||||||
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
||||||
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
||||||
|
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -146,6 +147,7 @@ public class DeptDataPermissionRule implements DataPermissionRule {
|
|||||||
new ExpressionList(CollectionUtils.convertList(deptIds, LongValue::new)));
|
new ExpressionList(CollectionUtils.convertList(deptIds, LongValue::new)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
private Expression buildUserExpression(String tableName, Alias tableAlias, Boolean self, Long userId) {
|
private Expression buildUserExpression(String tableName, Alias tableAlias, Boolean self, Long userId) {
|
||||||
// 如果不查看自己,则无需作为条件
|
// 如果不查看自己,则无需作为条件
|
||||||
if (Boolean.FALSE.equals(self)) {
|
if (Boolean.FALSE.equals(self)) {
|
||||||
@@ -155,6 +157,17 @@ public class DeptDataPermissionRule implements DataPermissionRule {
|
|||||||
if (StrUtil.isEmpty(columnName)) {
|
if (StrUtil.isEmpty(columnName)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Long cpUserId = deptDataPermissionService.getCpUserIdBySystemUserId(userId);
|
||||||
|
if (tableName.equals("farm_project")){
|
||||||
|
Expression projectSql = CCJSqlParserUtil.parseCondExpression("(creator = " + userId + " or JSON_CONTAINS(members, '"+ cpUserId +"'))");
|
||||||
|
return projectSql;
|
||||||
|
}
|
||||||
|
if (tableName.equals("farm_task")){
|
||||||
|
Expression taskSql = CCJSqlParserUtil.parseCondExpression(" (creator = " + userId + " or JSON_CONTAINS(executor_person, '"+ cpUserId +"')" +
|
||||||
|
" or main_person = " + cpUserId +")");
|
||||||
|
return taskSql;
|
||||||
|
}
|
||||||
// 拼接条件
|
// 拼接条件
|
||||||
return new EqualsTo(MyBatisUtils.buildColumn(tableName, tableAlias, columnName), new LongValue(userId));
|
return new EqualsTo(MyBatisUtils.buildColumn(tableName, tableAlias, columnName), new LongValue(userId));
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -19,4 +19,6 @@ public interface DeptDataPermissionFrameworkService {
|
|||||||
*/
|
*/
|
||||||
DeptDataPermissionRespDTO getDeptDataPermission(LoginUser loginUser);
|
DeptDataPermissionRespDTO getDeptDataPermission(LoginUser loginUser);
|
||||||
|
|
||||||
|
Long getCpUserIdBySystemUserId(Long id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -49,7 +49,9 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
|
|||||||
*/
|
*/
|
||||||
public final void init() {
|
public final void init() {
|
||||||
doInit();
|
doInit();
|
||||||
log.info("[init][配置({}) 初始化完成]", config);
|
// PayClientConfig
|
||||||
|
// log.info("[init][配置({}) 初始化完成]", config);
|
||||||
|
log.info("[init][配置({}) 初始化完成]", PayClientConfig.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+12
@@ -2,6 +2,8 @@ package cn.iocoder.yudao.framework.tenant.core.context;
|
|||||||
|
|
||||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 多租户上下文 Holder
|
* 多租户上下文 Holder
|
||||||
*
|
*
|
||||||
@@ -58,6 +60,16 @@ public class TenantContextHolder {
|
|||||||
return Boolean.TRUE.equals(IGNORE.get());
|
return Boolean.TRUE.equals(IGNORE.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> T apply(Long tenantId, Supplier<T> func){
|
||||||
|
Long oldTenant = TenantContextHolder.getTenantId();
|
||||||
|
try {
|
||||||
|
TenantContextHolder.setTenantId(tenantId);
|
||||||
|
return func.get();
|
||||||
|
}finally {
|
||||||
|
TenantContextHolder.setTenantId(oldTenant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void clear() {
|
public static void clear() {
|
||||||
TENANT_ID.remove();
|
TENANT_ID.remove();
|
||||||
IGNORE.remove();
|
IGNORE.remove();
|
||||||
|
|||||||
@@ -12,7 +12,8 @@
|
|||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>${project.artifactId}</name>
|
<name>${project.artifactId}</name>
|
||||||
<description>微信拓展
|
<description>
|
||||||
|
微信拓展
|
||||||
1. 基于 weixin-java-mp 库,对接微信公众号平台。目前主要解决微信公众号的支付场景。
|
1. 基于 weixin-java-mp 库,对接微信公众号平台。目前主要解决微信公众号的支付场景。
|
||||||
</description>
|
</description>
|
||||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||||
@@ -31,13 +32,33 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 三方云服务相关 -->
|
<!-- 三方云服务相关 -->
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.github.binarywang/weixin-java-mp -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.binarywang</groupId>
|
<groupId>com.github.binarywang</groupId>
|
||||||
<!-- <artifactId>weixin-java-mp</artifactId>-->
|
<artifactId>weixin-java-mp</artifactId>
|
||||||
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
|
<version>4.3.0</version>
|
||||||
<version>4.1.9.B</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- TODO 芋艿:清理 -->
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.github.binarywang/weixin-java-miniapp -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.binarywang</groupId>
|
||||||
|
<artifactId>weixin-java-miniapp</artifactId>
|
||||||
|
<version>4.3.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.github.binarywang/weixin-java-cp -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.binarywang</groupId>
|
||||||
|
<artifactId>weixin-java-cp</artifactId>
|
||||||
|
<version>4.3.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-extension</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package cn.iocoder.yudao.config;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import me.chanjar.weixin.cp.api.WxCpService;
|
||||||
|
import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
|
||||||
|
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Slf4j
|
||||||
|
public class WxCpConfigure {
|
||||||
|
@Value("${wxcp.corpId}")
|
||||||
|
private String corpId;
|
||||||
|
@Value("${wxcp.secret}")
|
||||||
|
private String secret;
|
||||||
|
@Value("${wxcp.agentId}")
|
||||||
|
private Integer agentId;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Scope("prototype")
|
||||||
|
public WxCpService wxCpService(){
|
||||||
|
|
||||||
|
WxCpDefaultConfigImpl config = new WxCpDefaultConfigImpl();
|
||||||
|
config.setCorpId(corpId);
|
||||||
|
config.setCorpSecret(secret);
|
||||||
|
config.setAgentId(agentId);
|
||||||
|
|
||||||
|
WxCpServiceImpl wxCpService = new WxCpServiceImpl();
|
||||||
|
wxCpService.setWxCpConfigStorage(config);
|
||||||
|
|
||||||
|
log.info("企业微信初始化:{}",wxCpService);
|
||||||
|
|
||||||
|
return wxCpService;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
package cn.iocoder.yudao.config;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||||
|
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
|
||||||
|
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.context.annotation.ScopedProxyMode;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by kellen on 2020/5/3. 微信小程序服务配置
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@Slf4j
|
||||||
|
public class WxMaConfiguration {
|
||||||
|
|
||||||
|
@Value("${wxma.app_id}")
|
||||||
|
private String appId;
|
||||||
|
@Value("${wxma.app_secret}")
|
||||||
|
private String appSecret;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||||
|
public WxMaService wxMaService() {
|
||||||
|
|
||||||
|
WxMaDefaultConfigImpl wxMaDefaultConfig = new WxMaDefaultConfigImpl();
|
||||||
|
wxMaDefaultConfig.setAppid(appId);
|
||||||
|
wxMaDefaultConfig.setSecret(appSecret);
|
||||||
|
|
||||||
|
WxMaServiceImpl wxMaService = new WxMaServiceImpl();
|
||||||
|
wxMaService.setWxMaConfig(wxMaDefaultConfig);
|
||||||
|
|
||||||
|
return wxMaService;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
cn.iocoder.yudao.config.WxCpConfigure,\
|
||||||
|
cn.iocoder.yudao.config.WxMaConfiguration
|
||||||
+1
-1
@@ -17,7 +17,7 @@ public class S3FileClientTest {
|
|||||||
// 配置成你自己的
|
// 配置成你自己的
|
||||||
config.setAccessKey("admin");
|
config.setAccessKey("admin");
|
||||||
config.setAccessSecret("password");
|
config.setAccessSecret("password");
|
||||||
config.setBucket("yudaoyuanma");
|
config.setBucket("zsw");
|
||||||
config.setDomain(null);
|
config.setDomain(null);
|
||||||
// 默认 9000 endpoint
|
// 默认 9000 endpoint
|
||||||
config.setEndpoint("http://127.0.0.1:9000");
|
config.setEndpoint("http://127.0.0.1:9000");
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
<artifactId>yudao-common</artifactId>
|
<artifactId>yudao-common</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Web 相关 -->
|
<!-- Web 相关 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.iocoder.boot</groupId>
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
|||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
package cn.iocoder.yudao.framework.quartz.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||||
|
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.quartz.*;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnProperty(prefix = "spring.quartz", name = "job-store-type", havingValue = "jdbc")
|
||||||
|
@Import(DatabaseInitializationDependencyConfigurer.class)
|
||||||
|
@EnableConfigurationProperties(QuartzProperties.class)
|
||||||
|
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
|
||||||
|
LiquibaseAutoConfiguration.class, FlywayAutoConfiguration.class })
|
||||||
|
public class JdbcStoreTypeConfiguration {
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Order(0)
|
||||||
|
public SchedulerFactoryBeanCustomizer dataSourceCustomizer(QuartzProperties properties,
|
||||||
|
DataSource dataSource,
|
||||||
|
@QuartzDataSource ObjectProvider<DataSource> quartzDataSource,
|
||||||
|
TransactionManager transactionManager
|
||||||
|
) {
|
||||||
|
return (schedulerFactoryBean) -> {
|
||||||
|
DataSource dataSourceToUse = getDataSource(dataSource, quartzDataSource);
|
||||||
|
schedulerFactoryBean.setDataSource(dataSourceToUse);
|
||||||
|
schedulerFactoryBean.setTransactionManager((PlatformTransactionManager) transactionManager);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataSource getDataSource(DataSource dataSource, ObjectProvider<DataSource> quartzDataSource) {
|
||||||
|
DataSource dataSourceIfAvailable = quartzDataSource.getIfAvailable();
|
||||||
|
return (dataSourceIfAvailable != null) ? dataSourceIfAvailable : dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlatformTransactionManager getTransactionManager(
|
||||||
|
ObjectProvider<PlatformTransactionManager> transactionManager,
|
||||||
|
ObjectProvider<PlatformTransactionManager> quartzTransactionManager) {
|
||||||
|
PlatformTransactionManager transactionManagerIfAvailable = quartzTransactionManager.getIfAvailable();
|
||||||
|
return (transactionManagerIfAvailable != null) ? transactionManagerIfAvailable
|
||||||
|
: transactionManager.getIfUnique();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public QuartzDataSourceInitializer quartzDataSourceInitializer(DataSource dataSource,
|
||||||
|
@QuartzDataSource ObjectProvider<DataSource> quartzDataSource, ResourceLoader resourceLoader,
|
||||||
|
QuartzProperties properties) {
|
||||||
|
DataSource dataSourceToUse = getDataSource(dataSource, quartzDataSource);
|
||||||
|
return new QuartzDataSourceInitializer(dataSourceToUse, resourceLoader, properties);
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
cn.iocoder.yudao.framework.quartz.config.YudaoQuartzAutoConfiguration,\
|
cn.iocoder.yudao.framework.quartz.config.YudaoQuartzAutoConfiguration,\
|
||||||
cn.iocoder.yudao.framework.quartz.config.YudaoAsyncAutoConfiguration
|
cn.iocoder.yudao.framework.quartz.config.YudaoAsyncAutoConfiguration,\
|
||||||
|
cn.iocoder.yudao.framework.quartz.config.JdbcStoreTypeConfiguration
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<mysql.version>5.1.46</mysql.version>
|
<mysql.version>8.0.23</mysql.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -46,10 +46,8 @@
|
|||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.baomidou</groupId>
|
|
||||||
<artifactId>dynamic-datasource-spring-boot-starter</artifactId> <!-- 多数据源 -->
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
+82
-2
@@ -1,22 +1,51 @@
|
|||||||
package cn.iocoder.yudao.framework.mybatis.config;
|
package cn.iocoder.yudao.framework.mybatis.config;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.handler.DefaultDBFieldHandler;
|
import cn.iocoder.yudao.framework.mybatis.core.handler.DefaultDBFieldHandler;
|
||||||
|
import com.alibaba.druid.pool.DruidDataSource;
|
||||||
|
import com.alibaba.druid.stat.DruidDataSourceStatManager;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.core.config.GlobalConfig;
|
||||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.session.SqlSession;
|
||||||
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
|
import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory;
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
import org.mybatis.spring.annotation.MapperScans;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.boot.autoconfigure.quartz.QuartzDataSource;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||||
|
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MyBaits 配置类
|
* MyBaits 配置类
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@Configuration
|
|
||||||
@MapperScan(value = "${yudao.info.base-package}", annotationClass = Mapper.class,
|
@MapperScans({
|
||||||
|
@MapperScan(basePackages ={"co.yixiang.**.service.mapper", "co.yixiang.config"},sqlSessionFactoryRef = "shangcheng"),
|
||||||
|
@MapperScan(basePackages = {"${yudao.info.base-package}", "cn.iocoder.yudao"}, annotationClass = Mapper.class,
|
||||||
lazyInitialization = "${mybatis.lazy-initialization:false}") // Mapper 懒加载,目前仅用于单元测试
|
lazyInitialization = "${mybatis.lazy-initialization:false}") // Mapper 懒加载,目前仅用于单元测试
|
||||||
|
})
|
||||||
|
@Configuration
|
||||||
|
@Slf4j
|
||||||
public class YudaoMybatisAutoConfiguration {
|
public class YudaoMybatisAutoConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@@ -31,4 +60,55 @@ public class YudaoMybatisAutoConfiguration {
|
|||||||
return new DefaultDBFieldHandler(); // 自动填充参数类
|
return new DefaultDBFieldHandler(); // 自动填充参数类
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean("dataSource")
|
||||||
|
@QuartzDataSource
|
||||||
|
@ConfigurationProperties("spring.datasource.dynamic.datasource.master")
|
||||||
|
public DataSource masterDataSource(){
|
||||||
|
return new DruidDataSource();
|
||||||
|
}
|
||||||
|
@Bean
|
||||||
|
@Primary
|
||||||
|
public SqlSessionFactory sqlSessionFactoryMaster(@Qualifier("dataSource") DataSource dataSource) throws Exception {
|
||||||
|
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
|
||||||
|
factory.setTypeEnumsPackage("cn.iocoder.yudao.module.farm.enums");
|
||||||
|
factory.setDataSource(dataSource);
|
||||||
|
return getSqlSessionFactory(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean("bxgDataSource")
|
||||||
|
@ConfigurationProperties("spring.datasource.dynamic.datasource.bxg")
|
||||||
|
public DataSource bxgDataSource(){
|
||||||
|
return new DruidDataSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean("shangcheng")
|
||||||
|
public SqlSessionFactory sqlSessionFactory(@Qualifier("bxgDataSource") DataSource dataSource) throws Exception {
|
||||||
|
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
|
||||||
|
factory.setDataSource(dataSource);
|
||||||
|
return getSqlSessionFactory(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private SqlSessionFactory getSqlSessionFactory(MybatisSqlSessionFactoryBean factory) throws Exception {
|
||||||
|
GlobalConfig globalConfig = new GlobalConfig();
|
||||||
|
GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig();
|
||||||
|
dbConfig.setIdType(IdType.AUTO);
|
||||||
|
globalConfig.setDbConfig(dbConfig);
|
||||||
|
globalConfig.setMetaObjectHandler(defaultMetaObjectHandler());
|
||||||
|
Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath*:/mapper/*/*.xml");
|
||||||
|
Arrays.stream(resources).forEach(resource -> {
|
||||||
|
log.info("master mapper:{}",resource.getFilename());
|
||||||
|
});
|
||||||
|
factory.setMapperLocations(resources);
|
||||||
|
factory.setPlugins(mybatisPlusInterceptor());
|
||||||
|
factory.setGlobalConfig(globalConfig);
|
||||||
|
return factory.getObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TransactionManager transactionManager(DataSource dataSource){
|
||||||
|
DataSourceTransactionManager manager = new DataSourceTransactionManager();
|
||||||
|
manager.setDataSource(dataSource);
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.mybatis.core.dataobject;
|
|||||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -21,11 +22,13 @@ public abstract class BaseDO implements Serializable {
|
|||||||
* 创建时间
|
* 创建时间
|
||||||
*/
|
*/
|
||||||
@TableField(fill = FieldFill.INSERT)
|
@TableField(fill = FieldFill.INSERT)
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
/**
|
/**
|
||||||
* 最后更新时间
|
* 最后更新时间
|
||||||
*/
|
*/
|
||||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
/**
|
/**
|
||||||
* 创建者,目前使用 SysUser 的 id 编号
|
* 创建者,目前使用 SysUser 的 id 编号
|
||||||
|
|||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
package cn.iocoder.yudao.framework.mybatis.core.dataobject;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName 公共模型
|
||||||
|
* @Author hupeng <610796224@qq.com>
|
||||||
|
* @Date 2020/6/13
|
||||||
|
**/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class BaseDomain implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|
||||||
|
@TableField(fill= FieldFill.INSERT)
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
@TableField(fill= FieldFill.UPDATE)
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
@TableLogic
|
||||||
|
@JsonIgnore
|
||||||
|
@TableField(fill= FieldFill.INSERT)
|
||||||
|
private Integer isDel;
|
||||||
|
}
|
||||||
+63
-17
@@ -1,10 +1,13 @@
|
|||||||
package cn.iocoder.yudao.framework.mybatis.core.handler;
|
package cn.iocoder.yudao.framework.mybatis.core.handler;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.ibatis.reflection.MetaObject;
|
import org.apache.ibatis.reflection.MetaObject;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@@ -15,33 +18,61 @@ import java.util.Objects;
|
|||||||
*
|
*
|
||||||
* @author hexiaowu
|
* @author hexiaowu
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
public class DefaultDBFieldHandler implements MetaObjectHandler {
|
public class DefaultDBFieldHandler implements MetaObjectHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void insertFill(MetaObject metaObject) {
|
public void insertFill(MetaObject metaObject) {
|
||||||
if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) {
|
// if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) {
|
||||||
BaseDO baseDO = (BaseDO) metaObject.getOriginalObject();
|
// BaseDO baseDO = (BaseDO) metaObject.getOriginalObject();
|
||||||
|
//
|
||||||
Date current = new Date();
|
// Date current = new Date();
|
||||||
// 创建时间为空,则以当前时间为插入时间
|
// // 创建时间为空,则以当前时间为插入时间
|
||||||
if (Objects.isNull(baseDO.getCreateTime())) {
|
// if (Objects.isNull(baseDO.getCreateTime())) {
|
||||||
baseDO.setCreateTime(current);
|
// baseDO.setCreateTime(current);
|
||||||
}
|
// }
|
||||||
// 更新时间为空,则以当前时间为更新时间
|
// // 更新时间为空,则以当前时间为更新时间
|
||||||
if (Objects.isNull(baseDO.getUpdateTime())) {
|
// if (Objects.isNull(baseDO.getUpdateTime())) {
|
||||||
baseDO.setUpdateTime(current);
|
// baseDO.setUpdateTime(current);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
Long userId = WebFrameworkUtils.getLoginUserId();
|
Long userId = WebFrameworkUtils.getLoginUserId();
|
||||||
// 当前登录用户不为空,创建人为空,则当前登录用户为创建人
|
// 当前登录用户不为空,创建人为空,则当前登录用户为创建人
|
||||||
if (Objects.nonNull(userId) && Objects.isNull(baseDO.getCreator())) {
|
if (metaObject.hasSetter("creator") && ObjectUtil.isNotEmpty(userId)) {
|
||||||
baseDO.setCreator(userId.toString());
|
this.setFieldValByName("creator", userId.toString(), metaObject);
|
||||||
}
|
}
|
||||||
// 当前登录用户不为空,更新人为空,则当前登录用户为更新人
|
|
||||||
if (Objects.nonNull(userId) && Objects.isNull(baseDO.getUpdater())) {
|
if (metaObject.hasSetter("updater") && ObjectUtil.isNotEmpty(userId)) {
|
||||||
baseDO.setUpdater(userId.toString());
|
this.setFieldValByName("updater", userId.toString(), metaObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timestamp time=new Timestamp(System.currentTimeMillis());
|
||||||
|
if (metaObject.hasSetter("createTime")) {
|
||||||
|
this.setFieldValByName("createTime", time, metaObject);
|
||||||
}
|
}
|
||||||
|
if (metaObject.hasSetter("updateTime")) {
|
||||||
|
this.setFieldValByName("updateTime", time, metaObject);
|
||||||
|
}
|
||||||
|
if (metaObject.hasSetter("createDate")) {
|
||||||
|
this.setFieldValByName("createDate", time, metaObject);
|
||||||
|
}
|
||||||
|
if (metaObject.hasSetter("updateDate")) {
|
||||||
|
this.setFieldValByName("updateDate", time, metaObject);
|
||||||
|
}
|
||||||
|
if (metaObject.hasSetter("delFlag")) {
|
||||||
|
this.setFieldValByName("delFlag", false, metaObject);
|
||||||
|
}
|
||||||
|
if (metaObject.hasSetter("isDel")) {
|
||||||
|
this.setFieldValByName("isDel", 0, metaObject);
|
||||||
|
}
|
||||||
|
if (metaObject.hasSetter("addTime")) {
|
||||||
|
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
||||||
|
this.setFieldValByName("addTime", Integer.valueOf(timestamp), metaObject);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -58,5 +89,20 @@ public class DefaultDBFieldHandler implements MetaObjectHandler {
|
|||||||
if (Objects.nonNull(userId) && Objects.isNull(modifier)) {
|
if (Objects.nonNull(userId) && Objects.isNull(modifier)) {
|
||||||
setFieldValByName("updater", userId.toString(), metaObject);
|
setFieldValByName("updater", userId.toString(), metaObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Timestamp time=new Timestamp(System.currentTimeMillis());
|
||||||
|
if (metaObject.hasSetter("updateTime")) {
|
||||||
|
this.setFieldValByName("updateTime", time, metaObject);
|
||||||
|
}
|
||||||
|
if (metaObject.hasSetter("updateDate")) {
|
||||||
|
this.setFieldValByName("updateDate", time, metaObject);
|
||||||
|
}
|
||||||
|
if (metaObject.hasSetter("delFlag")) {
|
||||||
|
this.setFieldValByName("delFlag", null, metaObject);
|
||||||
|
}
|
||||||
|
if (metaObject.hasSetter("createTime")) {
|
||||||
|
this.setFieldValByName("createTime", null, metaObject);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
package cn.iocoder.yudao.framework.mybatis.core.handler;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.type.CollectionType;
|
||||||
|
import org.apache.ibatis.type.BaseTypeHandler;
|
||||||
|
import org.apache.ibatis.type.JdbcType;
|
||||||
|
import org.apache.ibatis.type.MappedJdbcTypes;
|
||||||
|
import org.apache.ibatis.type.MappedTypes;
|
||||||
|
|
||||||
|
|
||||||
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zyj
|
||||||
|
*/
|
||||||
|
@MappedJdbcTypes(JdbcType.VARCHAR) // 数据库中该字段存储的类型
|
||||||
|
@MappedTypes(List.class) // 需要转换的对象
|
||||||
|
public class ListIntToListLongTypeHandler extends BaseTypeHandler<List<Long>> {
|
||||||
|
|
||||||
|
private static ObjectMapper mObjectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNonNullParameter(PreparedStatement preparedStatement, int i, List<Long> longs, JdbcType jdbcType) throws SQLException {
|
||||||
|
String json = JSONUtil.toJsonStr(longs);
|
||||||
|
preparedStatement.setObject(i, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Long> getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
|
||||||
|
String value = resultSet.getString(columnName);
|
||||||
|
return getLongs(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Long> getNullableResult(ResultSet resultSet, int i) throws SQLException {
|
||||||
|
String value = resultSet.getString(i);
|
||||||
|
return getLongs(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Long> getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
|
||||||
|
String value = callableStatement.getString(i);
|
||||||
|
return getLongs(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Long> getLongs(String value) {
|
||||||
|
if (ObjectUtil.isNotEmpty(value)) {
|
||||||
|
try {
|
||||||
|
CollectionType type = mObjectMapper.getTypeFactory().constructCollectionType(ArrayList.class, Long.class);
|
||||||
|
List<Long> longs = mObjectMapper.readValue(value , type);
|
||||||
|
return longs;
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+2
-1
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.crypto.SecureUtil;
|
import cn.hutool.crypto.SecureUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent;
|
import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent;
|
||||||
import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver;
|
import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver;
|
||||||
import org.aspectj.lang.JoinPoint;
|
import org.aspectj.lang.JoinPoint;
|
||||||
@@ -18,7 +19,7 @@ public class DefaultIdempotentKeyResolver implements IdempotentKeyResolver {
|
|||||||
@Override
|
@Override
|
||||||
public String resolver(JoinPoint joinPoint, Idempotent idempotent) {
|
public String resolver(JoinPoint joinPoint, Idempotent idempotent) {
|
||||||
String methodName = joinPoint.getSignature().toString();
|
String methodName = joinPoint.getSignature().toString();
|
||||||
String argsStr = StrUtil.join(",", joinPoint.getArgs());
|
String argsStr = StrUtil.join(",", JSONUtil.toJsonStr(joinPoint.getArgs()));
|
||||||
return SecureUtil.md5(methodName + argsStr);
|
return SecureUtil.md5(methodName + argsStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+23
-23
@@ -21,28 +21,28 @@ public class YudaoCacheAutoConfiguration {
|
|||||||
*
|
*
|
||||||
* 参考 org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration 的 createConfiguration 方法
|
* 参考 org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration 的 createConfiguration 方法
|
||||||
*/
|
*/
|
||||||
@Bean
|
// @Bean
|
||||||
@Primary
|
// @Primary
|
||||||
public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
|
// public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
|
||||||
// 设置使用 JSON 序列化方式
|
// // 设置使用 JSON 序列化方式
|
||||||
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
|
// RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
|
||||||
config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
|
// config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
|
||||||
|
//
|
||||||
// 设置 CacheProperties.Redis 的属性
|
// // 设置 CacheProperties.Redis 的属性
|
||||||
CacheProperties.Redis redisProperties = cacheProperties.getRedis();
|
// CacheProperties.Redis redisProperties = cacheProperties.getRedis();
|
||||||
if (redisProperties.getTimeToLive() != null) {
|
// if (redisProperties.getTimeToLive() != null) {
|
||||||
config = config.entryTtl(redisProperties.getTimeToLive());
|
// config = config.entryTtl(redisProperties.getTimeToLive());
|
||||||
}
|
// }
|
||||||
if (redisProperties.getKeyPrefix() != null) {
|
// if (redisProperties.getKeyPrefix() != null) {
|
||||||
config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
|
// config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
|
||||||
}
|
// }
|
||||||
if (!redisProperties.isCacheNullValues()) {
|
// if (!redisProperties.isCacheNullValues()) {
|
||||||
config = config.disableCachingNullValues();
|
// config = config.disableCachingNullValues();
|
||||||
}
|
// }
|
||||||
if (!redisProperties.isUseKeyPrefix()) {
|
// if (!redisProperties.isUseKeyPrefix()) {
|
||||||
config = config.disableKeyPrefix();
|
// config = config.disableKeyPrefix();
|
||||||
}
|
// }
|
||||||
return config;
|
// return config;
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-14
@@ -15,19 +15,19 @@ public class YudaoRedisAutoConfiguration {
|
|||||||
/**
|
/**
|
||||||
* 创建 RedisTemplate Bean,使用 JSON 序列化方式
|
* 创建 RedisTemplate Bean,使用 JSON 序列化方式
|
||||||
*/
|
*/
|
||||||
@Bean
|
// @Bean
|
||||||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
|
// public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
|
||||||
// 创建 RedisTemplate 对象
|
// // 创建 RedisTemplate 对象
|
||||||
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
// RedisTemplate<String, Object> template = new RedisTemplate<>();
|
||||||
// 设置 RedisConnection 工厂。😈 它就是实现多种 Java Redis 客户端接入的秘密工厂。感兴趣的胖友,可以自己去撸下。
|
// // 设置 RedisConnection 工厂。😈 它就是实现多种 Java Redis 客户端接入的秘密工厂。感兴趣的胖友,可以自己去撸下。
|
||||||
template.setConnectionFactory(factory);
|
// template.setConnectionFactory(factory);
|
||||||
// 使用 String 序列化方式,序列化 KEY 。
|
// // 使用 String 序列化方式,序列化 KEY 。
|
||||||
template.setKeySerializer(RedisSerializer.string());
|
// template.setKeySerializer(RedisSerializer.string());
|
||||||
template.setHashKeySerializer(RedisSerializer.string());
|
// template.setHashKeySerializer(RedisSerializer.string());
|
||||||
// 使用 JSON 序列化方式(库是 Jackson ),序列化 VALUE 。
|
// // 使用 JSON 序列化方式(库是 Jackson ),序列化 VALUE 。
|
||||||
template.setValueSerializer(RedisSerializer.json());
|
// template.setValueSerializer(RedisSerializer.json());
|
||||||
template.setHashValueSerializer(RedisSerializer.json());
|
// template.setHashValueSerializer(RedisSerializer.json());
|
||||||
return template;
|
// return template;
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -41,6 +41,6 @@ public class SecurityProperties {
|
|||||||
* 一定要配置密钥,保证安全性
|
* 一定要配置密钥,保证安全性
|
||||||
*/
|
*/
|
||||||
@NotEmpty(message = "mock 模式的密钥不能为空") // 这里设置了一个默认值,因为实际上只有 mockEnable 为 true 时才需要配置。
|
@NotEmpty(message = "mock 模式的密钥不能为空") // 这里设置了一个默认值,因为实际上只有 mockEnable 为 true 时才需要配置。
|
||||||
private String mockSecret = "yudaoyuanma";
|
private String mockSecret = "zsw";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -22,6 +22,7 @@ import org.springframework.security.web.access.AccessDeniedHandler;
|
|||||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -86,8 +87,11 @@ public class YudaoSecurityAutoConfiguration {
|
|||||||
* Token 认证过滤器 Bean
|
* Token 认证过滤器 Bean
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public JWTAuthenticationTokenFilter authenticationTokenFilter(MultiUserDetailsAuthenticationProvider authenticationProvider,
|
public JWTAuthenticationTokenFilter authenticationTokenFilter(
|
||||||
|
HttpServletRequest request,
|
||||||
|
MultiUserDetailsAuthenticationProvider authenticationProvider,
|
||||||
GlobalExceptionHandler globalExceptionHandler) {
|
GlobalExceptionHandler globalExceptionHandler) {
|
||||||
|
|
||||||
return new JWTAuthenticationTokenFilter(securityProperties, authenticationProvider, globalExceptionHandler);
|
return new JWTAuthenticationTokenFilter(securityProperties, authenticationProvider, globalExceptionHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-2
@@ -130,15 +130,22 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
|
|||||||
// 设置 App API 无需认证
|
// 设置 App API 无需认证
|
||||||
.antMatchers(buildAppApi("/**")).permitAll()
|
.antMatchers(buildAppApi("/**")).permitAll()
|
||||||
.antMatchers("/common/**").permitAll()
|
.antMatchers("/common/**").permitAll()
|
||||||
|
|
||||||
|
|
||||||
|
// 忽略宝享购全部
|
||||||
|
.antMatchers("/bxgApp/**").permitAll()
|
||||||
|
.antMatchers(HttpMethod.OPTIONS).permitAll()
|
||||||
|
.and().httpBasic().and().csrf().disable()
|
||||||
// ②:每个项目的自定义规则
|
// ②:每个项目的自定义规则
|
||||||
.and().authorizeRequests(registry -> // 下面,循环设置自定义规则
|
.authorizeRequests(registry -> // 下面,循环设置自定义规则
|
||||||
authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry)))
|
authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry)))
|
||||||
// ③:兜底规则,必须认证
|
// ③:兜底规则,必须认证
|
||||||
.authorizeRequests()
|
.authorizeRequests()
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
;
|
;
|
||||||
|
|
||||||
// 添加 JWT Filter
|
// // 添加 JWT Filter
|
||||||
|
|
||||||
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
|
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
package cn.iocoder.yudao.framework.security.core.annotations;
|
||||||
|
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName 自定义权限注解
|
||||||
|
* @Author hupeng <610796224@qq.com>
|
||||||
|
* @Date 2020/4/30
|
||||||
|
**/
|
||||||
|
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface AuthCheck {
|
||||||
|
int value() default 4;
|
||||||
|
}
|
||||||
+6
-1
@@ -140,7 +140,12 @@ public class MultiUserDetailsAuthenticationProvider extends AbstractUserDetailsA
|
|||||||
|
|
||||||
private UserTypeEnum getUserType(HttpServletRequest request) {
|
private UserTypeEnum getUserType(HttpServletRequest request) {
|
||||||
// log.error("URI:{}",request.getRequestURI());
|
// log.error("URI:{}",request.getRequestURI());
|
||||||
if (request.getRequestURI().startsWith(properties.getAdminApi().getPrefix()) || request.getRequestURI().startsWith("/common/")) {
|
if (request.getRequestURI().startsWith(properties.getAdminApi().getPrefix())
|
||||||
|
|| request.getRequestURI().startsWith("/common/")
|
||||||
|
|| request.getRequestURI().startsWith("/bxg")
|
||||||
|
|| request.getRequestURI().startsWith("/erp")
|
||||||
|
|| request.getRequestURI().startsWith("/api/upload")
|
||||||
|
) {
|
||||||
return UserTypeEnum.ADMIN;
|
return UserTypeEnum.ADMIN;
|
||||||
}
|
}
|
||||||
if (request.getRequestURI().startsWith(properties.getAppApi().getPrefix())) {
|
if (request.getRequestURI().startsWith(properties.getAppApi().getPrefix())) {
|
||||||
|
|||||||
+1
@@ -36,6 +36,7 @@ public class JWTAuthenticationTokenFilter extends OncePerRequestFilter {
|
|||||||
@SuppressWarnings("NullableProblems")
|
@SuppressWarnings("NullableProblems")
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
|
||||||
String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader());
|
String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader());
|
||||||
if (StrUtil.isNotEmpty(token)) {
|
if (StrUtil.isNotEmpty(token)) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -59,6 +59,12 @@
|
|||||||
<artifactId>resilience4j-ratelimiter</artifactId>
|
<artifactId>resilience4j-ratelimiter</artifactId>
|
||||||
<scope>provided</scope> <!-- 设置为 provided,主要是 GlobalExceptionHandler 使用 -->
|
<scope>provided</scope> <!-- 设置为 provided,主要是 GlobalExceptionHandler 使用 -->
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.apache.dubbo</groupId>-->
|
||||||
|
<!-- <artifactId>dubbo</artifactId>-->
|
||||||
|
<!-- <version>3.0.9</version>-->
|
||||||
|
<!-- <scope>compile</scope>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeDeserialize
|
|||||||
import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeSerializer;
|
import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeSerializer;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
@@ -38,7 +39,8 @@ public class YudaoJacksonAutoConfiguration {
|
|||||||
.addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);
|
.addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);
|
||||||
|
|
||||||
objectMapper.registerModules(simpleModule);
|
objectMapper.registerModules(simpleModule);
|
||||||
|
// 序列化枚举
|
||||||
|
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING,true);
|
||||||
JsonUtils.init(objectMapper);
|
JsonUtils.init(objectMapper);
|
||||||
log.info("初始化 jackson 自动配置");
|
log.info("初始化 jackson 自动配置");
|
||||||
return bean;
|
return bean;
|
||||||
|
|||||||
+91
-4
@@ -8,16 +8,15 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
|||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import springfox.documentation.builders.ApiInfoBuilder;
|
import springfox.documentation.builders.*;
|
||||||
import springfox.documentation.builders.ExampleBuilder;
|
import springfox.documentation.schema.ModelRef;
|
||||||
import springfox.documentation.builders.PathSelectors;
|
|
||||||
import springfox.documentation.builders.RequestParameterBuilder;
|
|
||||||
import springfox.documentation.service.*;
|
import springfox.documentation.service.*;
|
||||||
import springfox.documentation.spi.DocumentationType;
|
import springfox.documentation.spi.DocumentationType;
|
||||||
import springfox.documentation.spi.service.contexts.SecurityContext;
|
import springfox.documentation.spi.service.contexts.SecurityContext;
|
||||||
import springfox.documentation.spring.web.plugins.Docket;
|
import springfox.documentation.spring.web.plugins.Docket;
|
||||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -50,6 +49,7 @@ public class YudaoSwaggerAutoConfiguration {
|
|||||||
return new Docket(DocumentationType.SWAGGER_2)
|
return new Docket(DocumentationType.SWAGGER_2)
|
||||||
// 用来创建该 API 的基本信息,展示在文档的页面中(自定义展示的信息)
|
// 用来创建该 API 的基本信息,展示在文档的页面中(自定义展示的信息)
|
||||||
.apiInfo(apiInfo(properties))
|
.apiInfo(apiInfo(properties))
|
||||||
|
.groupName("管理系统")
|
||||||
// 设置扫描指定 package 包下的
|
// 设置扫描指定 package 包下的
|
||||||
.select()
|
.select()
|
||||||
.apis(basePackage(properties.getBasePackage()))
|
.apis(basePackage(properties.getBasePackage()))
|
||||||
@@ -61,6 +61,93 @@ public class YudaoSwaggerAutoConfiguration {
|
|||||||
.securityContexts(securityContexts());
|
.securityContexts(securityContexts());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean("SWAGGER_ADMIN")
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public Docket createRestApi1() {
|
||||||
|
SwaggerProperties properties = swaggerProperties();
|
||||||
|
ParameterBuilder ticketPar = new ParameterBuilder();
|
||||||
|
List<Parameter> pars = new ArrayList<>();
|
||||||
|
ticketPar.name("token").description("token")
|
||||||
|
.modelRef(new ModelRef("string"))
|
||||||
|
.parameterType("header")
|
||||||
|
.defaultValue("token " + " ")
|
||||||
|
.required(true)
|
||||||
|
.build();
|
||||||
|
pars.add(ticketPar.build());
|
||||||
|
return new Docket(DocumentationType.SWAGGER_2)
|
||||||
|
.groupName("商城后台")
|
||||||
|
.enable(true)
|
||||||
|
.apiInfo(apiInfo(properties))
|
||||||
|
.select()
|
||||||
|
.apis(RequestHandlerSelectors.basePackage("co.yixiang.modules"))
|
||||||
|
.paths(PathSelectors.regex("/error.*").negate())
|
||||||
|
.build()
|
||||||
|
.globalOperationParameters(pars)
|
||||||
|
//添加登陆认证
|
||||||
|
.securitySchemes(securitySchemes())
|
||||||
|
.globalRequestParameters(globalRequestParameters())
|
||||||
|
.securityContexts(securityContexts());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean("SWAGGER_APP")
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public Docket createAppApi() {
|
||||||
|
SwaggerProperties properties = swaggerProperties();
|
||||||
|
ParameterBuilder ticketPar = new ParameterBuilder();
|
||||||
|
List<Parameter> pars = new ArrayList<>();
|
||||||
|
ticketPar.name("token").description("token")
|
||||||
|
.modelRef(new ModelRef("string"))
|
||||||
|
.parameterType("header")
|
||||||
|
.defaultValue("token" + " ")
|
||||||
|
.required(true)
|
||||||
|
.build();
|
||||||
|
pars.add(ticketPar.build());
|
||||||
|
return new Docket(DocumentationType.SWAGGER_2)
|
||||||
|
.groupName("商城前台")
|
||||||
|
.enable(true)
|
||||||
|
.apiInfo(apiInfo(properties))
|
||||||
|
.select()
|
||||||
|
.apis(RequestHandlerSelectors.basePackage("co.yixiang.app.modules"))
|
||||||
|
.paths(PathSelectors.regex("/error.*").negate())
|
||||||
|
.build()
|
||||||
|
.globalOperationParameters(pars)
|
||||||
|
//添加登陆认证
|
||||||
|
.securitySchemes(securitySchemes())
|
||||||
|
.globalRequestParameters(globalRequestParameters())
|
||||||
|
.securityContexts(securityContexts());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean("SWAGGER_TOOL")
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public Docket createToolApi() {
|
||||||
|
SwaggerProperties properties = swaggerProperties();
|
||||||
|
ParameterBuilder ticketPar = new ParameterBuilder();
|
||||||
|
List<Parameter> pars = new ArrayList<>();
|
||||||
|
ticketPar.name("token").description("token")
|
||||||
|
.modelRef(new ModelRef("string"))
|
||||||
|
.parameterType("header")
|
||||||
|
.defaultValue("token" + " ")
|
||||||
|
.required(true)
|
||||||
|
.build();
|
||||||
|
pars.add(ticketPar.build());
|
||||||
|
return new Docket(DocumentationType.SWAGGER_2)
|
||||||
|
.groupName("电商工具")
|
||||||
|
.enable(true)
|
||||||
|
.apiInfo(apiInfo(properties))
|
||||||
|
.select()
|
||||||
|
.apis(RequestHandlerSelectors.basePackage("co.yixiang.tools"))
|
||||||
|
.paths(PathSelectors.regex("/error.*").negate())
|
||||||
|
.build()
|
||||||
|
.globalOperationParameters(pars)
|
||||||
|
//添加登陆认证
|
||||||
|
.securitySchemes(securitySchemes())
|
||||||
|
.globalRequestParameters(globalRequestParameters())
|
||||||
|
.securityContexts(securityContexts());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ========== apiInfo ==========
|
// ========== apiInfo ==========
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+19
-4
@@ -3,18 +3,21 @@ package cn.iocoder.yudao.framework.web.core.handler;
|
|||||||
import cn.hutool.core.exceptions.ExceptionUtil;
|
import cn.hutool.core.exceptions.ExceptionUtil;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.extra.servlet.ServletUtil;
|
import cn.hutool.extra.servlet.ServletUtil;
|
||||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService;
|
import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService;
|
||||||
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiErrorLogCreateReqDTO;
|
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiErrorLogCreateReqDTO;
|
||||||
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||||
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
import cn.iocoder.yudao.framework.common.exception.ShopException;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.ApiResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
||||||
|
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||||
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
|
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
//import org.apache.dubbo.rpc.RpcException;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.validation.BindException;
|
import org.springframework.validation.BindException;
|
||||||
@@ -92,6 +95,11 @@ public class GlobalExceptionHandler {
|
|||||||
if (ex instanceof AccessDeniedException) {
|
if (ex instanceof AccessDeniedException) {
|
||||||
return accessDeniedExceptionHandler(request, (AccessDeniedException) ex);
|
return accessDeniedExceptionHandler(request, (AccessDeniedException) ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (ex instanceof RpcException){
|
||||||
|
// log.error("dubbo错误", ex);
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
return defaultExceptionHandler(request, ex);
|
return defaultExceptionHandler(request, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,6 +223,13 @@ public class GlobalExceptionHandler {
|
|||||||
return CommonResult.error(ex.getCode(), ex.getMessage());
|
return CommonResult.error(ex.getCode(), ex.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(value = ShopException.class)
|
||||||
|
public ApiResult<?> yshopException(ShopException ex){
|
||||||
|
log.info("[YshopException]",ex);
|
||||||
|
return ApiResult.fail(ex.getErrorCode(),ex.getMessage());
|
||||||
|
//return CommonResult.error(ex.getErrorCode(), ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理系统异常,兜底处理所有的一切
|
* 处理系统异常,兜底处理所有的一切
|
||||||
*/
|
*/
|
||||||
|
|||||||
+3
-10
@@ -9,8 +9,6 @@ import cn.smallbun.screw.core.engine.EngineFileType;
|
|||||||
import cn.smallbun.screw.core.engine.EngineTemplateType;
|
import cn.smallbun.screw.core.engine.EngineTemplateType;
|
||||||
import cn.smallbun.screw.core.execute.DocumentationExecute;
|
import cn.smallbun.screw.core.execute.DocumentationExecute;
|
||||||
import cn.smallbun.screw.core.process.ProcessConfig;
|
import cn.smallbun.screw.core.process.ProcessConfig;
|
||||||
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
|
|
||||||
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
|
|
||||||
import com.zaxxer.hikari.HikariConfig;
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
import com.zaxxer.hikari.HikariDataSource;
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
@@ -32,9 +30,6 @@ import java.util.Arrays;
|
|||||||
@RequestMapping("/infra/db-doc")
|
@RequestMapping("/infra/db-doc")
|
||||||
public class DbDocController {
|
public class DbDocController {
|
||||||
|
|
||||||
@Resource
|
|
||||||
private DynamicDataSourceProperties dynamicDataSourceProperties;
|
|
||||||
|
|
||||||
private static final String FILE_OUTPUT_DIR = System.getProperty("java.io.tmpdir") + File.separator
|
private static final String FILE_OUTPUT_DIR = System.getProperty("java.io.tmpdir") + File.separator
|
||||||
+ "db-doc";
|
+ "db-doc";
|
||||||
private static final String DOC_FILE_NAME = "数据库文档";
|
private static final String DOC_FILE_NAME = "数据库文档";
|
||||||
@@ -119,13 +114,11 @@ public class DbDocController {
|
|||||||
// TODO 芋艿:screw 暂时不支持 druid,尴尬
|
// TODO 芋艿:screw 暂时不支持 druid,尴尬
|
||||||
private HikariDataSource buildDataSource() {
|
private HikariDataSource buildDataSource() {
|
||||||
// 获得 DataSource 数据源,目前只支持首个
|
// 获得 DataSource 数据源,目前只支持首个
|
||||||
String primary = dynamicDataSourceProperties.getPrimary();
|
|
||||||
DataSourceProperty dataSourceProperty = dynamicDataSourceProperties.getDatasource().get(primary);
|
|
||||||
// 创建 HikariConfig 配置类
|
// 创建 HikariConfig 配置类
|
||||||
HikariConfig hikariConfig = new HikariConfig();
|
HikariConfig hikariConfig = new HikariConfig();
|
||||||
hikariConfig.setJdbcUrl(dataSourceProperty.getUrl());
|
hikariConfig.setJdbcUrl("");
|
||||||
hikariConfig.setUsername(dataSourceProperty.getUsername());
|
hikariConfig.setUsername("");
|
||||||
hikariConfig.setPassword(dataSourceProperty.getPassword());
|
hikariConfig.setPassword("");
|
||||||
hikariConfig.addDataSourceProperty("useInformationSchema", "true"); // 设置可以获取 tables remarks 信息
|
hikariConfig.addDataSourceProperty("useInformationSchema", "true"); // 设置可以获取 tables remarks 信息
|
||||||
// 创建数据源
|
// 创建数据源
|
||||||
return new HikariDataSource(hikariConfig);
|
return new HikariDataSource(hikariConfig);
|
||||||
|
|||||||
+36
@@ -1,27 +1,61 @@
|
|||||||
package cn.iocoder.yudao.module.infra.framework.security.config;
|
package cn.iocoder.yudao.module.infra.framework.security.config;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
|
import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
|
||||||
|
import cn.iocoder.yudao.framework.security.core.annotations.AuthCheck;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
||||||
|
import org.springframework.web.method.HandlerMethod;
|
||||||
|
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
|
||||||
|
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Infra 模块的 Security 配置
|
* Infra 模块的 Security 配置
|
||||||
*/
|
*/
|
||||||
@Configuration("infraSecurityConfiguration")
|
@Configuration("infraSecurityConfiguration")
|
||||||
|
@Slf4j
|
||||||
public class SecurityConfiguration {
|
public class SecurityConfiguration {
|
||||||
|
|
||||||
@Value("${spring.boot.admin.context-path:''}")
|
@Value("${spring.boot.admin.context-path:''}")
|
||||||
private String adminSeverContextPath;
|
private String adminSeverContextPath;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
@Bean("infraAuthorizeRequestsCustomizer")
|
@Bean("infraAuthorizeRequestsCustomizer")
|
||||||
public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
|
public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
|
||||||
return new AuthorizeRequestsCustomizer() {
|
return new AuthorizeRequestsCustomizer() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
|
public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
|
||||||
|
|
||||||
|
// 查找全部宝象购的链接
|
||||||
|
Map<RequestMappingInfo, HandlerMethod> handlerMethods = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();
|
||||||
|
Set<String> anonymousUrls = new HashSet<>();
|
||||||
|
|
||||||
|
for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethods.entrySet()) {
|
||||||
|
HandlerMethod handlerMethod = infoEntry.getValue();
|
||||||
|
// 宝象购app包下 并且没有登录标识 放行
|
||||||
|
if (handlerMethod.getBeanType().getPackage().getName().startsWith("co.yixiang.app")
|
||||||
|
&& !handlerMethod.hasMethodAnnotation(AuthCheck.class)){
|
||||||
|
PatternsRequestCondition requestCondition = infoEntry.getKey().getPatternsCondition();
|
||||||
|
Optional.ofNullable(requestCondition).orElseThrow(RuntimeException::new);
|
||||||
|
anonymousUrls.addAll(requestCondition.getPatterns());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// anonymousUrls.forEach(s -> log.info("宝象购可以匿名访问的url:{}", s));
|
||||||
|
registry.antMatchers(anonymousUrls.toArray(new String[0])).anonymous();
|
||||||
// Swagger 接口文档
|
// Swagger 接口文档
|
||||||
registry.antMatchers("/swagger-ui.html").anonymous()
|
registry.antMatchers("/swagger-ui.html").anonymous()
|
||||||
.antMatchers("/swagger-resources/**").anonymous()
|
.antMatchers("/swagger-resources/**").anonymous()
|
||||||
@@ -32,6 +66,8 @@ public class SecurityConfiguration {
|
|||||||
.antMatchers("/actuator/**").anonymous();
|
.antMatchers("/actuator/**").anonymous();
|
||||||
// Druid 监控
|
// Druid 监控
|
||||||
registry.antMatchers("/druid/**").anonymous();
|
registry.antMatchers("/druid/**").anonymous();
|
||||||
|
// 首页
|
||||||
|
registry.antMatchers("/").anonymous();
|
||||||
// Spring Boot Admin Server 的安全配置
|
// Spring Boot Admin Server 的安全配置
|
||||||
registry.antMatchers(adminSeverContextPath).anonymous()
|
registry.antMatchers(adminSeverContextPath).anonymous()
|
||||||
.antMatchers(adminSeverContextPath + "/**").anonymous();
|
.antMatchers(adminSeverContextPath + "/**").anonymous();
|
||||||
|
|||||||
+3
-3
@@ -9,8 +9,8 @@
|
|||||||
文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
|
文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<select id="selectList2" resultType="TestDemoDO">
|
<!-- <select id="selectList2" resultType="TestDemoDO">-->
|
||||||
SELECT * FROM infra_test_demo
|
<!-- SELECT * FROM infra_test_demo-->
|
||||||
</select>
|
<!-- </select>-->
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ import lombok.NoArgsConstructor;
|
|||||||
@Builder
|
@Builder
|
||||||
public class AppAuthLoginRespVO {
|
public class AppAuthLoginRespVO {
|
||||||
|
|
||||||
@ApiModelProperty(value = "token", required = true, example = "yudaoyuanma")
|
@ApiModelProperty(value = "token", required = true, example = "zsw")
|
||||||
private String token;
|
private String token;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package cn.iocoder.yudao.module.member.controller.app.weixin;
|
||||||
|
|
||||||
|
import me.chanjar.weixin.mp.api.WxMpService;
|
||||||
|
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class TestConfigure {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WxMpService wxMpService(){
|
||||||
|
WxMpService wxMpService = new WxMpServiceImpl();
|
||||||
|
return wxMpService;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+5
-5
@@ -68,7 +68,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
|
|||||||
@Resource
|
@Resource
|
||||||
private PasswordEncoder passwordEncoder;
|
private PasswordEncoder passwordEncoder;
|
||||||
@Resource
|
@Resource
|
||||||
private MemberUserMapper userMapper;
|
private MemberUserMapper memberUserMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserDetails loadUserByUsername(String mobile) throws UsernameNotFoundException {
|
public UserDetails loadUserByUsername(String mobile) throws UsernameNotFoundException {
|
||||||
@@ -286,7 +286,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
|
|||||||
MemberUserDO userDO = checkOldPassword(userId, reqVO.getOldPassword());
|
MemberUserDO userDO = checkOldPassword(userId, reqVO.getOldPassword());
|
||||||
|
|
||||||
// 更新用户密码
|
// 更新用户密码
|
||||||
userMapper.updateById(MemberUserDO.builder().id(userDO.getId())
|
memberUserMapper.updateById(MemberUserDO.builder().id(userDO.getId())
|
||||||
.password(passwordEncoder.encode(reqVO.getPassword())).build());
|
.password(passwordEncoder.encode(reqVO.getPassword())).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,7 +300,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
|
|||||||
getClientIP()));
|
getClientIP()));
|
||||||
|
|
||||||
// 更新密码
|
// 更新密码
|
||||||
userMapper.updateById(MemberUserDO.builder().id(userDO.getId())
|
memberUserMapper.updateById(MemberUserDO.builder().id(userDO.getId())
|
||||||
.password(passwordEncoder.encode(reqVO.getPassword())).build());
|
.password(passwordEncoder.encode(reqVO.getPassword())).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,7 +319,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
|
|||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public MemberUserDO checkOldPassword(Long id, String oldPassword) {
|
public MemberUserDO checkOldPassword(Long id, String oldPassword) {
|
||||||
MemberUserDO user = userMapper.selectById(id);
|
MemberUserDO user = memberUserMapper.selectById(id);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw exception(USER_NOT_EXISTS);
|
throw exception(USER_NOT_EXISTS);
|
||||||
}
|
}
|
||||||
@@ -331,7 +331,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MemberUserDO checkUserIfExists(String mobile) {
|
public MemberUserDO checkUserIfExists(String mobile) {
|
||||||
MemberUserDO user = userMapper.selectByMobile(mobile);
|
MemberUserDO user = memberUserMapper.selectByMobile(mobile);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw exception(USER_NOT_EXISTS);
|
throw exception(USER_NOT_EXISTS);
|
||||||
}
|
}
|
||||||
|
|||||||
+137
-137
@@ -1,137 +1,137 @@
|
|||||||
package cn.iocoder.yudao.module.member.service.user;
|
//package cn.iocoder.yudao.module.member.service.user;
|
||||||
|
//
|
||||||
import cn.hutool.core.util.RandomUtil;
|
//import cn.hutool.core.util.RandomUtil;
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
//import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
//import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
||||||
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
|
//import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest;
|
//import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest;
|
||||||
import cn.iocoder.yudao.module.infra.api.file.FileApi;
|
//import cn.iocoder.yudao.module.infra.api.file.FileApi;
|
||||||
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO;
|
//import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO;
|
||||||
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
|
//import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
|
||||||
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
|
//import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
|
||||||
import cn.iocoder.yudao.module.member.service.auth.MemberAuthServiceImpl;
|
//import cn.iocoder.yudao.module.member.service.auth.MemberAuthServiceImpl;
|
||||||
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
|
//import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
|
||||||
import org.junit.jupiter.api.Test;
|
//import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
//import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.context.annotation.Import;
|
//import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
//import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
//import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
//
|
||||||
import javax.annotation.Resource;
|
//import javax.annotation.Resource;
|
||||||
import java.io.ByteArrayInputStream;
|
//import java.io.ByteArrayInputStream;
|
||||||
import java.util.function.Consumer;
|
//import java.util.function.Consumer;
|
||||||
|
//
|
||||||
import static cn.hutool.core.util.RandomUtil.*;
|
//import static cn.hutool.core.util.RandomUtil.*;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
//import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
|
//import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
//import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.mockito.Mockito.eq;
|
//import static org.mockito.Mockito.eq;
|
||||||
import static org.mockito.Mockito.when;
|
//import static org.mockito.Mockito.when;
|
||||||
|
//
|
||||||
// TODO @芋艿:单测的 review,等逻辑都达成一致后
|
//// TODO @芋艿:单测的 review,等逻辑都达成一致后
|
||||||
/**
|
///**
|
||||||
* {@link MemberUserServiceImpl} 的单元测试类
|
// * {@link MemberUserServiceImpl} 的单元测试类
|
||||||
*
|
// *
|
||||||
* @author 宋天
|
// * @author 宋天
|
||||||
*/
|
// */
|
||||||
@Import({MemberUserServiceImpl.class, YudaoRedisAutoConfiguration.class})
|
//@Import({MemberUserServiceImpl.class, YudaoRedisAutoConfiguration.class})
|
||||||
public class MemberUserServiceImplTest extends BaseDbAndRedisUnitTest {
|
//public class MemberUserServiceImplTest extends BaseDbAndRedisUnitTest {
|
||||||
|
//
|
||||||
@Resource
|
// @Resource
|
||||||
private MemberUserServiceImpl memberUserService;
|
// private MemberUserServiceImpl memberUserService;
|
||||||
|
//
|
||||||
@Resource
|
// @Resource
|
||||||
private StringRedisTemplate stringRedisTemplate;
|
// private StringRedisTemplate stringRedisTemplate;
|
||||||
|
//
|
||||||
@Resource
|
// @Resource
|
||||||
private MemberUserMapper userMapper;
|
// private MemberUserMapper userMapper;
|
||||||
|
//
|
||||||
@MockBean
|
// @MockBean
|
||||||
private MemberAuthServiceImpl authService;
|
// private MemberAuthServiceImpl authService;
|
||||||
|
//
|
||||||
@MockBean
|
// @MockBean
|
||||||
private PasswordEncoder passwordEncoder;
|
// private PasswordEncoder passwordEncoder;
|
||||||
|
//
|
||||||
@MockBean
|
// @MockBean
|
||||||
private SmsCodeApi smsCodeApi;
|
// private SmsCodeApi smsCodeApi;
|
||||||
@MockBean
|
// @MockBean
|
||||||
private FileApi fileApi;
|
// private FileApi fileApi;
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
public void testUpdateNickName_success(){
|
// public void testUpdateNickName_success(){
|
||||||
// mock 数据
|
// // mock 数据
|
||||||
MemberUserDO userDO = randomUserDO();
|
// MemberUserDO userDO = randomUserDO();
|
||||||
userMapper.insert(userDO);
|
// userMapper.insert(userDO);
|
||||||
|
//
|
||||||
// 随机昵称
|
// // 随机昵称
|
||||||
String newNickName = randomString();
|
// String newNickName = randomString();
|
||||||
|
//
|
||||||
// 调用接口修改昵称
|
// // 调用接口修改昵称
|
||||||
memberUserService.updateUserNickname(userDO.getId(),newNickName);
|
// memberUserService.updateUserNickname(userDO.getId(),newNickName);
|
||||||
// 查询新修改后的昵称
|
// // 查询新修改后的昵称
|
||||||
String nickname = memberUserService.getUser(userDO.getId()).getNickname();
|
// String nickname = memberUserService.getUser(userDO.getId()).getNickname();
|
||||||
// 断言
|
// // 断言
|
||||||
assertEquals(newNickName,nickname);
|
// assertEquals(newNickName,nickname);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
public void testUpdateAvatar_success() throws Exception {
|
// public void testUpdateAvatar_success() throws Exception {
|
||||||
// mock 数据
|
// // mock 数据
|
||||||
MemberUserDO dbUser = randomUserDO();
|
// MemberUserDO dbUser = randomUserDO();
|
||||||
userMapper.insert(dbUser);
|
// userMapper.insert(dbUser);
|
||||||
|
//
|
||||||
// 准备参数
|
// // 准备参数
|
||||||
Long userId = dbUser.getId();
|
// Long userId = dbUser.getId();
|
||||||
byte[] avatarFileBytes = randomBytes(10);
|
// byte[] avatarFileBytes = randomBytes(10);
|
||||||
ByteArrayInputStream avatarFile = new ByteArrayInputStream(avatarFileBytes);
|
// ByteArrayInputStream avatarFile = new ByteArrayInputStream(avatarFileBytes);
|
||||||
// mock 方法
|
// // mock 方法
|
||||||
String avatar = randomString();
|
// String avatar = randomString();
|
||||||
when(fileApi.createFile(eq(avatarFileBytes))).thenReturn(avatar);
|
// when(fileApi.createFile(eq(avatarFileBytes))).thenReturn(avatar);
|
||||||
// 调用
|
// // 调用
|
||||||
String str = memberUserService.updateUserAvatar(userId, avatarFile);
|
// String str = memberUserService.updateUserAvatar(userId, avatarFile);
|
||||||
// 断言
|
// // 断言
|
||||||
assertEquals(avatar, str);
|
// assertEquals(avatar, str);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
public void updateMobile_success(){
|
// public void updateMobile_success(){
|
||||||
// mock数据
|
// // mock数据
|
||||||
String oldMobile = randomNumbers(11);
|
// String oldMobile = randomNumbers(11);
|
||||||
MemberUserDO userDO = randomUserDO();
|
// MemberUserDO userDO = randomUserDO();
|
||||||
userDO.setMobile(oldMobile);
|
// userDO.setMobile(oldMobile);
|
||||||
userMapper.insert(userDO);
|
// userMapper.insert(userDO);
|
||||||
|
//
|
||||||
// TODO 芋艿:需要修复该单元测试,重构多模块带来的
|
// // TODO 芋艿:需要修复该单元测试,重构多模块带来的
|
||||||
// 旧手机和旧验证码
|
// // 旧手机和旧验证码
|
||||||
// SmsCodeDO codeDO = new SmsCodeDO();
|
//// SmsCodeDO codeDO = new SmsCodeDO();
|
||||||
String oldCode = RandomUtil.randomString(4);
|
// String oldCode = RandomUtil.randomString(4);
|
||||||
// codeDO.setMobile(userDO.getMobile());
|
//// codeDO.setMobile(userDO.getMobile());
|
||||||
// codeDO.setCode(oldCode);
|
//// codeDO.setCode(oldCode);
|
||||||
// codeDO.setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene());
|
//// codeDO.setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene());
|
||||||
// codeDO.setUsed(Boolean.FALSE);
|
//// codeDO.setUsed(Boolean.FALSE);
|
||||||
// when(smsCodeService.checkCodeIsExpired(codeDO.getMobile(),codeDO.getCode(),codeDO.getScene())).thenReturn(codeDO);
|
//// when(smsCodeService.checkCodeIsExpired(codeDO.getMobile(),codeDO.getCode(),codeDO.getScene())).thenReturn(codeDO);
|
||||||
|
//
|
||||||
// 更新手机号
|
// // 更新手机号
|
||||||
String newMobile = randomNumbers(11);
|
// String newMobile = randomNumbers(11);
|
||||||
String newCode = randomNumbers(4);
|
// String newCode = randomNumbers(4);
|
||||||
AppUserUpdateMobileReqVO reqVO = new AppUserUpdateMobileReqVO();
|
// AppUserUpdateMobileReqVO reqVO = new AppUserUpdateMobileReqVO();
|
||||||
reqVO.setMobile(newMobile);
|
// reqVO.setMobile(newMobile);
|
||||||
reqVO.setCode(newCode);
|
// reqVO.setCode(newCode);
|
||||||
reqVO.setOldMobile(oldMobile);
|
// reqVO.setOldMobile(oldMobile);
|
||||||
reqVO.setOldCode(oldCode);
|
// reqVO.setOldCode(oldCode);
|
||||||
memberUserService.updateUserMobile(userDO.getId(),reqVO);
|
// memberUserService.updateUserMobile(userDO.getId(),reqVO);
|
||||||
|
//
|
||||||
assertEquals(memberUserService.getUser(userDO.getId()).getMobile(),newMobile);
|
// assertEquals(memberUserService.getUser(userDO.getId()).getMobile(),newMobile);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// ========== 随机对象 ==========
|
// // ========== 随机对象 ==========
|
||||||
|
//
|
||||||
@SafeVarargs
|
// @SafeVarargs
|
||||||
private static MemberUserDO randomUserDO(Consumer<MemberUserDO>... consumers) {
|
// private static MemberUserDO randomUserDO(Consumer<MemberUserDO>... consumers) {
|
||||||
Consumer<MemberUserDO> consumer = (o) -> {
|
// Consumer<MemberUserDO> consumer = (o) -> {
|
||||||
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
// o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
||||||
};
|
// };
|
||||||
return randomPojo(MemberUserDO.class, ArrayUtils.append(consumer, consumers));
|
// return randomPojo(MemberUserDO.class, ArrayUtils.append(consumer, consumers));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
}
|
//}
|
||||||
|
|||||||
+2
@@ -123,4 +123,6 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode SENSITIVE_WORD_NOT_EXISTS = new ErrorCode(1002019000, "系统敏感词在所有标签中都不存在");
|
ErrorCode SENSITIVE_WORD_NOT_EXISTS = new ErrorCode(1002019000, "系统敏感词在所有标签中都不存在");
|
||||||
ErrorCode SENSITIVE_WORD_EXISTS = new ErrorCode(1002019001, "系统敏感词已在标签中存在");
|
ErrorCode SENSITIVE_WORD_EXISTS = new ErrorCode(1002019001, "系统敏感词已在标签中存在");
|
||||||
|
|
||||||
|
ErrorCode CP_USER_NOT_EXISTS = new ErrorCode(1002021001,"微信企业成员不存在");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.enums.wxcp;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum WxCpMsgTypeEnum {
|
||||||
|
|
||||||
|
project,
|
||||||
|
|
||||||
|
task;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -97,6 +97,11 @@
|
|||||||
<artifactId>yudao-spring-boot-starter-excel</artifactId>
|
<artifactId>yudao-spring-boot-starter-excel</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-biz-weixin</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.controller.admin.CpUser;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import io.swagger.annotations.*;
|
||||||
|
|
||||||
|
import javax.validation.constraints.*;
|
||||||
|
import javax.validation.*;
|
||||||
|
import javax.servlet.http.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||||
|
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.CpUser.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.dataobject.CpUser.CpUserDO;
|
||||||
|
import cn.iocoder.yudao.module.system.convert.CpUser.CpUserConvert;
|
||||||
|
import cn.iocoder.yudao.module.system.service.CpUser.CpUserService;
|
||||||
|
|
||||||
|
@Api(tags = "管理后台 - 企业微信成员")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/system/cp-user")
|
||||||
|
@Validated
|
||||||
|
public class CpUserController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CpUserService cpUserService;
|
||||||
|
|
||||||
|
@PostMapping("/create")
|
||||||
|
@ApiOperation("创建企业微信成员")
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:cp-user:create')")
|
||||||
|
public CommonResult<Long> createCpUser(@Valid @RequestBody CpUserCreateReqVO createReqVO) {
|
||||||
|
return success(cpUserService.createCpUser(createReqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/update")
|
||||||
|
@ApiOperation("更新企业微信成员")
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:cp-user:update')")
|
||||||
|
public CommonResult<Boolean> updateCpUser(@Valid @RequestBody CpUserUpdateReqVO updateReqVO) {
|
||||||
|
cpUserService.updateCpUser(updateReqVO);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/delete")
|
||||||
|
@ApiOperation("删除企业微信成员")
|
||||||
|
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:cp-user:delete')")
|
||||||
|
public CommonResult<Boolean> deleteCpUser(@RequestParam("id") Long id) {
|
||||||
|
cpUserService.deleteCpUser(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get")
|
||||||
|
@ApiOperation("获得企业微信成员")
|
||||||
|
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:cp-user:query')")
|
||||||
|
public CommonResult<CpUserRespVO> getCpUser(@RequestParam("id") Long id) {
|
||||||
|
CpUserDO cpUser = cpUserService.getCpUser(id);
|
||||||
|
return success(CpUserConvert.INSTANCE.convert(cpUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/list")
|
||||||
|
@ApiOperation("获得企业微信成员列表")
|
||||||
|
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:cp-user:query')")
|
||||||
|
public CommonResult<List<CpUserRespVO>> getCpUserList(@RequestParam("ids") Collection<Long> ids) {
|
||||||
|
List<CpUserDO> list = cpUserService.getCpUserList(ids);
|
||||||
|
return success(CpUserConvert.INSTANCE.convertList(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/page")
|
||||||
|
@ApiOperation("获得企业微信成员分页")
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:cp-user:query')")
|
||||||
|
public CommonResult<PageResult<CpUserRespVO>> getCpUserPage(@Valid CpUserPageReqVO pageVO) {
|
||||||
|
PageResult<CpUserDO> pageResult = cpUserService.getCpUserPage(pageVO);
|
||||||
|
return success(CpUserConvert.INSTANCE.convertPage(pageResult));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/export-excel")
|
||||||
|
@ApiOperation("导出企业微信成员 Excel")
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:cp-user:export')")
|
||||||
|
@OperateLog(type = EXPORT)
|
||||||
|
public void exportCpUserExcel(@Valid CpUserExportReqVO exportReqVO,
|
||||||
|
HttpServletResponse response) throws IOException {
|
||||||
|
List<CpUserDO> list = cpUserService.getCpUserList(exportReqVO);
|
||||||
|
// 导出 Excel
|
||||||
|
List<CpUserExcelVO> datas = CpUserConvert.INSTANCE.convertList02(list);
|
||||||
|
ExcelUtils.write(response, "企业微信成员.xls", "数据", CpUserExcelVO.class, datas);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.controller.admin.CpUser.dto;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.system.enums.wxcp.WxCpMsgTypeEnum;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("企业微信发送推送消息")
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class CpMessageDto {
|
||||||
|
|
||||||
|
private WxCpMsgTypeEnum typeEnum;
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
// 标题
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
// 子标题
|
||||||
|
private String description;
|
||||||
|
private Map<String,String> contentItems;
|
||||||
|
|
||||||
|
// 是否放大第一对item
|
||||||
|
private Boolean emphasisFirstItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于微信消息推送的 - 模板ID 不一定适用于企业微信
|
||||||
|
*/
|
||||||
|
private String templateId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收人userid
|
||||||
|
*/
|
||||||
|
private List<String> reciveIds;
|
||||||
|
|
||||||
|
}
|
||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.controller.admin.CpUser.vo;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import io.swagger.annotations.*;
|
||||||
|
import javax.validation.constraints.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业微信成员 Base VO,提供给添加、修改、详细的子 VO 使用
|
||||||
|
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CpUserBaseVO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "用户昵称", required = true)
|
||||||
|
@NotNull(message = "用户昵称不能为空")
|
||||||
|
private String userid;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "头像", required = true)
|
||||||
|
@NotNull(message = "头像不能为空")
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "状态", required = true)
|
||||||
|
@NotNull(message = "状态不能为空")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "手机号", required = true)
|
||||||
|
@NotNull(message = "手机号不能为空")
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "姓名")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "部门")
|
||||||
|
private Object department;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "职位")
|
||||||
|
private String position;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "邮件")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "企业邮件")
|
||||||
|
private String bizMail;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "工时")
|
||||||
|
private Integer workHour;
|
||||||
|
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.controller.admin.CpUser.vo;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import io.swagger.annotations.*;
|
||||||
|
import javax.validation.constraints.*;
|
||||||
|
|
||||||
|
@ApiModel("管理后台 - 企业微信成员创建 Request VO")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class CpUserCreateReqVO extends CpUserBaseVO {
|
||||||
|
|
||||||
|
}
|
||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.controller.admin.CpUser.vo;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import io.swagger.annotations.*;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业微信成员 Excel VO
|
||||||
|
*
|
||||||
|
* @author 系统管理员
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CpUserExcelVO {
|
||||||
|
|
||||||
|
@ExcelProperty("编号")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@ExcelProperty("用户昵称")
|
||||||
|
private String userid;
|
||||||
|
|
||||||
|
@ExcelProperty("头像")
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
@ExcelProperty("状态")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@ExcelProperty("手机号")
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
@ExcelProperty("创建时间")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
@ExcelProperty("姓名")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ExcelProperty("部门")
|
||||||
|
private Object department;
|
||||||
|
|
||||||
|
@ExcelProperty("职位")
|
||||||
|
private String position;
|
||||||
|
|
||||||
|
@ExcelProperty("邮件")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@ExcelProperty("企业邮件")
|
||||||
|
private String bizMail;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "工时")
|
||||||
|
private Integer workHour;
|
||||||
|
|
||||||
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.controller.admin.CpUser.vo;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import io.swagger.annotations.*;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
|
@ApiModel(value = "管理后台 - 企业微信成员 Excel 导出 Request VO", description = "参数和 CpUserPageReqVO 是一致的")
|
||||||
|
@Data
|
||||||
|
public class CpUserExportReqVO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "用户昵称")
|
||||||
|
private String userid;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "头像")
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "状态")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "手机号")
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
|
@ApiModelProperty(value = "开始创建时间")
|
||||||
|
private Date beginCreateTime;
|
||||||
|
|
||||||
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
|
@ApiModelProperty(value = "结束创建时间")
|
||||||
|
private Date endCreateTime;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "姓名")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "部门")
|
||||||
|
private Object department;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "职位")
|
||||||
|
private String position;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "邮件")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "企业邮件")
|
||||||
|
private String bizMail;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "工时")
|
||||||
|
private Integer workHour;
|
||||||
|
}
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.controller.admin.CpUser.vo;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import io.swagger.annotations.*;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
|
@ApiModel("管理后台 - 企业微信成员分页 Request VO")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class CpUserPageReqVO extends PageParam {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "用户昵称")
|
||||||
|
private String userid;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "头像")
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "状态")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "手机号")
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
|
@ApiModelProperty(value = "开始创建时间")
|
||||||
|
private Date beginCreateTime;
|
||||||
|
|
||||||
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
|
@ApiModelProperty(value = "结束创建时间")
|
||||||
|
private Date endCreateTime;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "姓名")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "部门")
|
||||||
|
private Object department;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "职位")
|
||||||
|
private String position;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "邮件")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "企业邮件")
|
||||||
|
private String bizMail;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "工时")
|
||||||
|
private Integer workHour;
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.controller.admin.CpUser.vo;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import io.swagger.annotations.*;
|
||||||
|
|
||||||
|
@ApiModel("管理后台 - 企业微信成员 Response VO")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class CpUserRespVO extends CpUserBaseVO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "编号", required = true)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "创建时间", required = true)
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.controller.admin.CpUser.vo;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import io.swagger.annotations.*;
|
||||||
|
import javax.validation.constraints.*;
|
||||||
|
|
||||||
|
@ApiModel("管理后台 - 企业微信成员更新 Request VO")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class CpUserUpdateReqVO extends CpUserBaseVO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "编号", required = true)
|
||||||
|
@NotNull(message = "编号不能为空")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
}
|
||||||
+102
@@ -1,17 +1,32 @@
|
|||||||
package cn.iocoder.yudao.module.system.controller.admin.auth;
|
package cn.iocoder.yudao.module.system.controller.admin.auth;
|
||||||
|
|
||||||
|
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||||
|
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
|
||||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||||
|
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.auth.param.WxCpLoginDto;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*;
|
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
|
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
|
||||||
|
import cn.iocoder.yudao.module.system.convert.user.UserConvert;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.dataobject.CpUser.CpUserDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
|
||||||
|
import cn.iocoder.yudao.module.system.enums.ErrorCodeConstants;
|
||||||
import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
|
import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.system.service.CpUser.CpUserService;
|
||||||
import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
|
import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
|
||||||
|
import cn.iocoder.yudao.module.system.service.auth.AdminAuthServiceImpl;
|
||||||
|
import cn.iocoder.yudao.module.system.service.auth.UserSessionService;
|
||||||
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
|
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
|
||||||
import cn.iocoder.yudao.module.system.service.permission.RoleService;
|
import cn.iocoder.yudao.module.system.service.permission.RoleService;
|
||||||
import cn.iocoder.yudao.module.system.service.social.SocialUserService;
|
import cn.iocoder.yudao.module.system.service.social.SocialUserService;
|
||||||
@@ -21,6 +36,12 @@ import io.swagger.annotations.ApiImplicitParam;
|
|||||||
import io.swagger.annotations.ApiImplicitParams;
|
import io.swagger.annotations.ApiImplicitParams;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import me.chanjar.weixin.common.error.WxErrorException;
|
||||||
|
import me.chanjar.weixin.cp.api.WxCpService;
|
||||||
|
import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
@@ -46,11 +67,29 @@ public class AuthController {
|
|||||||
@Resource
|
@Resource
|
||||||
private AdminUserService userService;
|
private AdminUserService userService;
|
||||||
@Resource
|
@Resource
|
||||||
|
private AdminUserMapper adminUserMapper;
|
||||||
|
@Resource
|
||||||
private RoleService roleService;
|
private RoleService roleService;
|
||||||
@Resource
|
@Resource
|
||||||
private PermissionService permissionService;
|
private PermissionService permissionService;
|
||||||
@Resource
|
@Resource
|
||||||
private SocialUserService socialUserService;
|
private SocialUserService socialUserService;
|
||||||
|
@Resource
|
||||||
|
private CpUserService cpUserService;
|
||||||
|
@Resource
|
||||||
|
private WxCpService wxCpService;
|
||||||
|
@Resource
|
||||||
|
private UserSessionService userSessionService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AdminAuthServiceImpl adminAuthService;
|
||||||
|
@Resource
|
||||||
|
private UserRoleMapper userRoleMapper;
|
||||||
|
@Resource
|
||||||
|
private PasswordEncoder passwordEncoder;
|
||||||
|
@Resource
|
||||||
|
private WxMaService wxMaService;
|
||||||
|
|
||||||
|
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
@ApiOperation("使用账号密码登录")
|
@ApiOperation("使用账号密码登录")
|
||||||
@@ -61,6 +100,69 @@ public class AuthController {
|
|||||||
return success(AuthLoginRespVO.builder().token(token).build());
|
return success(AuthLoginRespVO.builder().token(token).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/loginByCp")
|
||||||
|
@ApiOperation("微信小程序登录")
|
||||||
|
public CommonResult<AuthLoginRespVO> loginByMxApp(@RequestBody @Valid WxCpLoginDto dto) throws WxErrorException {
|
||||||
|
CpUserDO cpuser;
|
||||||
|
// 企业微信登录
|
||||||
|
if ("wxcp".equals(dto.getCode())){
|
||||||
|
cpuser = cpUserService.getByUserId("test");
|
||||||
|
}else{
|
||||||
|
if (dto.getPlatform().equalsIgnoreCase("WX")){
|
||||||
|
//普通微信
|
||||||
|
WxMaJscode2SessionResult result = wxMaService.jsCode2SessionInfo(dto.getCode());
|
||||||
|
log.info("微信登录信息,{}", result);
|
||||||
|
cpuser = cpUserService.getByUserId(result.getUnionid());
|
||||||
|
if (ObjectUtil.isEmpty(cpuser)){
|
||||||
|
cpuser = cpUserService.getByUserId("test");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
//企业微信
|
||||||
|
WxCpMaJsCode2SessionResult session = wxCpService.jsCode2Session(dto.getCode());
|
||||||
|
log.info("企业微信登录信息:{}", session);
|
||||||
|
cpuser = cpUserService.getByUserId(session.getUserId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ObjectUtil.isEmpty(cpuser)){
|
||||||
|
return CommonResult.error(ErrorCodeConstants.USER_NOT_EXISTS.getCode(),"未发现绑定的企业用户,暂时无法登录,请联系管理员");
|
||||||
|
}
|
||||||
|
|
||||||
|
AdminUserDO user = userService.getUserByUsername(cpuser.getUserId());
|
||||||
|
if (ObjectUtil.isEmpty(user)){
|
||||||
|
//第一次登录 注册一个系统用户
|
||||||
|
user = AdminUserDO.builder()
|
||||||
|
.username(cpuser.getUserId())
|
||||||
|
.nickname(cpuser.getName())
|
||||||
|
.cpUserId(cpuser.getUserId())
|
||||||
|
.password((passwordEncoder.encode("123456")))
|
||||||
|
.cpUserId(cpuser.getUserId())
|
||||||
|
.build();
|
||||||
|
user.setTenantId(1L);
|
||||||
|
adminUserMapper.insert(user);
|
||||||
|
|
||||||
|
//设置默认角色 农场人员
|
||||||
|
UserRoleDO userRole = new UserRoleDO();
|
||||||
|
userRole.setUserId(user.getId());
|
||||||
|
userRole.setRoleId(112L);
|
||||||
|
userRole.setTenantId(1L);
|
||||||
|
userRoleMapper.insert(userRole);
|
||||||
|
|
||||||
|
}else {
|
||||||
|
user.setCpUserId(cpuser.getUserId());
|
||||||
|
userService.updateUser(UserConvert.INSTANCE.convertFromEntity(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginUser login = AuthConvert.INSTANCE.convert(user);
|
||||||
|
//权限
|
||||||
|
login.setRoleIds(adminAuthService.getUserRoleIds(login.getId()));
|
||||||
|
String token = userSessionService.createUserSession(login, getClientIP(), getUserAgent());
|
||||||
|
|
||||||
|
log.info("{}:TOKEN:::{}",user.getUsername(),token);
|
||||||
|
AuthLoginRespVO vo = AuthLoginRespVO.builder().token(token).user(cpuser).build();
|
||||||
|
return CommonResult.success(vo);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/get-permission-info")
|
@GetMapping("/get-permission-info")
|
||||||
@ApiOperation("获取登录用户的权限信息")
|
@ApiOperation("获取登录用户的权限信息")
|
||||||
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
|
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.controller.admin.auth.param;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class WxCpLoginDto {
|
||||||
|
|
||||||
|
@NotEmpty(message = "CODE不能为空")
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
private String platform;
|
||||||
|
|
||||||
|
}
|
||||||
+3
-1
@@ -18,7 +18,7 @@ import javax.validation.constraints.Pattern;
|
|||||||
@Builder
|
@Builder
|
||||||
public class AuthLoginReqVO {
|
public class AuthLoginReqVO {
|
||||||
|
|
||||||
@ApiModelProperty(value = "账号", required = true, example = "yudaoyuanma")
|
@ApiModelProperty(value = "账号", required = true, example = "zsw")
|
||||||
@NotEmpty(message = "登录账号不能为空")
|
@NotEmpty(message = "登录账号不能为空")
|
||||||
@Length(min = 4, max = 16, message = "账号长度为 4-16 位")
|
@Length(min = 4, max = 16, message = "账号长度为 4-16 位")
|
||||||
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
|
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
|
||||||
@@ -37,6 +37,8 @@ public class AuthLoginReqVO {
|
|||||||
@NotEmpty(message = "唯一标识不能为空", groups = CodeEnableGroup.class)
|
@NotEmpty(message = "唯一标识不能为空", groups = CodeEnableGroup.class)
|
||||||
private String uuid;
|
private String uuid;
|
||||||
|
|
||||||
|
private String platform;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 开启验证码的 Group
|
* 开启验证码的 Group
|
||||||
*/
|
*/
|
||||||
|
|||||||
+4
-1
@@ -1,5 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth;
|
package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.system.dal.dataobject.CpUser.CpUserDO;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@@ -14,7 +16,8 @@ import lombok.NoArgsConstructor;
|
|||||||
@Builder
|
@Builder
|
||||||
public class AuthLoginRespVO {
|
public class AuthLoginRespVO {
|
||||||
|
|
||||||
@ApiModelProperty(value = "token", required = true, example = "yudaoyuanma")
|
@ApiModelProperty(value = "token", required = true, example = "zsw")
|
||||||
private String token;
|
private String token;
|
||||||
|
|
||||||
|
private CpUserDO user;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -34,6 +34,9 @@ public class AuthMenuRespVO {
|
|||||||
@ApiModelProperty(value = "菜单图标", example = "/menu/list", notes = "仅菜单类型为菜单或者目录时,才需要传")
|
@ApiModelProperty(value = "菜单图标", example = "/menu/list", notes = "仅菜单类型为菜单或者目录时,才需要传")
|
||||||
private String icon;
|
private String icon;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "是否隐藏")
|
||||||
|
private Boolean hidden;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 子路由
|
* 子路由
|
||||||
*/
|
*/
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@ public class AuthSocialLogin2ReqVO {
|
|||||||
@NotEmpty(message = "state 不能为空")
|
@NotEmpty(message = "state 不能为空")
|
||||||
private String state;
|
private String state;
|
||||||
|
|
||||||
@ApiModelProperty(value = "账号", required = true, example = "yudaoyuanma")
|
@ApiModelProperty(value = "账号", required = true, example = "zsw")
|
||||||
@NotEmpty(message = "登录账号不能为空")
|
@NotEmpty(message = "登录账号不能为空")
|
||||||
@Length(min = 4, max = 16, message = "账号长度为 4-16 位")
|
@Length(min = 4, max = 16, message = "账号长度为 4-16 位")
|
||||||
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
|
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
|
||||||
|
|||||||
+2
@@ -50,4 +50,6 @@ public class MenuBaseVO {
|
|||||||
@NotNull(message = "状态不能为空")
|
@NotNull(message = "状态不能为空")
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
|
private Boolean hidden;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -51,4 +51,7 @@ public class UserBaseVO {
|
|||||||
@ApiModelProperty(value = "用户头像", example = "https://www.iocoder.cn/xxx.png")
|
@ApiModelProperty(value = "用户头像", example = "https://www.iocoder.cn/xxx.png")
|
||||||
private String avatar;
|
private String avatar;
|
||||||
|
|
||||||
|
@ApiModelProperty("企业微信userid")
|
||||||
|
private String cpUserId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -28,4 +28,6 @@ public class UserRespVO extends UserBaseVO {
|
|||||||
@ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式")
|
@ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式")
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
|
|
||||||
|
@ApiModelProperty("企业微信userid")
|
||||||
|
private String cpUserId;
|
||||||
}
|
}
|
||||||
|
|||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.convert.CpUser;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
|
||||||
|
import me.chanjar.weixin.cp.bean.WxCpUser;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.CpUser.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.dataobject.CpUser.CpUserDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业微信成员 Convert
|
||||||
|
*
|
||||||
|
* @author 系统管理员
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CpUserConvert {
|
||||||
|
|
||||||
|
CpUserConvert INSTANCE = Mappers.getMapper(CpUserConvert.class);
|
||||||
|
|
||||||
|
CpUserDO convert(CpUserCreateReqVO bean);
|
||||||
|
|
||||||
|
CpUserDO convert(CpUserUpdateReqVO bean);
|
||||||
|
|
||||||
|
CpUserRespVO convert(CpUserDO bean);
|
||||||
|
|
||||||
|
List<CpUserRespVO> convertList(List<CpUserDO> list);
|
||||||
|
|
||||||
|
PageResult<CpUserRespVO> convertPage(PageResult<CpUserDO> page);
|
||||||
|
|
||||||
|
List<CpUserExcelVO> convertList02(List<CpUserDO> list);
|
||||||
|
|
||||||
|
List<CpUserDO> convertListFromWxApi(List<WxCpUser> list);
|
||||||
|
|
||||||
|
}
|
||||||
+12
-1
@@ -10,12 +10,15 @@ import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
|
|||||||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
||||||
import cn.iocoder.yudao.module.system.enums.permission.MenuIdEnum;
|
import cn.iocoder.yudao.module.system.enums.permission.MenuIdEnum;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mapping;
|
import org.mapstruct.Mapping;
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface AuthConvert {
|
public interface AuthConvert {
|
||||||
@@ -31,10 +34,18 @@ public interface AuthConvert {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) {
|
default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) {
|
||||||
|
Set<String> permissions = CollectionUtils.convertSet(menuList, MenuDO::getPermission);
|
||||||
|
// 兼容了一个菜单多个权限。包含逗号分为多块写入
|
||||||
|
menuList.forEach(menuDO -> {
|
||||||
|
if (menuDO.getPermission().contains(",")){
|
||||||
|
permissions.remove(menuDO.getPermission());
|
||||||
|
permissions.addAll( Sets.newHashSet(Arrays.asList(menuDO.getPermission().split(","))));
|
||||||
|
}
|
||||||
|
});
|
||||||
return AuthPermissionInfoRespVO.builder()
|
return AuthPermissionInfoRespVO.builder()
|
||||||
.user(AuthPermissionInfoRespVO.UserVO.builder().id(user.getId()).nickname(user.getNickname()).avatar(user.getAvatar()).build())
|
.user(AuthPermissionInfoRespVO.UserVO.builder().id(user.getId()).nickname(user.getNickname()).avatar(user.getAvatar()).build())
|
||||||
.roles(CollectionUtils.convertSet(roleList, RoleDO::getCode))
|
.roles(CollectionUtils.convertSet(roleList, RoleDO::getCode))
|
||||||
.permissions(CollectionUtils.convertSet(menuList, MenuDO::getPermission))
|
.permissions(permissions)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
@@ -23,6 +23,8 @@ public interface UserConvert {
|
|||||||
|
|
||||||
UserPageItemRespVO convert(AdminUserDO bean);
|
UserPageItemRespVO convert(AdminUserDO bean);
|
||||||
|
|
||||||
|
UserUpdateReqVO convertFromEntity(AdminUserDO bean);
|
||||||
|
|
||||||
UserPageItemRespVO.Dept convert(DeptDO bean);
|
UserPageItemRespVO.Dept convert(DeptDO bean);
|
||||||
|
|
||||||
AdminUserDO convert(UserCreateReqVO bean);
|
AdminUserDO convert(UserCreateReqVO bean);
|
||||||
|
|||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.dal.dataobject.CpUser;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业微信成员 DO
|
||||||
|
*
|
||||||
|
* @author 系统管理员
|
||||||
|
*/
|
||||||
|
@TableName("wxcp_users")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class CpUserDO extends BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编号
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
/**
|
||||||
|
* 用户昵称
|
||||||
|
*/
|
||||||
|
@TableField(value = "user_id")
|
||||||
|
private String userId;
|
||||||
|
/**
|
||||||
|
* 头像
|
||||||
|
*/
|
||||||
|
private String avatar;
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
/**
|
||||||
|
* 手机号
|
||||||
|
*/
|
||||||
|
private String mobile;
|
||||||
|
/**
|
||||||
|
* 姓名
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
/**
|
||||||
|
* 部门
|
||||||
|
*/
|
||||||
|
private Object department;
|
||||||
|
/**
|
||||||
|
* 职位
|
||||||
|
*/
|
||||||
|
private String position;
|
||||||
|
/**
|
||||||
|
* 邮件
|
||||||
|
*/
|
||||||
|
private String email;
|
||||||
|
/**
|
||||||
|
* 企业邮件
|
||||||
|
*/
|
||||||
|
private String bizMail;
|
||||||
|
|
||||||
|
private Integer workHour;
|
||||||
|
|
||||||
|
}
|
||||||
+3
@@ -73,4 +73,7 @@ public class MenuDO extends BaseDO {
|
|||||||
*/
|
*/
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private Boolean hidden;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -1,8 +1,10 @@
|
|||||||
package cn.iocoder.yudao.module.system.dal.dataobject.permission;
|
package cn.iocoder.yudao.module.system.dal.dataobject.permission;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
@@ -14,7 +16,7 @@ import lombok.EqualsAndHashCode;
|
|||||||
@TableName("system_user_role")
|
@TableName("system_user_role")
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class UserRoleDO extends BaseDO {
|
public class UserRoleDO extends TenantBaseDO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自增主键
|
* 自增主键
|
||||||
|
|||||||
+5
@@ -91,4 +91,9 @@ public class AdminUserDO extends TenantBaseDO {
|
|||||||
*/
|
*/
|
||||||
private Date loginDate;
|
private Date loginDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业微信用户ID
|
||||||
|
*/
|
||||||
|
private String cpUserId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.dal.mysql.CpUser;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.dataobject.CpUser.CpUserDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.CpUser.vo.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业微信成员 Mapper
|
||||||
|
*
|
||||||
|
* @author 系统管理员
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CpUserMapper extends BaseMapperX<CpUserDO> {
|
||||||
|
|
||||||
|
default PageResult<CpUserDO> selectPage(CpUserPageReqVO reqVO) {
|
||||||
|
return selectPage(reqVO, new LambdaQueryWrapperX<CpUserDO>()
|
||||||
|
.eqIfPresent(CpUserDO::getUserId, reqVO.getUserid())
|
||||||
|
.eqIfPresent(CpUserDO::getAvatar, reqVO.getAvatar())
|
||||||
|
.eqIfPresent(CpUserDO::getStatus, reqVO.getStatus())
|
||||||
|
.eqIfPresent(CpUserDO::getMobile, reqVO.getMobile())
|
||||||
|
.betweenIfPresent(CpUserDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
|
||||||
|
.likeIfPresent(CpUserDO::getName, reqVO.getName())
|
||||||
|
.eqIfPresent(CpUserDO::getDepartment, reqVO.getDepartment())
|
||||||
|
.eqIfPresent(CpUserDO::getPosition, reqVO.getPosition())
|
||||||
|
.eqIfPresent(CpUserDO::getEmail, reqVO.getEmail())
|
||||||
|
.eqIfPresent(CpUserDO::getBizMail, reqVO.getBizMail())
|
||||||
|
.orderByDesc(CpUserDO::getId));
|
||||||
|
}
|
||||||
|
|
||||||
|
default List<CpUserDO> selectList(CpUserExportReqVO reqVO) {
|
||||||
|
return selectList(new LambdaQueryWrapperX<CpUserDO>()
|
||||||
|
.eqIfPresent(CpUserDO::getUserId, reqVO.getUserid())
|
||||||
|
.eqIfPresent(CpUserDO::getAvatar, reqVO.getAvatar())
|
||||||
|
.eqIfPresent(CpUserDO::getStatus, reqVO.getStatus())
|
||||||
|
.eqIfPresent(CpUserDO::getMobile, reqVO.getMobile())
|
||||||
|
.betweenIfPresent(CpUserDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
|
||||||
|
.likeIfPresent(CpUserDO::getName, reqVO.getName())
|
||||||
|
.eqIfPresent(CpUserDO::getDepartment, reqVO.getDepartment())
|
||||||
|
.eqIfPresent(CpUserDO::getPosition, reqVO.getPosition())
|
||||||
|
.eqIfPresent(CpUserDO::getEmail, reqVO.getEmail())
|
||||||
|
.eqIfPresent(CpUserDO::getBizMail, reqVO.getBizMail())
|
||||||
|
.orderByDesc(CpUserDO::getId));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.dal.mysql.dict;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.system.dict.DictModel;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface DictMapper extends BaseMapper<DictModel> {
|
||||||
|
|
||||||
|
List<DictModel> queryTableDictByKeysAndFilterSql(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("filterSql") String filterSql, @Param("codeValues") List<String> codeValues);
|
||||||
|
|
||||||
|
}
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.dict;
|
||||||
|
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典注解
|
||||||
|
* @author: dangzhenghui
|
||||||
|
* @date: 2019年03月17日-下午9:37:16
|
||||||
|
*/
|
||||||
|
@Target(ElementType.FIELD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Dict {
|
||||||
|
/**
|
||||||
|
* 方法描述: 数据code
|
||||||
|
* 作 者: dangzhenghui
|
||||||
|
* 日 期: 2019年03月17日-下午9:37:16
|
||||||
|
*
|
||||||
|
* @return 返回类型: String
|
||||||
|
*/
|
||||||
|
String dicCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方法描述: 数据Text
|
||||||
|
* 作 者: dangzhenghui
|
||||||
|
* 日 期: 2019年03月17日-下午9:37:16
|
||||||
|
*
|
||||||
|
* @return 返回类型: String
|
||||||
|
*/
|
||||||
|
String dicText() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方法描述: 数据字典表
|
||||||
|
* 作 者: dangzhenghui
|
||||||
|
* 日 期: 2019年03月17日-下午9:37:16
|
||||||
|
*
|
||||||
|
* @return 返回类型: String
|
||||||
|
*/
|
||||||
|
String dictTable() default "";
|
||||||
|
}
|
||||||
+327
@@ -0,0 +1,327 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.dict;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
|
||||||
|
import com.alibaba.druid.support.json.JSONUtils;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.alibaba.fastjson.parser.Feature;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 字典aop类
|
||||||
|
* @Author: dangzhenghui
|
||||||
|
* @Date: 2019-3-17 21:50
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class DictAspect {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DictDataService dictDataService;
|
||||||
|
@Autowired
|
||||||
|
public RedisTemplate redisTemplate;
|
||||||
|
|
||||||
|
public static final String DICT_TEXT_SUFFIX = "_dictText";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定义切点Pointcut
|
||||||
|
*/
|
||||||
|
@Pointcut("execution(public * cn.iocoder.yudao.module.*.controller..*.*Controller.*(..))")
|
||||||
|
public void excudeService() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Around("excudeService()")
|
||||||
|
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
|
||||||
|
long time1=System.currentTimeMillis();
|
||||||
|
Object result = pjp.proceed();
|
||||||
|
long time2=System.currentTimeMillis();
|
||||||
|
log.debug("获取JSON数据 耗时:"+(time2-time1)+"ms");
|
||||||
|
long start=System.currentTimeMillis();
|
||||||
|
this.parseDictText(result);
|
||||||
|
long end=System.currentTimeMillis();
|
||||||
|
log.debug("注入字典到JSON数据 耗时"+(end-start)+"ms");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本方法针对返回对象为Result 的IPage的分页列表数据进行动态字典注入
|
||||||
|
* 字典注入实现 通过对实体类添加注解@dict 来标识需要的字典内容,字典分为单字典code即可 ,table字典 code table text配合使用与原来jeecg的用法相同
|
||||||
|
* 示例为SysUser 字段为sex 添加了注解@Dict(dicCode = "sex") 会在字典服务立马查出来对应的text 然后在请求list的时候将这个字典text,已字段名称加_dictText形式返回到前端
|
||||||
|
* 例输入当前返回值的就会多出一个sex_dictText字段
|
||||||
|
* {
|
||||||
|
* sex:1,
|
||||||
|
* sex_dictText:"男"
|
||||||
|
* }
|
||||||
|
* 前端直接取值sext_dictText在table里面无需再进行前端的字典转换了
|
||||||
|
* customRender:function (text) {
|
||||||
|
* if(text==1){
|
||||||
|
* return "男";
|
||||||
|
* }else if(text==2){
|
||||||
|
* return "女";
|
||||||
|
* }else{
|
||||||
|
* return text;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* 目前vue是这么进行字典渲染到table上的多了就很麻烦了 这个直接在服务端渲染完成前端可以直接用
|
||||||
|
* @param result
|
||||||
|
*/
|
||||||
|
private void parseDictText(Object result) {
|
||||||
|
if (result instanceof CommonResult) {
|
||||||
|
if (((CommonResult) result).getData() instanceof PageResult) {
|
||||||
|
List<JSONObject> items = new ArrayList<>();
|
||||||
|
|
||||||
|
//step.1 筛选出加了 Dict 注解的字段列表
|
||||||
|
List<Field> dictFieldList = new ArrayList<>();
|
||||||
|
// 字典数据列表, key = 字典code,value=数据列表
|
||||||
|
Map<String, List<String>> dataListMap = new HashMap<>(5);
|
||||||
|
|
||||||
|
for (Object record : ((PageResult) ((CommonResult) result).getData()).getList()) {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
// 1String json="{}";
|
||||||
|
String json = JSONUtil.toJsonStr(record);
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// //解决@JsonFormat注解解析不了的问题详见SysAnnouncement类的@JsonFormat
|
||||||
|
// json = mapper.writeValueAsString(record);
|
||||||
|
// } catch (JsonProcessingException e) {
|
||||||
|
// log.error("json解析失败"+e.getMessage(),e);
|
||||||
|
// }
|
||||||
|
//update-begin--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 -----
|
||||||
|
JSONObject item = JSONObject.parseObject(json, Feature.OrderedField);
|
||||||
|
//update-end--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 -----
|
||||||
|
|
||||||
|
//update-begin--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------
|
||||||
|
//for (Field field : record.getClass().getDeclaredFields()) {
|
||||||
|
// 遍历所有字段,把字典Code取出来,放到 map 里
|
||||||
|
for (Field field : getAllFields(record)) {
|
||||||
|
String value = item.getString(field.getName());
|
||||||
|
if (ObjectUtil.isEmpty(value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//update-end--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------
|
||||||
|
if (field.getAnnotation(Dict.class) != null) {
|
||||||
|
if (!dictFieldList.contains(field)) {
|
||||||
|
dictFieldList.add(field);
|
||||||
|
}
|
||||||
|
String code = field.getAnnotation(Dict.class).dicCode();
|
||||||
|
String text = field.getAnnotation(Dict.class).dicText();
|
||||||
|
String table = field.getAnnotation(Dict.class).dictTable();
|
||||||
|
|
||||||
|
List<String> dataList;
|
||||||
|
String dictCode = code;
|
||||||
|
if (!StringUtils.isEmpty(table)) {
|
||||||
|
dictCode = String.format("%s,%s,%s", table, text, code);
|
||||||
|
}
|
||||||
|
dataList = dataListMap.computeIfAbsent(dictCode, k -> new ArrayList<>());
|
||||||
|
this.listAddAllDeduplicate(dataList, Arrays.asList(value.split(",")));
|
||||||
|
}
|
||||||
|
//date类型默认转换string格式化日期
|
||||||
|
// if (CommonConstant.JAVA_UTIL_DATE.equals(field.getType().getName())&&field.getAnnotation(JsonFormat.class)==null&&item.get(field.getName())!=null){
|
||||||
|
// SimpleDateFormat aDate=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
// item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
items.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
//step.2 调用翻译方法,一次性翻译
|
||||||
|
Map<String, List<DictModel>> translText = this.translateAllDict(dataListMap);
|
||||||
|
|
||||||
|
//step.3 将翻译结果填充到返回结果里
|
||||||
|
for (JSONObject record : items) {
|
||||||
|
for (Field field : dictFieldList) {
|
||||||
|
String code = field.getAnnotation(Dict.class).dicCode();
|
||||||
|
String text = field.getAnnotation(Dict.class).dicText();
|
||||||
|
String table = field.getAnnotation(Dict.class).dictTable();
|
||||||
|
|
||||||
|
String fieldDictCode = code;
|
||||||
|
if (!StringUtils.isEmpty(table)) {
|
||||||
|
fieldDictCode = String.format("%s,%s,%s", table, text, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
String value = record.getString(field.getName());
|
||||||
|
if (ObjectUtil.isNotEmpty(value)) {
|
||||||
|
List<DictModel> dictModels = translText.get(fieldDictCode);
|
||||||
|
if(dictModels==null || dictModels.size()==0){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String textValue = this.translDictText(dictModels, value);
|
||||||
|
log.debug(" 字典Val : " + textValue);
|
||||||
|
log.debug(" __翻译字典字段__ " + field.getName() + DICT_TEXT_SUFFIX + ": " + textValue);
|
||||||
|
|
||||||
|
// TODO-sun 测试输出,待删
|
||||||
|
log.debug(" ---- dictCode: " + fieldDictCode);
|
||||||
|
log.debug(" ---- value: " + value);
|
||||||
|
log.debug(" ----- text: " + textValue);
|
||||||
|
log.debug(" ---- dictModels: " + JSON.toJSONString(dictModels));
|
||||||
|
|
||||||
|
record.put(field.getName() + DICT_TEXT_SUFFIX, textValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
((PageResult)((CommonResult) result).getData()).setList(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list 去重添加
|
||||||
|
*/
|
||||||
|
private void listAddAllDeduplicate(List<String> dataList, List<String> addList) {
|
||||||
|
// 筛选出dataList中没有的数据
|
||||||
|
List<String> filterList = addList.stream().filter(i -> !dataList.contains(i)).collect(Collectors.toList());
|
||||||
|
dataList.addAll(filterList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一次性把所有的字典都翻译了
|
||||||
|
* 1. 所有的普通数据字典的所有数据只执行一次SQL
|
||||||
|
* 2. 表字典相同的所有数据只执行一次SQL
|
||||||
|
* @param dataListMap
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Map<String, List<DictModel>> translateAllDict(Map<String, List<String>> dataListMap) {
|
||||||
|
// 翻译后的字典文本,key=dictCode
|
||||||
|
Map<String, List<DictModel>> translText = new HashMap<>(5);
|
||||||
|
// 需要翻译的数据(有些可以从redis缓存中获取,就不走数据库查询)
|
||||||
|
List<String> needTranslData = new ArrayList<>();
|
||||||
|
//step.1 先通过redis中获取缓存字典数据
|
||||||
|
for (String dictCode : dataListMap.keySet()) {
|
||||||
|
List<String> dataList = dataListMap.get(dictCode);
|
||||||
|
if (dataList.size() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 表字典需要翻译的数据
|
||||||
|
List<String> needTranslDataTable = new ArrayList<>();
|
||||||
|
for (String s : dataList) {
|
||||||
|
String data = s.trim();
|
||||||
|
if (data.length() == 0) {
|
||||||
|
continue; //跳过循环
|
||||||
|
}
|
||||||
|
if (dictCode.contains(",")) {
|
||||||
|
String keyString = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, data);
|
||||||
|
if (redisTemplate.hasKey(keyString)) {
|
||||||
|
try {
|
||||||
|
String text = redisTemplate.opsForValue().get(keyString).toString();
|
||||||
|
List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());
|
||||||
|
list.add(new DictModel(data, text));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn(e.getMessage());
|
||||||
|
}
|
||||||
|
} else if (!needTranslDataTable.contains(data)) {
|
||||||
|
// 去重添加
|
||||||
|
needTranslDataTable.add(data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String keyString = String.format("sys:cache:dict::%s:%s", dictCode, data);
|
||||||
|
if (redisTemplate.hasKey(keyString)) {
|
||||||
|
try {
|
||||||
|
String text = redisTemplate.opsForValue().get(keyString).toString();
|
||||||
|
List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());
|
||||||
|
list.add(new DictModel(data, text));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn(e.getMessage());
|
||||||
|
}
|
||||||
|
} else if (!needTranslData.contains(data)) {
|
||||||
|
// 去重添加
|
||||||
|
needTranslData.add(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//step.2 调用数据库翻译表字典
|
||||||
|
if (needTranslDataTable.size() > 0) {
|
||||||
|
String[] arr = dictCode.split(",");
|
||||||
|
String table = arr[0], text = arr[1], code = arr[2];
|
||||||
|
String values = String.join(",", needTranslDataTable);
|
||||||
|
log.info("translateDictFromTableByKeys.dictCode:" + dictCode);
|
||||||
|
log.info("translateDictFromTableByKeys.values:" + values);
|
||||||
|
List<DictModel> texts = dictDataService.queryTableDictTextByKeys(table,text,code,needTranslDataTable);
|
||||||
|
log.info("translateDictFromTableByKeys.result:" + texts);
|
||||||
|
List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());
|
||||||
|
list.addAll(texts);
|
||||||
|
|
||||||
|
// 做 redis 缓存
|
||||||
|
for (DictModel dict : texts) {
|
||||||
|
String redisKey = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, dict.getValue());
|
||||||
|
try {
|
||||||
|
// update-begin-author:taoyan date:20211012 for: 字典表翻译注解缓存未更新 issues/3061
|
||||||
|
// 保留5分钟
|
||||||
|
redisTemplate.opsForValue().set(redisKey, dict.getText(), 300, TimeUnit.SECONDS);
|
||||||
|
// update-end-author:taoyan date:20211012 for: 字典表翻译注解缓存未更新 issues/3061
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//step.3 调用数据库进行翻译普通字典
|
||||||
|
return translText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典值替换文本
|
||||||
|
*
|
||||||
|
* @param dictModels
|
||||||
|
* @param values
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String translDictText(List<DictModel> dictModels, String values) {
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
|
||||||
|
// 允许多个逗号分隔,允许传数组对象
|
||||||
|
String[] splitVal = values.split(",");
|
||||||
|
for (String val : splitVal) {
|
||||||
|
String dictText = val;
|
||||||
|
for (DictModel dict : dictModels) {
|
||||||
|
if (val.equals(dict.getValue())) {
|
||||||
|
dictText = dict.getText();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.add(dictText);
|
||||||
|
}
|
||||||
|
return String.join(",", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static Field[] getAllFields(Object object) {
|
||||||
|
Class<?> clazz = object.getClass();
|
||||||
|
List<Field> fieldList = new ArrayList<>();
|
||||||
|
while (clazz != null) {
|
||||||
|
fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
|
||||||
|
clazz = clazz.getSuperclass();
|
||||||
|
}
|
||||||
|
Field[] fields = new Field[fieldList.size()];
|
||||||
|
fieldList.toArray(fields);
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.dict;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 字典类
|
||||||
|
* @author: jeecg-boot
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class DictModel implements Serializable{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public DictModel() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public DictModel(String value, String text) {
|
||||||
|
this.value = value;
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典value
|
||||||
|
*/
|
||||||
|
private String value;
|
||||||
|
/**
|
||||||
|
* 字典文本
|
||||||
|
*/
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 特殊用途: JgEditableTable
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getTitle() {
|
||||||
|
return this.text;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 特殊用途: vue3 Select组件
|
||||||
|
*/
|
||||||
|
public String getLabel() {
|
||||||
|
return this.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+4
@@ -26,6 +26,10 @@ public class SecurityConfiguration {
|
|||||||
registry.antMatchers(buildAdminApi("/system/tenant/get-id-by-name")).anonymous();
|
registry.antMatchers(buildAdminApi("/system/tenant/get-id-by-name")).anonymous();
|
||||||
// 短信回调 API
|
// 短信回调 API
|
||||||
registry.antMatchers(buildAdminApi("/system/sms/callback/**")).anonymous();
|
registry.antMatchers(buildAdminApi("/system/sms/callback/**")).anonymous();
|
||||||
|
// 企业微信登录
|
||||||
|
registry.antMatchers(buildAdminApi("/system/loginByCp")).anonymous();
|
||||||
|
// 第三方登录
|
||||||
|
registry.antMatchers(buildAdminApi("/system/social-auth-redirect")).anonymous();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.job.cpuser;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
|
||||||
|
import cn.iocoder.yudao.module.system.service.CpUser.CpUserService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class CpWeixinUserSyncJob implements JobHandler {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CpUserService cpUserService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String execute(String param) throws Exception {
|
||||||
|
TenantContextHolder.setTenantId(1L);
|
||||||
|
cpUserService.cpUserSync();
|
||||||
|
return "企业微信同步完成...";
|
||||||
|
}
|
||||||
|
}
|
||||||
+79
@@ -0,0 +1,79 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.service.CpUser;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import javax.validation.*;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.CpUser.dto.CpMessageDto;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.CpUser.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.dataobject.CpUser.CpUserDO;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import me.chanjar.weixin.common.error.WxErrorException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业微信成员 Service 接口
|
||||||
|
*
|
||||||
|
* @author 系统管理员
|
||||||
|
*/
|
||||||
|
public interface CpUserService extends IService<CpUserDO> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建企业微信成员
|
||||||
|
*
|
||||||
|
* @param createReqVO 创建信息
|
||||||
|
* @return 编号
|
||||||
|
*/
|
||||||
|
Long createCpUser(@Valid CpUserCreateReqVO createReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新企业微信成员
|
||||||
|
*
|
||||||
|
* @param updateReqVO 更新信息
|
||||||
|
*/
|
||||||
|
void updateCpUser(@Valid CpUserUpdateReqVO updateReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除企业微信成员
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
*/
|
||||||
|
void deleteCpUser(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得企业微信成员
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
* @return 企业微信成员
|
||||||
|
*/
|
||||||
|
CpUserDO getCpUser(Long id);
|
||||||
|
|
||||||
|
CpUserDO getByUserId(String userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得企业微信成员列表
|
||||||
|
*
|
||||||
|
* @param ids 编号
|
||||||
|
* @return 企业微信成员列表
|
||||||
|
*/
|
||||||
|
List<CpUserDO> getCpUserList(Collection<Long> ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得企业微信成员分页
|
||||||
|
*
|
||||||
|
* @param pageReqVO 分页查询
|
||||||
|
* @return 企业微信成员分页
|
||||||
|
*/
|
||||||
|
PageResult<CpUserDO> getCpUserPage(CpUserPageReqVO pageReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得企业微信成员列表, 用于 Excel 导出
|
||||||
|
*
|
||||||
|
* @param exportReqVO 查询条件
|
||||||
|
* @return 企业微信成员列表
|
||||||
|
*/
|
||||||
|
List<CpUserDO> getCpUserList(CpUserExportReqVO exportReqVO);
|
||||||
|
|
||||||
|
void cpUserSync() throws WxErrorException;
|
||||||
|
|
||||||
|
void sendMessage(CpMessageDto cpMessage) throws WxErrorException;
|
||||||
|
}
|
||||||
+164
@@ -0,0 +1,164 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.service.CpUser;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.CpUser.dto.CpMessageDto;
|
||||||
|
import cn.iocoder.yudao.module.system.enums.wxcp.WxCpMsgTypeEnum;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import me.chanjar.weixin.common.error.WxErrorException;
|
||||||
|
import me.chanjar.weixin.cp.api.WxCpService;
|
||||||
|
import me.chanjar.weixin.cp.bean.WxCpDepart;
|
||||||
|
import me.chanjar.weixin.cp.bean.WxCpUser;
|
||||||
|
import me.chanjar.weixin.cp.bean.message.WxCpMessage;
|
||||||
|
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.CpUser.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.dataobject.CpUser.CpUserDO;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.system.convert.CpUser.CpUserConvert;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.mysql.CpUser.CpUserMapper;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业微信成员 Service 实现类
|
||||||
|
*
|
||||||
|
* @author 系统管理员
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
@Slf4j
|
||||||
|
public class CpUserServiceImpl extends ServiceImpl<CpUserMapper,CpUserDO> implements CpUserService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CpUserMapper cpUserMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WxCpService wxCpService;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long createCpUser(CpUserCreateReqVO createReqVO) {
|
||||||
|
// 插入
|
||||||
|
CpUserDO cpUser = CpUserConvert.INSTANCE.convert(createReqVO);
|
||||||
|
cpUserMapper.insert(cpUser);
|
||||||
|
// 返回
|
||||||
|
return cpUser.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateCpUser(CpUserUpdateReqVO updateReqVO) {
|
||||||
|
// 校验存在
|
||||||
|
this.validateCpUserExists(updateReqVO.getId());
|
||||||
|
// 更新
|
||||||
|
CpUserDO updateObj = CpUserConvert.INSTANCE.convert(updateReqVO);
|
||||||
|
cpUserMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteCpUser(Long id) {
|
||||||
|
// 校验存在
|
||||||
|
this.validateCpUserExists(id);
|
||||||
|
// 删除
|
||||||
|
cpUserMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateCpUserExists(Long id) {
|
||||||
|
if (cpUserMapper.selectById(id) == null) {
|
||||||
|
throw exception(CP_USER_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CpUserDO getCpUser(Long id) {
|
||||||
|
return cpUserMapper.selectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CpUserDO getByUserId(String userId) {
|
||||||
|
return this.getOne(Wrappers.<CpUserDO>lambdaQuery().eq(CpUserDO::getUserId,userId),false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CpUserDO> getCpUserList(Collection<Long> ids) {
|
||||||
|
return cpUserMapper.selectBatchIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<CpUserDO> getCpUserPage(CpUserPageReqVO pageReqVO) {
|
||||||
|
return cpUserMapper.selectPage(pageReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CpUserDO> getCpUserList(CpUserExportReqVO exportReqVO) {
|
||||||
|
return cpUserMapper.selectList(exportReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void cpUserSync() throws WxErrorException {
|
||||||
|
WxCpConfigStorage config = wxCpService.getWxCpConfigStorage();
|
||||||
|
List<WxCpDepart> departList = wxCpService.getDepartmentService().list(null);
|
||||||
|
|
||||||
|
//根据部门id获取部门成员信息
|
||||||
|
//6 旭清回鄉生態農業發展公司
|
||||||
|
//35 回鄉信息技术公司
|
||||||
|
List<WxCpUser> userList = wxCpService.getUserService().listByDepartment(6L, true, 0);
|
||||||
|
userList.addAll(wxCpService.getUserService().listByDepartment(35L, true, 0));
|
||||||
|
|
||||||
|
|
||||||
|
List<CpUserDO> rs = CpUserConvert.INSTANCE.convertListFromWxApi(userList);
|
||||||
|
|
||||||
|
List<CpUserDO> nowUsers = this.cpUserMapper.selectList();
|
||||||
|
|
||||||
|
// 已经存在的员工
|
||||||
|
List<String> nowUsersIds = nowUsers.stream().map(CpUserDO::getUserId).collect(Collectors.toList());
|
||||||
|
|
||||||
|
rs.removeIf(cpUserDO -> nowUsersIds.contains(cpUserDO.getUserId()));
|
||||||
|
this.saveBatch(rs);
|
||||||
|
|
||||||
|
// 已经离职的员工 设置删除
|
||||||
|
List<String> leaveUserIds = userList.stream().filter(wxCpUser -> wxCpUser.getStatus() == 0)
|
||||||
|
.map(WxCpUser::getUserId).collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (ObjectUtil.isNotEmpty(leaveUserIds)) {
|
||||||
|
List<CpUserDO> leaveUsers = this.list(Wrappers.<CpUserDO>lambdaQuery()
|
||||||
|
.in(CpUserDO::getUserId, leaveUserIds));
|
||||||
|
leaveUsers.forEach(cpUserDO -> cpUserDO.setDeleted(true));
|
||||||
|
this.updateBatchById(leaveUsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(CpMessageDto cpMessage) throws WxErrorException {
|
||||||
|
WxCpMessage message = new WxCpMessage();
|
||||||
|
String agentId = wxCpService.getWxCpConfigStorage().getAgentId().toString();
|
||||||
|
|
||||||
|
String page = String.format("/pages/task/%sDetail/index?id=%d",
|
||||||
|
cpMessage.getTypeEnum().equals(WxCpMsgTypeEnum.project) ? "project" : "task",
|
||||||
|
cpMessage.getId());
|
||||||
|
|
||||||
|
message.setMsgType("miniprogram_notice");
|
||||||
|
message.setAppId(agentId);
|
||||||
|
message.setPage(page);
|
||||||
|
message.setTitle(cpMessage.getTitle());
|
||||||
|
message.setDescription(cpMessage.getDescription());
|
||||||
|
message.setContentItems(cpMessage.getContentItems());
|
||||||
|
message.setToUser(String.join("|", cpMessage.getReciveIds()));
|
||||||
|
wxCpService.getMessageService().send(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+11
@@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*;
|
|||||||
import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
|
import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 管理后台的认证 Service 接口
|
* 管理后台的认证 Service 接口
|
||||||
@@ -24,6 +25,16 @@ public interface AdminAuthService extends SecurityAuthFrameworkService {
|
|||||||
*/
|
*/
|
||||||
String login(@Valid AuthLoginReqVO reqVO, String userIp, String userAgent);
|
String login(@Valid AuthLoginReqVO reqVO, String userIp, String userAgent);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得 User 拥有的角色编号数组
|
||||||
|
*
|
||||||
|
* @param userId 用户编号
|
||||||
|
* @return 角色编号数组
|
||||||
|
*/
|
||||||
|
Set<Long> getUserRoleIds(Long userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 社交登录,使用 code 授权码
|
* 社交登录,使用 code 授权码
|
||||||
*
|
*
|
||||||
|
|||||||
+23
-2
@@ -1,5 +1,6 @@
|
|||||||
package cn.iocoder.yudao.module.system.service.auth;
|
package cn.iocoder.yudao.module.system.service.auth;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
|
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
|
||||||
@@ -13,9 +14,11 @@ import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthSocialBi
|
|||||||
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthSocialLogin2ReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthSocialLogin2ReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthSocialLoginReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthSocialLoginReqVO;
|
||||||
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
|
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.dataobject.CpUser.CpUserDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
||||||
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
|
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
|
||||||
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
|
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
|
||||||
|
import cn.iocoder.yudao.module.system.service.CpUser.CpUserService;
|
||||||
import cn.iocoder.yudao.module.system.service.common.CaptchaService;
|
import cn.iocoder.yudao.module.system.service.common.CaptchaService;
|
||||||
import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
|
import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
|
||||||
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
|
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
|
||||||
@@ -24,7 +27,9 @@ import cn.iocoder.yudao.module.system.service.user.AdminUserService;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
import org.springframework.security.authentication.DisabledException;
|
import org.springframework.security.authentication.DisabledException;
|
||||||
@@ -71,9 +76,17 @@ public class AdminAuthServiceImpl implements AdminAuthService {
|
|||||||
@Resource
|
@Resource
|
||||||
private SocialUserService socialUserService;
|
private SocialUserService socialUserService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisTemplate redisTemplate;
|
||||||
|
@Resource
|
||||||
|
private CpUserService cpUserService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private Validator validator;
|
private Validator validator;
|
||||||
|
|
||||||
|
@Value("${spring.profiles.active}")
|
||||||
|
private String profile;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||||
// 获取 username 对应的 AdminUserDO
|
// 获取 username 对应的 AdminUserDO
|
||||||
@@ -100,19 +113,27 @@ public class AdminAuthServiceImpl implements AdminAuthService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String login(AuthLoginReqVO reqVO, String userIp, String userAgent) {
|
public String login(AuthLoginReqVO reqVO, String userIp, String userAgent) {
|
||||||
|
if ("prod".equals(profile)) {
|
||||||
// 判断验证码是否正确
|
// 判断验证码是否正确
|
||||||
this.verifyCaptcha(reqVO);
|
this.verifyCaptcha(reqVO);
|
||||||
|
}
|
||||||
|
|
||||||
// 使用账号密码,进行登录
|
// 使用账号密码,进行登录
|
||||||
LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword());
|
LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword());
|
||||||
|
|
||||||
|
CpUserDO wxUser = cpUserService.getByUserId(loginUser.getUsername());
|
||||||
|
if (ObjectUtil.isNotEmpty(wxUser)){
|
||||||
|
//将cpUserId存入 key为 系统用户id value为 cpUserId
|
||||||
|
redisTemplate.opsForValue().set("CpUserId::" + loginUser.getId(), wxUser.getId().toString());
|
||||||
|
}
|
||||||
|
|
||||||
// 缓存登陆用户到 Redis 中,返回 sessionId 编号
|
// 缓存登陆用户到 Redis 中,返回 sessionId 编号
|
||||||
return createUserSessionAfterLoginSuccess(loginUser, LoginLogTypeEnum.LOGIN_USERNAME, userIp, userAgent);
|
return createUserSessionAfterLoginSuccess(loginUser, LoginLogTypeEnum.LOGIN_USERNAME, userIp, userAgent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyCaptcha(AuthLoginReqVO reqVO) {
|
private void verifyCaptcha(AuthLoginReqVO reqVO) {
|
||||||
// 如果验证码关闭,则不进行校验
|
// 如果验证码关闭,则不进行校验
|
||||||
if (!captchaService.isCaptchaEnable()) {
|
if (!captchaService.isCaptchaEnable() || "wxcp".equals(reqVO.getPlatform())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 校验验证码
|
// 校验验证码
|
||||||
@@ -187,7 +208,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
|
|||||||
* @param userId 用户编号
|
* @param userId 用户编号
|
||||||
* @return 角色编号数组
|
* @return 角色编号数组
|
||||||
*/
|
*/
|
||||||
private Set<Long> getUserRoleIds(Long userId) {
|
public Set<Long> getUserRoleIds(Long userId) {
|
||||||
return permissionService.getUserRoleIds(userId, singleton(CommonStatusEnum.ENABLE.getStatus()));
|
return permissionService.getUserRoleIds(userId, singleton(CommonStatusEnum.ENABLE.getStatus()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
@@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataCrea
|
|||||||
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataExportReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataExportReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataUpdateReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataUpdateReqVO;
|
||||||
|
import cn.iocoder.yudao.module.system.dict.DictModel;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -94,4 +95,6 @@ public interface DictDataService extends DictDataFrameworkService {
|
|||||||
*/
|
*/
|
||||||
void validDictDatas(String dictType, Collection<String> values);
|
void validDictDatas(String dictType, Collection<String> values);
|
||||||
|
|
||||||
|
List<DictModel> queryTableDictTextByKeys(String table, String text, String code, List<String> keys);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-4
@@ -13,20 +13,20 @@ import cn.iocoder.yudao.module.system.convert.dict.DictDataConvert;
|
|||||||
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.mysql.dict.DictDataMapper;
|
import cn.iocoder.yudao.module.system.dal.mysql.dict.DictDataMapper;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.mysql.dict.DictMapper;
|
||||||
|
import cn.iocoder.yudao.module.system.dict.DictModel;
|
||||||
import cn.iocoder.yudao.module.system.mq.producer.dict.DictDataProducer;
|
import cn.iocoder.yudao.module.system.mq.producer.dict.DictDataProducer;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableTable;
|
import com.google.common.collect.ImmutableTable;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||||
@@ -40,6 +40,8 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class DictDataServiceImpl implements DictDataService {
|
public class DictDataServiceImpl implements DictDataService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DictMapper dictMapper;
|
||||||
/**
|
/**
|
||||||
* 排序 dictType > sort
|
* 排序 dictType > sort
|
||||||
*/
|
*/
|
||||||
@@ -277,4 +279,17 @@ public class DictDataServiceImpl implements DictDataService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DictModel> queryTableDictTextByKeys(String table, String text, String code, List<String> keys) {
|
||||||
|
//update-begin-author:taoyan date:20220113 for: @dict注解支持 dicttable 设置where条件
|
||||||
|
String filterSql = null;
|
||||||
|
if(table.toLowerCase().indexOf("where")>0){
|
||||||
|
String[] arr = table.split(" (?i)where ");
|
||||||
|
table = arr[0];
|
||||||
|
filterSql = arr[1];
|
||||||
|
}
|
||||||
|
return dictMapper.queryTableDictByKeysAndFilterSql(table, text, code, filterSql, keys);
|
||||||
|
//update-end-author:taoyan date:20220113 for: @dict注解支持 dicttable 设置where条件
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user