Compare commits

...

21 Commits

Author SHA1 Message Date
smallchill
bcd93a7a4e 🎉 4.5.0.RELEASE 新增账号锁定与解锁功能,新增腾讯云对象存储支持 2025-03-14 10:21:31 +08:00
smallchill
fb91e2627f 🎉 增加依赖适配新版 2025-01-21 11:01:58 +08:00
smallchill
524f13d15d 🎉 4.4.0.RELEASE 新增黑白名单、脱敏工具、BladeRedis新版工具 2025-01-20 17:06:34 +08:00
smallchill
cd04e83390 🎉 4.4.0.RELEASE 新增黑白名单、脱敏工具、BladeRedis新版工具 2025-01-18 18:19:14 +08:00
smallchill
74669cebe5 🎉 4.3.0.RELEASE 多租户支持线程模式指定租户ID与忽略租户 2024-11-07 19:56:49 +08:00
smallchill
35f70db177 🎉 4.2.0.RELEASE 重构包名,分类core模块与starter模块 2024-09-06 13:57:28 +08:00
smallchill
c3165e2ed6 🎉 4.1.0.RELEASE 登录认证升级为国密算法,数据库password字段内容无需变动 2024-07-14 23:40:58 +08:00
smallchill
31b94c25d1 🎉 4.0.0.RELEASE 升级 SpringBoot3 SpringCloud2023 JDK17 2024-04-22 00:19:47 +08:00
smallchill
15359e5cf1 🎉 3.7.1.RELEASE 升级系统安全性能 2023-12-08 00:48:40 +08:00
smallchill
0ff435c76e 🎉 增加aesKey生成器 2023-09-13 00:27:21 +08:00
smallchill
72b33cd4bb 🎉 3.7.0.RELEASE Token加密传输 2023-09-12 13:36:26 +08:00
smallchill
85daa7e425 🎉 3.7.0.RELEASE Token加密传输 2023-09-12 12:21:39 +08:00
smallchill
abc412290c 🎉 3.7.0.RELEASE Token加密传输 2023-09-12 02:00:24 +08:00
smallchill
fd5135e3a5 🎉 3.6.0.RELEASE vue3版前端正式发布 2023-04-29 22:03:24 +08:00
smallchill
647d85e326 🎉 3.5.0.RELEASE 新增报文加密 令牌签名校验提示 2022-11-01 23:30:25 +08:00
smallchill
6f587fd649 🎉 3.4.1.RELEASE 重构Swagger封装 2022-11-01 23:16:26 +08:00
smallchill
e59522a8ea 🎉 3.4.0.RELEASE 升级适配springboot2.7.1 新增灰度服务功能 2022-07-19 12:28:23 +08:00
smallchill
fc1ddb4a11 🎉 3.3.1.RELEASE 升级适配代码生成器API 2022-04-11 21:59:37 +08:00
smallchill
4d2e706fcb 🎉 3.3.0.RELEASE 升级适配SpringCloud 2021 2022-03-28 15:55:49 +08:00
smallchill
5914f6c133 🎉 3.2.0.RELEASE 新增灵活数据权限特性 2021-11-05 01:17:34 +08:00
smallchill
d15f2236c1 🎉 3.1.0.RELEASE 底层架构升级适配 2021-06-29 11:17:33 +08:00
327 changed files with 4679 additions and 2502 deletions

4
.gitignore vendored
View File

@ -25,3 +25,7 @@ Thumbs.db
*.war *.war
*.ear *.ear
/target /target
# Flattened pom
.flattened-pom.xml
/**/.flattened-pom.xml

View File

@ -176,7 +176,7 @@ recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within the same "printed page" as the copyright notice for easier identification within
third-party archives. third-party archives.
Copyright 2020 BladeX (https://bladex.vip) Copyright 2023 BladeX (https://bladex.cn)
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

222
README.md
View File

@ -1,35 +1,45 @@
<p align="center"> <p align="center">
<img src="https://img.shields.io/badge/Release-V3.0.3-green.svg" alt="Downloads"> <img src="https://img.shields.io/badge/Release-V4.5.0-green.svg" alt="Downloads">
<img src="https://img.shields.io/badge/JDK-1.8+-green.svg" alt="Build Status"> <img src="https://img.shields.io/badge/JDK-17+-green.svg" alt="Build Status">
<img src="https://img.shields.io/badge/license-Apache%202-blue.svg" alt="Build Status"> <img src="https://img.shields.io/badge/license-Apache%202-blue.svg" alt="Build Status">
<img src="https://img.shields.io/badge/Spring%20Cloud-2020-blue.svg" alt="Coverage Status"> <img src="https://img.shields.io/badge/Spring%20Cloud-2023-blue.svg" alt="Coverage Status">
<img src="https://img.shields.io/badge/Spring%20Boot-2.4.4-blue.svg" alt="Downloads"> <img src="https://img.shields.io/badge/Spring%20Boot-3.2-blue.svg" alt="Downloads">
<a target="_blank" href="https://bladex.vip"> <a target="_blank" href="https://bladex.cn">
<img src="https://img.shields.io/badge/Author-Small%20Chill-ff69b4.svg" alt="Downloads"> <img src="https://img.shields.io/badge/Author-Small%20Chill-ff69b4.svg" alt="Downloads">
</a> </a>
<a target="_blank" href="https://bladex.vip"> <a target="_blank" href="https://bladex.cn">
<img src="https://img.shields.io/badge/Copyright%20-@BladeX-%23ff3f59.svg" alt="Downloads"> <img src="https://img.shields.io/badge/Copyright%20-@BladeX-%23ff3f59.svg" alt="Downloads">
</a> </a>
</p> </p>
## SpringBlade微服务开发平台 ## SpringBlade微服务开发平台
* 采用前后端分离的模式,前端开源两个框架:[Sword](https://gitee.com/smallc/Sword) (基于 React、Ant Design)、[Saber](https://gitee.com/smallc/Saber) (基于 Vue、Element-UI) * 采用前后端分离的模式,前端开源两个框架:[Sword](https://gitee.com/smallc/Sword) (基于 React、Ant Design)、[Saber](https://gitee.com/smallc/Saber) (基于 Vue、Element-UI)
* 后端采用SpringCloud全家桶并同时对其基础组件做了高度的封装单独开源出一个框架[BladeTool](https://github.com/chillzhuang/blade-tool) * 后端采用SpringCloud全家桶并同时对其基础组件做了高度的封装单独开源出一个框架[BladeTool](https://gitee.com/smallc/blade-tool)
* [BladeTool](https://github.com/chillzhuang/blade-tool)已推送至Maven中央库直接引入即可减少了工程的臃肿也可更注重于业务开发 * [BladeTool](https://github.com/chillzhuang/blade-tool)已推送至Maven中央库直接引入即可减少了工程的臃肿也可更注重于业务开发
* 集成Sentinel从流量控制、熔断降级、系统负载等多个维度保护服务的稳定性。 * 集成Sentinel从流量控制、熔断降级、系统负载等多个维度保护服务的稳定性。
* 注册中心、配置中心选型Nacos为工程瘦身的同时加强各模块之间的联动。 * 注册中心、配置中心选型Nacos为工程瘦身的同时加强各模块之间的联动。
* 使用Traefik进行反向代理监听后台变化自动化应用新的配置文件。
* 极简封装了多租户底层用更少的代码换来拓展性更强的SaaS多租户系统。 * 极简封装了多租户底层用更少的代码换来拓展性更强的SaaS多租户系统。
* 借鉴OAuth2实现了多终端认证系统可控制子系统的token权限互相隔离。 * 借鉴OAuth2自研多终端认证系统可控制子系统的token权限互相隔离。
* 借鉴Security封装了Secure模块采用JWT做Token认证可拓展集成Redis等细颗粒度控制方案。 * 借鉴Security自研Secure模块采用JWT做Token认证可拓展集成Redis等细颗粒度控制方案。
* 稳定生产了三年,经历了从 Camden -> Hoxton -> 2020 的技术架构也经历了从fat jar -> docker -> k8s + jenkins的部署架构。 * 稳定生产了六年,经历了从 Camden -> Hoxton -> 2023 的技术架构也经历了从fat jar -> docker -> k8s + jenkins的部署架构。
* 项目分包明确,规范微服务的开发模式,使包与包之间的分工清晰。 * 项目分包明确,规范微服务的开发模式,使包与包之间的分工清晰。
## 架构图 ## 架构图
<img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-framework.png"/> <img src="https://xbladex.oss-cn-hangzhou.aliyuncs.com/upload/springblade-framework.png"/>
## 核心技术栈
| 技术栈 | 版本 |
|----------------------|------------|
| Java | 17+ |
| NodeJS | 18+ |
| Spring | 6.1.15 |
| Spring Boot | 3.2.12 |
| Spring Cloud | 2023.0.3 |
| Spring Cloud Alibaba | 2023.0.1.2 |
| Nacos Alibaba | 2.3.2 |
| Mybatis Plus | 3.5.8 |
## 趋势图
<a href="https://whnb.wang/smallc/SpringBlade" rel="nofollow"><img src="https://whnb.wang/img/smallc/SpringBlade" alt="Stargazers over time"></a>
## 工程结构 ## 工程结构
``` ```
@ -46,8 +56,7 @@ SpringBlade
├── blade-service -- 业务模块 ├── blade-service -- 业务模块
├ ├── blade-desk -- 工作台模块 ├ ├── blade-desk -- 工作台模块
├ ├── blade-log -- 日志模块 ├ ├── blade-log -- 日志模块
├ ├── blade-system -- 系统模块 ├ └── blade-system -- 系统模块
├ └── blade-user -- 用户模块
├── blade-service-api -- 业务模块api封装 ├── blade-service-api -- 业务模块api封装
├ ├── blade-desk-api -- 工作台api ├ ├── blade-desk-api -- 工作台api
├ ├── blade-dict-api -- 字典api ├ ├── blade-dict-api -- 字典api
@ -55,37 +64,70 @@ SpringBlade
└── └── blade-user-api -- 用户api └── └── blade-user-api -- 用户api
``` ```
## 官网 ## 官方信息
* 官网地址:[https://bladex.vip](https://bladex.vip)
* 问答社区:[https://sns.bladex.vip](https://sns.bladex.vip)
* 会员计划:[SpringBlade会员计划](https://gitee.com/smallc/SpringBlade/wikis/SpringBlade会员计划)
* 交流一群:`477853168`(满)
* 交流二群:`751253339`(满)
* 交流三群:`784729540`(满)
* 交流四群:`1034621754`(满)
* 交流五群:`946350912`(满)
* 交流六群:`511624269`
## 在线演示 | 简介 | 内容 |
* Saber-基于Vue[https://saber.bladex.vip](https://saber.bladex.vip) |------|-------------------------------------------------------------------------------|
* Sword-基于React[https://sword.bladex.vip](https://sword.bladex.vip) | 官网地址 | [https://bladex.cn](https://bladex.cn) |
* Archer-全能代码生成系统:[https://archer.bladex.vip](https://archer.bladex.vip) | 问答社区 | [https://sns.bladex.cn](https://sns.bladex.cn) |
* Caster-数据大屏展示系统:[https://data.avuejs.com](https://data.avuejs.com) | 会员计划 | [SpringBlade会员计划](https://gitee.com/smallc/SpringBlade/wikis/SpringBlade会员计划) |
| 交流一群 | `477853168` (满) |
| 交流二群 | `751253339` (满) |
| 交流三群 | `784729540` (满) |
| 交流四群 | `1034621754` (满) |
| 交流五群 | `946350912` (满) |
| 交流六群 | `511624269` (满) |
| 交流七群 | `298061704` |
## 官方产品
| 简介 | 演示地址 |
|-----------------|------------------------------------------------------|
| BladeX企业级开发平台 | [https://saber3.bladex.cn](https://saber3.bladex.cn) |
| BladeX可视化数据大屏 | [https://data.bladex.cn](https://data.bladex.cn) |
| BladeX物联网开发平台 | [https://iot.bladex.cn](https://iot.bladex.cn) |
| BladeXAI大模型平台 | [https://aigc.bladex.cn/](https://aigc.bladex.cn/) |
## 前端项目
| 简介 | 地址 |
|--------------------|------------------------------------------------------------------------------|
| 前端框架Saber3(基于Vue3) | [https://gitee.com/smallc/Saber3](https://gitee.com/smallc/Saber) |
| 前端框架Saber(基于Vue2) | [https://gitee.com/smallc/Saber2](https://gitee.com/smallc/Saber/tree/vue2/) |
| 前端框架Sword(基于React) | [https://gitee.com/smallc/Sword](https://gitee.com/smallc/Sword) |
## 后端项目
| 简介 | 地址 |
|---------------|----------------------------------------------------------------------------------------------------|
| 核心框架项目地址 | [https://gitee.com/smallc/blade-tool](https://gitee.com/smallc/blade-tool) |
| 后端Gitee地址 | [https://gitee.com/smallc/SpringBlade](https://gitee.com/smallc/SpringBlade) |
| 后端Github地址 | [https://github.com/chillzhuang/SpringBlade](https://github.com/chillzhuang/SpringBlade) |
| 后端SpringBoot版 | [https://gitee.com/smallc/SpringBlade/tree/boot/](https://gitee.com/smallc/SpringBlade/tree/boot/) |
## 安全手册
| 简介 | 地址 |
|-----------|----------------------------------------------------------------------------------------------------|
| Blade安全手册 | [https://www.kancloud.cn/smallchill/blade-safety](https://www.kancloud.cn/smallchill/blade-safety) |
## 技术文档 ## 技术文档
* [SpringBlade常见问题集锦](https://sns.bladex.vip/article-14966.html)
* [SpringBlade开发手册一览](https://gitee.com/smallc/SpringBlade/wikis/SpringBlade开发手册)
* [SpringBlade基于Kuboard部署K8S](https://kuboard.cn/learning/k8s-practice/spring-blade/)
## 项目地址 | 简介 | 地址 |
* 后端Gitee地址[https://gitee.com/smallc/SpringBlade](https://gitee.com/smallc/SpringBlade) |---------------------------|--------------------------------------------------------------------------------------------------------------------------|
* 后端Github地址[https://github.com/chillzhuang/SpringBlade](https://github.com/chillzhuang/SpringBlade) | SpringBlade开发手册一览 | [https://gitee.com/smallc/SpringBlade/wikis/SpringBlade开发手册](https://gitee.com/smallc/SpringBlade/wikis/SpringBlade开发手册) |
* 后端SpringBoot版[https://gitee.com/smallc/SpringBlade/tree/boot/](https://gitee.com/smallc/SpringBlade/tree/boot/) | SpringBlade常见问题集锦 | [https://sns.bladex.cn/article-14966.html](https://sns.bladex.cn/article-14966.html) |
* 前端框架Sword(基于React)[https://gitee.com/smallc/Sword](https://gitee.com/smallc/Sword) | SpringBlade基于Kuboard部署K8S | [https://kuboard.cn/learning/k8s-practice/spring-blade/](https://kuboard.cn/learning/k8s-practice/spring-blade/) |
* 前端框架Saber(基于Vue)[https://gitee.com/smallc/Saber](https://gitee.com/smallc/Saber) | SpringBlade基于Rainbond部署 | [https://www.rainbond.com/docs/micro-service/example/blade](https://www.rainbond.com/docs/micro-service/example/blade) |
* 核心框架项目地址:[https://github.com/chillzhuang/blade-tool](https://github.com/chillzhuang/blade-tool)
# 开源协议
## 免费公开课
<table>
<tr>
<td><a href="https://space.bilibili.com/525525/channel/seriesdetail?sid=2740449" target="_blank"><img style="width: 300px; height: 170px" src="https://xbladex.oss-cn-hangzhou.aliyuncs.com/upload/springblade-course.jpg"/></a></td>
<td><img style="width: 300px; height: 170px" src="https://xbladex.oss-cn-hangzhou.aliyuncs.com/upload/springblade-bilibili.jpg"/></td>
</tr>
</table>
## 开源协议
Apache Licence 2.0 [英文原文](http://www.apache.org/licenses/LICENSE-2.0.html) Apache Licence 2.0 [英文原文](http://www.apache.org/licenses/LICENSE-2.0.html)
Apache Licence是著名的非盈利开源组织Apache采用的协议。该协议和BSD类似同样鼓励代码共享和尊重原作者的著作权同样允许代码修改再发布作为开源或商业软件 Apache Licence是著名的非盈利开源组织Apache采用的协议。该协议和BSD类似同样鼓励代码共享和尊重原作者的著作权同样允许代码修改再发布作为开源或商业软件
需要满足的条件如下: 需要满足的条件如下:
@ -93,99 +135,9 @@ Apache Licence是著名的非盈利开源组织Apache采用的协议。该协议
* 如果你修改了代码,需要在被修改的文件中说明。 * 如果你修改了代码,需要在被修改的文件中说明。
* 在延伸的代码中(修改和有源代码衍生的代码中)需要带有原来代码中的协议,商标,专利声明和其他原来作者规定需要包含的说明。 * 在延伸的代码中(修改和有源代码衍生的代码中)需要带有原来代码中的协议,商标,专利声明和其他原来作者规定需要包含的说明。
* 如果再发布的产品中包含一个Notice文件则在Notice文件中需要带有Apache Licence。你可以在Notice中增加自己的许可但不可以表现为对Apache Licence构成更改。 * 如果再发布的产品中包含一个Notice文件则在Notice文件中需要带有Apache Licence。你可以在Notice中增加自己的许可但不可以表现为对Apache Licence构成更改。
Apache Licence也是对商业应用友好的许可。使用者也可以在需要的时候修改代码来满足需要并作为开源或商业产品发布/销售。 Apache Licence也是对商业应用友好的许可。使用者也可以在需要的时候修改代码来满足需要并作为开源或商业产品发布/销售。
## 用户权益 ## 用户权益
* 允许免费用于学习、毕设、公司项目、私活等。 * 允许免费用于学习、毕设、公司项目、私活等,但请保留源码作者信息
* 对未经过授权和不遵循 Apache 2.0 协议二次开源或者商业化我们将追究到底。 * 对未经过授权和不遵循 Apache 2.0 协议二次开源或者商业化我们将追究到底。
* 参考请注明:参考自 SpringBladehttps://gitee.com/smallc/SpringBlade 。另请遵循 Apache 2.0 协议。 * 参考请注明:参考自 SpringBladehttps://gitee.com/smallc/SpringBlade。
* `注意`:若禁止条款被发现有权追讨 **19999** 的授权费。
# 界面
## [BladeX](https://bladex.vip/#/vip) 工作流一览
<table>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/bladex-flow1.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/bladex-flow2.png"/></td>
</tr>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/bladex-flow3.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/bladex-flow4.png"/></td>
</tr>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/bladex-flow5.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/bladex-flow6.png"/></td>
</tr>
</table>
## [Sword](https://gitee.com/smallc/Sword) 界面一览
<table>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-main.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-menu.png"/></td>
</tr>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-menu-edit.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-menu-icon.png"/></td>
</tr>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-role.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-user.png"/></td>
</tr>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-dict.png "/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-log.png"/></td>
</tr>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-locale-cn.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-locale-us.png"/></td>
</tr>
</table>
## [Saber](https://gitee.com/smallc/Saber) 界面一览
<table>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/saber-user.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/saber-role.png"/></td>
</tr>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/saber-dict.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/saber-dict-select.png"/></td>
</tr>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/saber-log.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/saber-code.png"/></td>
</tr>
</table>
## 监控界面一览
<table>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-k8s1.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-k8s2.png"/></td>
</tr>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-grafana.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-harbor.png"/></td>
</tr>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-traefik.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-traefik-health.png"/></td>
</tr>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-nacos.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-sentinel.png"/></td>
</tr>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-admin1.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-admin2.png"/></td>
</tr>
<tr>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-swagger1.png"/></td>
<td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-swagger2.png"/></td>
</tr>
</table>
## 关注我们
![](https://images.gitee.com/uploads/images/2019/0330/065148_f0ada806_410595.jpeg)

View File

@ -1,6 +1,8 @@
FROM anapsix/alpine-java:8_server-jre_unlimited # 网络问题无法下载可以改为阿里云镜像
# FROM registry.cn-hangzhou.aliyuncs.com/bladex-repo/alpine-java:openjdk17_cn_slim
FROM bladex/alpine-java:openjdk17_cn_slim
MAINTAINER smallchill@163.com MAINTAINER bladejava@qq.com
RUN mkdir -p /blade/auth RUN mkdir -p /blade/auth
@ -10,6 +12,6 @@ EXPOSE 8010
ADD ./target/blade-auth.jar ./app.jar ADD ./target/blade-auth.jar ./app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"] ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
CMD ["--spring.profiles.active=test"] CMD ["--spring.profiles.active=test"]

View File

@ -8,12 +8,11 @@
<parent> <parent>
<artifactId>SpringBlade</artifactId> <artifactId>SpringBlade</artifactId>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<version>3.0.3</version> <version>${revision}</version>
</parent> </parent>
<artifactId>blade-auth</artifactId> <artifactId>blade-auth</artifactId>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<version>${blade.project.version}</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
@ -21,48 +20,48 @@
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-common</artifactId> <artifactId>blade-common</artifactId>
<version>${blade.project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-cloud</artifactId> <artifactId>blade-core-cloud</artifactId>
<version>${blade.tool.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-secure</artifactId> <artifactId>blade-core-secure</artifactId>
<version>${blade.tool.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-log</artifactId> <artifactId>blade-starter-log</artifactId>
<version>${blade.tool.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-social</artifactId> <artifactId>blade-starter-social</artifactId>
<version>${blade.tool.version}</version> </dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-redis</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-user-api</artifactId> <artifactId>blade-user-api</artifactId>
<version>${blade.project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-swagger</artifactId> <artifactId>blade-starter-swagger</artifactId>
<version>${blade.tool.version}</version> </dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot-autoconfigure</artifactId>
</dependency> </dependency>
<!-- Captcha --> <!-- Captcha -->
<dependency> <dependency>
<groupId>com.github.whvcse</groupId> <groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId> <artifactId>easy-captcha</artifactId>
<version>${captcha.version}</version>
</dependency> </dependency>
<!-- MySQL --> <!-- MySQL -->
<dependency> <dependency>
<groupId>mysql</groupId> <groupId>com.mysql</groupId>
<artifactId>mysql-connector-java</artifactId> <artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
</dependencies> </dependencies>
@ -92,22 +91,6 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId> <artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<!--suppress UnresolvedMavenProperty -->
<copy overwrite="true"
tofile="${session.executionRootDirectory}/target/${artifactId}.jar"
file="${project.build.directory}/${artifactId}.jar" />
</tasks>
</configuration>
</execution>
</executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,20 +16,20 @@
package org.springblade.auth.controller; package org.springblade.auth.controller;
import com.wf.captcha.SpecCaptcha; import com.wf.captcha.SpecCaptcha;
import io.swagger.annotations.Api; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.annotations.ApiOperation; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.annotations.ApiParam; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import org.springblade.auth.granter.ITokenGranter; import org.springblade.auth.granter.ITokenGranter;
import org.springblade.auth.granter.TokenGranterBuilder; import org.springblade.auth.granter.TokenGranterBuilder;
import org.springblade.auth.granter.TokenParameter; import org.springblade.auth.granter.TokenParameter;
import org.springblade.auth.utils.TokenUtil; import org.springblade.auth.utils.TokenUtil;
import org.springblade.common.cache.CacheNames; import org.springblade.common.cache.CacheNames;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.secure.AuthInfo; import org.springblade.core.secure.AuthInfo;
import org.springblade.core.tool.api.R; import org.springblade.core.tool.api.R;
import org.springblade.core.tool.support.Kv; import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.Func; import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.RedisUtil;
import org.springblade.core.tool.utils.WebUtil; import org.springblade.core.tool.utils.WebUtil;
import org.springblade.system.user.entity.UserInfo; import org.springblade.system.user.entity.UserInfo;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@ -47,18 +47,18 @@ import java.util.concurrent.TimeUnit;
*/ */
@RestController @RestController
@AllArgsConstructor @AllArgsConstructor
@Api(value = "用户授权认证", tags = "授权接口") @Tag(name = "用户授权认证", description = "授权接口")
public class AuthController { public class AuthController {
private RedisUtil redisUtil; private BladeRedis bladeRedis;
@PostMapping("token") @PostMapping("token")
@ApiOperation(value = "获取认证token", notes = "传入租户ID:tenantId,账号:account,密码:password") @Operation(summary = "获取认证token", description = "传入租户ID:tenantId,账号:account,密码:password")
public R<AuthInfo> token(@ApiParam(value = "授权类型", required = true) @RequestParam(defaultValue = "password", required = false) String grantType, public R<AuthInfo> token(@Parameter(description = "授权类型", required = true) @RequestParam(defaultValue = "password", required = false) String grantType,
@ApiParam(value = "刷新令牌") @RequestParam(required = false) String refreshToken, @Parameter(description = "刷新令牌") @RequestParam(required = false) String refreshToken,
@ApiParam(value = "租户ID", required = true) @RequestParam(defaultValue = "000000", required = false) String tenantId, @Parameter(description = "租户ID", required = true) @RequestParam(defaultValue = "000000", required = false) String tenantId,
@ApiParam(value = "账号") @RequestParam(required = false) String account, @Parameter(description = "账号") @RequestParam(required = false) String account,
@ApiParam(value = "密码") @RequestParam(required = false) String password) { @Parameter(description = "密码") @RequestParam(required = false) String password) {
String userType = Func.toStr(WebUtil.getRequest().getHeader(TokenUtil.USER_TYPE_HEADER_KEY), TokenUtil.DEFAULT_USER_TYPE); String userType = Func.toStr(WebUtil.getRequest().getHeader(TokenUtil.USER_TYPE_HEADER_KEY), TokenUtil.DEFAULT_USER_TYPE);
@ -81,15 +81,22 @@ public class AuthController {
} }
@GetMapping("/captcha") @GetMapping("/captcha")
@ApiOperation(value = "获取验证码") @Operation(summary = "获取验证码")
public R<Kv> captcha() { public R<Kv> captcha() {
SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5); SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
String verCode = specCaptcha.text().toLowerCase(); String verCode = specCaptcha.text().toLowerCase();
String key = UUID.randomUUID().toString(); String key = UUID.randomUUID().toString();
// 存入redis并设置过期时间为30分钟 // 存入redis并设置过期时间为30分钟
redisUtil.set(CacheNames.CAPTCHA_KEY + key, verCode, 30L, TimeUnit.MINUTES); bladeRedis.setEx(CacheNames.CAPTCHA_KEY + key, verCode, 30L, TimeUnit.MINUTES);
// 将key和base64返回给前端 // 将key和base64返回给前端
return R.data(Kv.init().set("key", key).set("image", specCaptcha.toBase64())); return R.data(Kv.init().set("key", key).set("image", specCaptcha.toBase64()));
} }
@PostMapping("/logout")
@Operation(summary = "登出")
public R<Kv> logout() {
// 登出预留逻辑
return R.data(Kv.init().set("code", "200").set("msg", "操作成功"));
}
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,8 +15,8 @@
*/ */
package org.springblade.auth.controller; package org.springblade.auth.controller;
import io.swagger.annotations.Api; import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.annotations.ApiOperation; import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthCallback; import me.zhyd.oauth.model.AuthCallback;
@ -30,7 +30,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
/** /**
@ -42,7 +42,7 @@ import java.io.IOException;
@RestController @RestController
@AllArgsConstructor @AllArgsConstructor
@ConditionalOnProperty(value = "social.enabled", havingValue = "true") @ConditionalOnProperty(value = "social.enabled", havingValue = "true")
@Api(value = "第三方登陆", tags = "第三方登陆端点") @Tag(name = "第三方登陆", description = "第三方登陆端点")
public class SocialController { public class SocialController {
private final SocialProperties socialProperties; private final SocialProperties socialProperties;
@ -50,7 +50,7 @@ public class SocialController {
/** /**
* 授权完毕跳转 * 授权完毕跳转
*/ */
@ApiOperation(value = "授权完毕跳转") @Operation(summary = "授权完毕跳转")
@RequestMapping("/oauth/render/{source}") @RequestMapping("/oauth/render/{source}")
public void renderAuth(@PathVariable("source") String source, HttpServletResponse response) throws IOException { public void renderAuth(@PathVariable("source") String source, HttpServletResponse response) throws IOException {
AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties); AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
@ -61,7 +61,7 @@ public class SocialController {
/** /**
* 获取认证信息 * 获取认证信息
*/ */
@ApiOperation(value = "获取认证信息") @Operation(summary = "获取认证信息")
@RequestMapping("/oauth/callback/{source}") @RequestMapping("/oauth/callback/{source}")
public Object login(@PathVariable("source") String source, AuthCallback callback) { public Object login(@PathVariable("source") String source, AuthCallback callback) {
AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties); AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
@ -71,7 +71,7 @@ public class SocialController {
/** /**
* 撤销授权 * 撤销授权
*/ */
@ApiOperation(value = "撤销授权") @Operation(summary = "撤销授权")
@RequestMapping("/oauth/revoke/{source}/{token}") @RequestMapping("/oauth/revoke/{source}/{token}")
public Object revokeAuth(@PathVariable("source") String source, @PathVariable("token") String token) { public Object revokeAuth(@PathVariable("source") String source, @PathVariable("token") String token) {
AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties); AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
@ -81,7 +81,7 @@ public class SocialController {
/** /**
* 续期accessToken * 续期accessToken
*/ */
@ApiOperation(value = "续期令牌") @Operation(summary = "续期令牌")
@RequestMapping("/oauth/refresh/{source}") @RequestMapping("/oauth/refresh/{source}")
public Object refreshAuth(@PathVariable("source") String source, String token) { public Object refreshAuth(@PathVariable("source") String source, String token) {
AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties); AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,31 +16,40 @@
package org.springblade.auth.granter; package org.springblade.auth.granter;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.auth.enums.BladeUserEnum; import org.springblade.auth.enums.BladeUserEnum;
import org.springblade.auth.utils.TokenUtil; import org.springblade.auth.utils.TokenUtil;
import org.springblade.common.cache.CacheNames; import org.springblade.common.cache.CacheNames;
import org.springblade.core.log.exception.ServiceException; import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.secure.props.BladeAuthProperties;
import org.springblade.core.tool.api.R; import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.*; import org.springblade.core.tool.utils.*;
import org.springblade.system.user.entity.UserInfo; import org.springblade.system.user.entity.UserInfo;
import org.springblade.system.user.feign.IUserClient; import org.springblade.system.user.feign.IUserClient;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import java.time.Duration;
/** /**
* 验证码TokenGranter * 验证码TokenGranter
* *
* @author Chill * @author Chill
*/ */
@Slf4j
@Component @Component
@AllArgsConstructor @AllArgsConstructor
public class CaptchaTokenGranter implements ITokenGranter { public class CaptchaTokenGranter implements ITokenGranter {
public static final String GRANT_TYPE = "captcha"; public static final String GRANT_TYPE = "captcha";
public static final Integer FAIL_COUNT = 5;
private IUserClient userClient; private IUserClient userClient;
private RedisUtil redisUtil; private BladeRedis bladeRedis;
private BladeAuthProperties authProperties;
@Override @Override
public UserInfo grant(TokenParameter tokenParameter) { public UserInfo grant(TokenParameter tokenParameter) {
@ -49,7 +58,7 @@ public class CaptchaTokenGranter implements ITokenGranter {
String key = request.getHeader(TokenUtil.CAPTCHA_HEADER_KEY); String key = request.getHeader(TokenUtil.CAPTCHA_HEADER_KEY);
String code = request.getHeader(TokenUtil.CAPTCHA_HEADER_CODE); String code = request.getHeader(TokenUtil.CAPTCHA_HEADER_CODE);
// 获取验证码 // 获取验证码
String redisCode = String.valueOf(redisUtil.get(CacheNames.CAPTCHA_KEY + key)); String redisCode = Func.toStr(bladeRedis.getAndDel(CacheNames.CAPTCHA_KEY + key));
// 判断验证码 // 判断验证码
if (code == null || !StringUtil.equalsIgnoreCase(redisCode, code)) { if (code == null || !StringUtil.equalsIgnoreCase(redisCode, code)) {
throw new ServiceException(TokenUtil.CAPTCHA_NOT_CORRECT); throw new ServiceException(TokenUtil.CAPTCHA_NOT_CORRECT);
@ -58,21 +67,40 @@ public class CaptchaTokenGranter implements ITokenGranter {
String tenantId = tokenParameter.getArgs().getStr("tenantId"); String tenantId = tokenParameter.getArgs().getStr("tenantId");
String account = tokenParameter.getArgs().getStr("account"); String account = tokenParameter.getArgs().getStr("account");
String password = tokenParameter.getArgs().getStr("password"); String password = tokenParameter.getArgs().getStr("password");
// 判断登录是否锁定
int cnt = Func.toInt(bladeRedis.get(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, account)), 0);
if (cnt >= FAIL_COUNT) {
log.error("用户登录失败次数过多, 账号:{}, IP:{}", account, WebUtil.getIP());
throw new ServiceException(TokenUtil.USER_HAS_TOO_MANY_FAILS);
}
UserInfo userInfo = null; UserInfo userInfo = null;
if (Func.isNoneBlank(account, password)) { if (Func.isNoneBlank(account, password)) {
// 获取用户类型 // 获取用户类型
String userType = tokenParameter.getArgs().getStr("userType"); String userType = tokenParameter.getArgs().getStr("userType");
// 解密密码
String decryptPassword = TokenUtil.decryptPassword(password, authProperties.getPublicKey(), authProperties.getPrivateKey());
// 定义返回结果
R<UserInfo> result; R<UserInfo> result;
// 根据不同用户类型调用对应的接口返回数据用户可自行拓展 // 根据不同用户类型调用对应的接口返回数据用户可自行拓展
if (userType.equals(BladeUserEnum.WEB.getName())) { if (userType.equals(BladeUserEnum.WEB.getName())) {
result = userClient.userInfo(tenantId, account, DigestUtil.encrypt(password)); result = userClient.userInfo(tenantId, account, DigestUtil.encrypt(decryptPassword));
} else if (userType.equals(BladeUserEnum.APP.getName())) { } else if (userType.equals(BladeUserEnum.APP.getName())) {
result = userClient.userInfo(tenantId, account, DigestUtil.encrypt(password)); result = userClient.userInfo(tenantId, account, DigestUtil.encrypt(decryptPassword));
} else { } else {
result = userClient.userInfo(tenantId, account, DigestUtil.encrypt(password)); result = userClient.userInfo(tenantId, account, DigestUtil.encrypt(decryptPassword));
} }
userInfo = result.isSuccess() ? result.getData() : null; userInfo = result.isSuccess() ? result.getData() : null;
} }
if (userInfo == null || userInfo.getUser() == null) {
// 增加错误锁定次数
bladeRedis.setEx(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, account), cnt + 1, Duration.ofMinutes(30));
} else {
// 成功则清除登录缓存
bladeRedis.del(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, account));
}
return userInfo; return userInfo;
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,47 +16,80 @@
package org.springblade.auth.granter; package org.springblade.auth.granter;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.auth.enums.BladeUserEnum; import org.springblade.auth.enums.BladeUserEnum;
import org.springblade.auth.utils.TokenUtil;
import org.springblade.common.cache.CacheNames;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.secure.props.BladeAuthProperties;
import org.springblade.core.tool.api.R; import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.DigestUtil; import org.springblade.core.tool.utils.DigestUtil;
import org.springblade.core.tool.utils.Func; import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.WebUtil;
import org.springblade.system.user.entity.UserInfo; import org.springblade.system.user.entity.UserInfo;
import org.springblade.system.user.feign.IUserClient; import org.springblade.system.user.feign.IUserClient;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.Duration;
/** /**
* PasswordTokenGranter * PasswordTokenGranter
* *
* @author Chill * @author Chill
*/ */
@Slf4j
@Component @Component
@AllArgsConstructor @AllArgsConstructor
public class PasswordTokenGranter implements ITokenGranter { public class PasswordTokenGranter implements ITokenGranter {
public static final String GRANT_TYPE = "password"; public static final String GRANT_TYPE = "password";
public static final Integer FAIL_COUNT = 5;
private IUserClient userClient; private IUserClient userClient;
private BladeRedis bladeRedis;
private BladeAuthProperties authProperties;
@Override @Override
public UserInfo grant(TokenParameter tokenParameter) { public UserInfo grant(TokenParameter tokenParameter) {
String tenantId = tokenParameter.getArgs().getStr("tenantId"); String tenantId = tokenParameter.getArgs().getStr("tenantId");
String account = tokenParameter.getArgs().getStr("account"); String account = tokenParameter.getArgs().getStr("account");
String password = tokenParameter.getArgs().getStr("password"); String password = tokenParameter.getArgs().getStr("password");
// 判断登录是否锁定
int cnt = Func.toInt(bladeRedis.get(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, account)), 0);
if (cnt >= FAIL_COUNT) {
log.error("用户登录失败次数过多, 账号:{}, IP:{}", account, WebUtil.getIP());
throw new ServiceException(TokenUtil.USER_HAS_TOO_MANY_FAILS);
}
UserInfo userInfo = null; UserInfo userInfo = null;
if (Func.isNoneBlank(account, password)) { if (Func.isNoneBlank(account, password)) {
// 获取用户类型 // 获取用户类型
String userType = tokenParameter.getArgs().getStr("userType"); String userType = tokenParameter.getArgs().getStr("userType");
// 解密密码
String decryptPassword = TokenUtil.decryptPassword(password, authProperties.getPublicKey(), authProperties.getPrivateKey());
// 定义返回结果
R<UserInfo> result; R<UserInfo> result;
// 根据不同用户类型调用对应的接口返回数据用户可自行拓展 // 根据不同用户类型调用对应的接口返回数据用户可自行拓展
if (userType.equals(BladeUserEnum.WEB.getName())) { if (userType.equals(BladeUserEnum.WEB.getName())) {
result = userClient.userInfo(tenantId, account, DigestUtil.encrypt(password)); result = userClient.userInfo(tenantId, account, DigestUtil.encrypt(decryptPassword));
} else if (userType.equals(BladeUserEnum.APP.getName())) { } else if (userType.equals(BladeUserEnum.APP.getName())) {
result = userClient.userInfo(tenantId, account, DigestUtil.encrypt(password)); result = userClient.userInfo(tenantId, account, DigestUtil.encrypt(decryptPassword));
} else { } else {
result = userClient.userInfo(tenantId, account, DigestUtil.encrypt(password)); result = userClient.userInfo(tenantId, account, DigestUtil.encrypt(decryptPassword));
} }
userInfo = result.isSuccess() ? result.getData() : null; userInfo = result.isSuccess() ? result.getData() : null;
} }
if (userInfo == null || userInfo.getUser() == null) {
// 增加错误锁定次数
bladeRedis.setEx(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, account), cnt + 1, Duration.ofMinutes(30));
} else {
// 成功则清除登录缓存
bladeRedis.del(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, account));
}
return userInfo; return userInfo;
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -33,7 +33,7 @@ import org.springblade.system.user.entity.UserOauth;
import org.springblade.system.user.feign.IUserClient; import org.springblade.system.user.feign.IUserClient;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import java.util.Objects; import java.util.Objects;
/** /**
@ -79,7 +79,7 @@ public class SocialTokenGranter implements ITokenGranter {
} }
// 组装数据 // 组装数据
UserOauth userOauth = Objects.requireNonNull(BeanUtil.copy(authUser, UserOauth.class)); UserOauth userOauth = Objects.requireNonNull(BeanUtil.copyProperties(authUser, UserOauth.class));
userOauth.setSource(authUser.getSource()); userOauth.setSource(authUser.getSource());
userOauth.setTenantId(tenantId); userOauth.setTenantId(tenantId);
userOauth.setUuid(authUser.getUuid()); userOauth.setUuid(authUser.getUuid());

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,6 +20,9 @@ import org.springblade.core.secure.AuthInfo;
import org.springblade.core.secure.TokenInfo; import org.springblade.core.secure.TokenInfo;
import org.springblade.core.secure.utils.SecureUtil; import org.springblade.core.secure.utils.SecureUtil;
import org.springblade.core.tool.utils.Func; import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.SM2Util;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.system.user.entity.User; import org.springblade.system.user.entity.User;
import org.springblade.system.user.entity.UserInfo; import org.springblade.system.user.entity.UserInfo;
@ -43,7 +46,9 @@ public class TokenUtil {
public final static String USER_NOT_FOUND = "用户名或密码错误"; public final static String USER_NOT_FOUND = "用户名或密码错误";
public final static String HEADER_KEY = "Authorization"; public final static String HEADER_KEY = "Authorization";
public final static String HEADER_PREFIX = "Basic "; public final static String HEADER_PREFIX = "Basic ";
public final static String DEFAULT_AVATAR = "https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png"; public final static String ENCRYPT_PREFIX = "04";
public final static String USER_HAS_TOO_MANY_FAILS = "用户登录失败次数过多";
public final static String DEFAULT_AVATAR = "https://bladex.cn/images/logo.png";
/** /**
* 创建认证token * 创建认证token
@ -61,6 +66,7 @@ public class TokenUtil {
param.put(TokenConstant.OAUTH_ID, userInfo.getOauthId()); param.put(TokenConstant.OAUTH_ID, userInfo.getOauthId());
param.put(TokenConstant.USER_ID, Func.toStr(user.getId())); param.put(TokenConstant.USER_ID, Func.toStr(user.getId()));
param.put(TokenConstant.ROLE_ID, user.getRoleId()); param.put(TokenConstant.ROLE_ID, user.getRoleId());
param.put(TokenConstant.DEPT_ID, user.getDeptId());
param.put(TokenConstant.ACCOUNT, user.getAccount()); param.put(TokenConstant.ACCOUNT, user.getAccount());
param.put(TokenConstant.USER_NAME, user.getAccount()); param.put(TokenConstant.USER_NAME, user.getAccount());
param.put(TokenConstant.ROLE_NAME, Func.join(userInfo.getRoles())); param.put(TokenConstant.ROLE_NAME, Func.join(userInfo.getRoles()));
@ -96,4 +102,31 @@ public class TokenUtil {
return SecureUtil.createJWT(param, "audience", "issuser", TokenConstant.REFRESH_TOKEN); return SecureUtil.createJWT(param, "audience", "issuser", TokenConstant.REFRESH_TOKEN);
} }
/**
* 解析国密sm2加密密码
*
* @param rawPassword 请求时提交的原密码
* @param publicKey 公钥
* @param privateKey 私钥
* @return 解密后的密码
*/
public static String decryptPassword(String rawPassword, String publicKey, String privateKey) {
// 其中有空则匹配失败
if (StringUtil.isAnyBlank(publicKey, privateKey)) {
return StringPool.EMPTY;
}
// 处理部分工具类加密不带04前缀的情况
if (!StringUtil.startsWithIgnoreCase(rawPassword, ENCRYPT_PREFIX)) {
rawPassword = ENCRYPT_PREFIX + rawPassword;
}
// 解密密码
String decryptPassword = SM2Util.decrypt(rawPassword, privateKey);
// 签名校验
boolean isVerified = SM2Util.verify(decryptPassword, SM2Util.sign(decryptPassword, privateKey), publicKey);
if (!isVerified) {
return StringPool.EMPTY;
}
return decryptPassword;
}
} }

View File

@ -0,0 +1,24 @@
package org.springblade.test;
import org.springblade.core.tool.utils.AesUtil;
import org.springblade.core.tool.utils.RandomType;
import org.springblade.core.tool.utils.StringUtil;
/**
* signKey生成器
*
* @author Chill
*/
public class SignKeyGenerator {
public static void main(String[] args) {
System.out.println("=========== blade.token.sign-key 配置如下 ==============");
System.out.println("#blade配置\n" +
"blade:\n" +
" token:\n" +
" sign-key: " + StringUtil.random(32, RandomType.ALL) +"\n" +
" aes-key: " + AesUtil.genAesKey() );
System.out.println("=======================================================");
}
}

View File

@ -0,0 +1,46 @@
package org.springblade.test;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.util.encoders.Hex;
import org.springblade.core.tool.utils.SM2Util;
import org.springblade.core.tool.utils.StringPool;
/**
* signKey生成器
*
* @author Chill
*/
public class Sm2KeyGenerator {
public static void main(String[] args) {
System.out.println("================ blade.auth 配置如下 =================");
AsymmetricCipherKeyPair keyPair = SM2Util.generateKeyPair();
String publicKey = SM2Util.getPublicKeyString(keyPair);
String privateKey = SM2Util.getPrivateKeyString(keyPair);
System.out.println("#blade配置 \n" +
"blade:\n" +
" auth:\n" +
" public-key: " + publicKey + "\n" +
" private-key: " + privateKey);
System.out.println("=======================================================");
System.out.println(StringPool.EMPTY);
System.out.println("============== saber website.js 配置如下 ===============");
System.out.println("//saber配置\n" +
"auth: {\n" +
" publicKey: '" + publicKey + "',\n" +
"}");
System.out.println("=======================================================");
System.out.println(StringPool.EMPTY);
System.out.println("============== 密码:[admin] 加密流程如下 ================");
String password = "admin";
byte[] encryptedData = SM2Util.encrypt(password, publicKey);
String decryptedText = SM2Util.decrypt(encryptedData, privateKey);
System.out.println("加密前: " + password);
System.out.println("加密后: " + Hex.toHexString(encryptedData));
System.out.println("解密后: " + decryptedText);
System.out.println("请注意: 此密文为前端加密后调用token接口的密码参数");
System.out.println("=======================================================");
}
}

View File

@ -5,25 +5,26 @@
<parent> <parent>
<artifactId>SpringBlade</artifactId> <artifactId>SpringBlade</artifactId>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<version>3.0.3</version> <version>${revision}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>blade-common</artifactId> <artifactId>blade-common</artifactId>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<version>${blade.project.version}</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-launch</artifactId> <artifactId>blade-core-launch</artifactId>
<version>${blade.tool.version}</version> </dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-loadbalancer</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.dreamlu</groupId> <groupId>net.dreamlu</groupId>
<artifactId>mica-auto</artifactId> <artifactId>mica-auto</artifactId>
<version>${mica.auto.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -27,6 +27,26 @@ public interface CacheNames {
String DICT_VALUE = "dict:value"; String DICT_VALUE = "dict:value";
String DICT_LIST = "dict:list"; String DICT_LIST = "dict:list";
String CAPTCHA_KEY = "blade:auth::captcha:"; /**
* 验证码key
*/
String CAPTCHA_KEY = "blade:auth::blade:captcha:";
/**
* 登录失败key
*/
String USER_FAIL_KEY = "blade:user::blade:fail:";
/**
* 返回租户格式的key
*
* @param tenantId 租户编号
* @param cacheKey 缓存key
* @param cacheKeyValue 缓存key值
* @return tenantKey
*/
static String tenantKey(String tenantId, String cacheKey, String cacheKeyValue) {
return tenantId.concat(":").concat(cacheKey).concat(cacheKeyValue);
}
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,7 +24,7 @@ import org.springframework.context.annotation.Configuration;
* *
* @author Chill * @author Chill
*/ */
@Configuration @Configuration(proxyBeanMethods = false)
@AllArgsConstructor @AllArgsConstructor
public class BladeCommonConfiguration { public class BladeCommonConfiguration {

View File

@ -9,6 +9,16 @@ import org.springblade.core.launch.constant.AppConstant;
*/ */
public interface LauncherConstant { public interface LauncherConstant {
/**
* nacos 用户名
*/
String NACOS_USERNAME = "nacos";
/**
* nacos 密码
*/
String NACOS_PASSWORD = "nacos";
/** /**
* nacos namespace id * nacos namespace id
*/ */

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@ package org.springblade.common.launch;
import org.springblade.common.constant.LauncherConstant; import org.springblade.common.constant.LauncherConstant;
import org.springblade.core.launch.service.LauncherService; import org.springblade.core.launch.service.LauncherService;
import org.springblade.core.launch.utils.PropsUtil;
import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.builder.SpringApplicationBuilder;
import java.util.Properties; import java.util.Properties;
@ -31,10 +32,12 @@ public class LauncherServiceImpl implements LauncherService {
@Override @Override
public void launcher(SpringApplicationBuilder builder, String appName, String profile) { public void launcher(SpringApplicationBuilder builder, String appName, String profile) {
Properties props = System.getProperties(); Properties props = System.getProperties();
props.setProperty("spring.cloud.nacos.discovery.server-addr", LauncherConstant.nacosAddr(profile)); PropsUtil.setProperty(props, "spring.cloud.nacos.username", LauncherConstant.NACOS_USERNAME);
props.setProperty("spring.cloud.nacos.config.server-addr", LauncherConstant.nacosAddr(profile)); PropsUtil.setProperty(props, "spring.cloud.nacos.password", LauncherConstant.NACOS_PASSWORD);
props.setProperty("spring.cloud.sentinel.transport.dashboard", LauncherConstant.sentinelAddr(profile)); PropsUtil.setProperty(props, "spring.cloud.nacos.discovery.server-addr", LauncherConstant.nacosAddr(profile));
props.setProperty("spring.zipkin.base-url", LauncherConstant.zipkinAddr(profile)); PropsUtil.setProperty(props, "spring.cloud.nacos.config.server-addr", LauncherConstant.nacosAddr(profile));
PropsUtil.setProperty(props, "spring.cloud.sentinel.transport.dashboard", LauncherConstant.sentinelAddr(profile));
PropsUtil.setProperty(props, "spring.zipkin.base-url", LauncherConstant.zipkinAddr(profile));
} }
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -0,0 +1,42 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.common.tool;
import org.springframework.util.StringUtils;
import java.util.Properties;
/**
* 配置工具类
*
* @author Chill
*/
public class PropsUtil {
/**
* 设置配置值已存在则跳过
*
* @param props property
* @param key key
* @param value value
*/
public static void setProperty(Properties props, String key, String value) {
if (StringUtils.isEmpty(props.getProperty(key))) {
props.setProperty(key, value);
}
}
}

View File

@ -1,6 +1,6 @@
FROM anapsix/alpine-java:8_server-jre_unlimited FROM bladex/alpine-java:openjdk17_cn_slim
MAINTAINER smallchill@163.com MAINTAINER bladejava@qq.com
RUN mkdir -p /blade/gateway RUN mkdir -p /blade/gateway
@ -10,6 +10,6 @@ EXPOSE 80
ADD ./target/blade-gateway.jar ./app.jar ADD ./target/blade-gateway.jar ./app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"] ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
CMD ["--spring.profiles.active=test"] CMD ["--spring.profiles.active=test"]

View File

@ -5,13 +5,12 @@
<parent> <parent>
<artifactId>SpringBlade</artifactId> <artifactId>SpringBlade</artifactId>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<version>3.0.3</version> <version>${revision}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>blade-gateway</artifactId> <artifactId>blade-gateway</artifactId>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<version>${blade.project.version}</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
@ -19,7 +18,6 @@
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-launch</artifactId> <artifactId>blade-core-launch</artifactId>
<version>${blade.tool.version}</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -34,7 +32,6 @@
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-common</artifactId> <artifactId>blade-common</artifactId>
<version>${blade.project.version}</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
@ -54,7 +51,6 @@
<dependency> <dependency>
<groupId>de.codecentric</groupId> <groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId> <artifactId>spring-boot-admin-starter-client</artifactId>
<version>${spring.boot.admin.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
@ -68,46 +64,20 @@
<dependency> <dependency>
<groupId>com.alibaba.cloud</groupId> <groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>${alibaba.cloud.version}</version>
</dependency> </dependency>
<!-- Nacos --> <!-- 开启knife4j -->
<dependency> <dependency>
<groupId>com.alibaba.cloud</groupId> <groupId>com.github.xiaoymin</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <artifactId>knife4j-gateway-spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</exclusion>
</exclusions>
<version>${alibaba.cloud.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<exclusions>
<exclusion>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</exclusion>
</exclusions>
<version>${alibaba.cloud.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${alibaba.nacos.version}</version>
</dependency> </dependency>
<!-- JWT --> <!-- JWT -->
<dependency> <dependency>
<groupId>io.jsonwebtoken</groupId> <groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId> <artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.jsonwebtoken</groupId> <groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <artifactId>jjwt-jackson</artifactId>
<version>0.11.2</version>
</dependency> </dependency>
</dependencies> </dependencies>
@ -136,22 +106,6 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId> <artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<!--suppress UnresolvedMavenProperty -->
<copy overwrite="true"
tofile="${session.executionRootDirectory}/target/${artifactId}.jar"
file="${project.build.directory}/${artifactId}.jar" />
</tasks>
</configuration>
</execution>
</executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,14 +19,12 @@ import org.springblade.core.launch.BladeApplication;
import org.springblade.core.launch.constant.AppConstant; import org.springblade.core.launch.constant.AppConstant;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.scheduling.annotation.EnableScheduling;
/** /**
* 项目启动 * 项目启动
* *
* @author Chill * @author Chill
*/ */
@EnableScheduling
@EnableDiscoveryClient @EnableDiscoveryClient
@SpringBootApplication @SpringBootApplication
public class GateWayApplication { public class GateWayApplication {

View File

@ -0,0 +1,44 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.gateway.config;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.gateway.props.JwtProperties;
import org.springblade.gateway.utils.JwtUtil;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* JWT配置信息
*
* @author Chill
*/
@Slf4j
@Configuration(proxyBeanMethods = false)
@AllArgsConstructor
@EnableConfigurationProperties({JwtProperties.class})
public class JwtConfiguration implements SmartInitializingSingleton {
private final JwtProperties properties;
@Override
public void afterSingletonsInstantiated() {
JwtUtil.setJwtProperties(properties);
}
}

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,20 +18,13 @@ package org.springblade.gateway.config;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springblade.gateway.filter.GatewayFilter;
import org.springblade.gateway.props.AuthProperties; import org.springblade.gateway.props.AuthProperties;
import org.springblade.gateway.props.RequestProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; 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.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/** /**
* 路由配置信息 * 路由配置信息
@ -39,43 +32,17 @@ import reactor.core.publisher.Mono;
* @author Chill * @author Chill
*/ */
@Slf4j @Slf4j
@Configuration @Configuration(proxyBeanMethods = false)
@AllArgsConstructor @AllArgsConstructor
@EnableConfigurationProperties({AuthProperties.class}) @EnableConfigurationProperties({AuthProperties.class, RequestProperties.class})
public class RouterFunctionConfiguration { public class RouterFunctionConfiguration {
/** /**
* 这里为支持的请求头如果有自定义的header字段请自己添加 * 全局配置
*/
private static final String ALLOWED_HEADERS = "X-Requested-With, Tenant-Id, Blade-Auth, Content-Type, Authorization, credential, X-XSRF-TOKEN, token, username, client, knfie4j-gateway-request, request-origion";
private static final String ALLOWED_METHODS = "GET,POST,PUT,DELETE,OPTIONS,HEAD";
private static final String ALLOWED_ORIGIN = "*";
private static final String ALLOWED_EXPOSE = "*";
private static final String MAX_AGE = "18000L";
/**
* 跨域配置
*/ */
@Bean @Bean
public WebFilter corsFilter() { public WebFilter gatewayFilter(RequestProperties requestProperties) {
return (ServerWebExchange ctx, WebFilterChain chain) -> { return new GatewayFilter(requestProperties);
ServerHttpRequest request = ctx.getRequest();
if (CorsUtils.isCorsRequest(request)) {
ServerHttpResponse response = ctx.getResponse();
HttpHeaders headers = response.getHeaders();
headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
headers.add("Access-Control-Max-Age", MAX_AGE);
headers.add("Access-Control-Allow-Credentials", "true");
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
return chain.filter(ctx);
};
} }
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,9 +21,11 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Claims;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springblade.core.launch.props.BladeProperties;
import org.springblade.gateway.props.AuthProperties; import org.springblade.gateway.props.AuthProperties;
import org.springblade.gateway.provider.AuthProvider; import org.springblade.gateway.provider.AuthProvider;
import org.springblade.gateway.provider.ResponseProvider; import org.springblade.gateway.provider.ResponseProvider;
import org.springblade.gateway.utils.JwtCrypto;
import org.springblade.gateway.utils.JwtUtil; import org.springblade.gateway.utils.JwtUtil;
import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.cloud.gateway.filter.GlobalFilter;
@ -39,6 +41,8 @@ import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import static org.springblade.gateway.utils.JwtCrypto.BLADE_CRYPTO_AES_KEY;
/** /**
* 鉴权认证 * 鉴权认证
* *
@ -50,6 +54,7 @@ import java.nio.charset.StandardCharsets;
public class AuthFilter implements GlobalFilter, Ordered { public class AuthFilter implements GlobalFilter, Ordered {
private final AuthProperties authProperties; private final AuthProperties authProperties;
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final BladeProperties bladeProperties;
private final AntPathMatcher antPathMatcher = new AntPathMatcher(); private final AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override @Override
@ -61,11 +66,15 @@ public class AuthFilter implements GlobalFilter, Ordered {
ServerHttpResponse resp = exchange.getResponse(); ServerHttpResponse resp = exchange.getResponse();
String headerToken = exchange.getRequest().getHeaders().getFirst(AuthProvider.AUTH_KEY); String headerToken = exchange.getRequest().getHeaders().getFirst(AuthProvider.AUTH_KEY);
String paramToken = exchange.getRequest().getQueryParams().getFirst(AuthProvider.AUTH_KEY); String paramToken = exchange.getRequest().getQueryParams().getFirst(AuthProvider.AUTH_KEY);
if (StringUtils.isAllBlank(headerToken, paramToken)) { if (StringUtils.isBlank(headerToken) && StringUtils.isBlank(paramToken)) {
return unAuth(resp, "缺失令牌,鉴权失败"); return unAuth(resp, "缺失令牌,鉴权失败");
} }
String auth = StringUtils.isBlank(headerToken) ? paramToken : headerToken; String auth = StringUtils.isBlank(headerToken) ? paramToken : headerToken;
String token = JwtUtil.getToken(auth); String token = JwtUtil.getToken(auth);
//校验 加密Token 合法性
if (JwtUtil.isCrypto(auth)) {
token = JwtCrypto.decryptToString(token, bladeProperties.getEnvironment().getProperty(BLADE_CRYPTO_AES_KEY));
}
Claims claims = JwtUtil.parseJWT(token); Claims claims = JwtUtil.parseJWT(token);
if (claims == null) { if (claims == null) {
return unAuth(resp, "请求未授权"); return unAuth(resp, "请求未授权");

View File

@ -0,0 +1,161 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.gateway.filter;
import lombok.RequiredArgsConstructor;
import org.springblade.gateway.props.RequestProperties;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.lang.NonNull;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PatternMatchUtils;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Objects;
/**
* 全局拦截器
*
* @author Chill
*/
@RequiredArgsConstructor
public class GatewayFilter implements WebFilter, Ordered {
/**
* 请求配置
*/
private final RequestProperties requestProperties;
/**
* 路径匹配
*/
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
/**
* 默认拦截地址
*/
private final List<String> defaultBlockUrl = List.of("/**/actuator/**", "/health/**");
/**
* 默认白名单
*/
private final List<String> defaultWhiteList = List.of("127.0.0.1", "172.30.*.*", "192.168.*.*", "10.*.*.*", "0:0:0:0:0:0:0:1");
/**
* 默认提示信息
*/
private final static String DEFAULT_MESSAGE = "当前请求被拒绝,请联系管理员!";
/**
* 这里为支持的请求头如果有自定义的header字段请自己添加
*/
private static final String ALLOWED_HEADERS = "X-Requested-With, Tenant-Id, Blade-Auth, Content-Type, Authorization, credential, X-XSRF-TOKEN, token, username, client, knfie4j-gateway-request, knife4j-gateway-code, request-origion";
private static final String ALLOWED_METHODS = "GET,POST,PUT,DELETE,OPTIONS,HEAD";
private static final String ALLOWED_ORIGIN = "*";
private static final String ALLOWED_EXPOSE = "*";
private static final String MAX_AGE = "18000L";
@NonNull
@Override
public Mono<Void> filter(@NonNull ServerWebExchange exchange, @NonNull WebFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
// 处理跨域请求
if (CorsUtils.isCorsRequest(request)) {
ServerHttpResponse response = exchange.getResponse();
HttpHeaders headers = response.getHeaders();
headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
headers.add("Access-Control-Max-Age", MAX_AGE);
headers.add("Access-Control-Allow-Credentials", "true");
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
// 处理黑白名单与拦截请求
if (requestProperties.getEnabled()) {
String path = request.getPath().value();
String ip = Objects.requireNonNull(request.getRemoteAddress()).getHostString();
if (isRequestBlock(path, ip)) {
throw new RuntimeException(DEFAULT_MESSAGE);
}
}
return chain.filter(exchange);
}
/**
* 是否白名单
*
* @param ip ip地址
* @return boolean
*/
private boolean isWhiteList(String ip) {
List<String> whiteList = requestProperties.getWhiteList();
String[] defaultWhiteIps = defaultWhiteList.toArray(new String[0]);
String[] whiteIps = whiteList.toArray(new String[0]);
return PatternMatchUtils.simpleMatch(defaultWhiteIps, ip) || PatternMatchUtils.simpleMatch(whiteIps, ip);
}
/**
* 是否黑名单
*
* @param ip ip地址
* @return boolean
*/
private boolean isBlackList(String ip) {
List<String> blackList = requestProperties.getBlackList();
String[] blackIps = blackList.toArray(new String[0]);
return PatternMatchUtils.simpleMatch(blackIps, ip);
}
/**
* 是否禁用请求访问
*
* @param path 请求路径
* @return boolean
*/
private boolean isRequestBlock(String path) {
List<String> blockUrl = requestProperties.getBlockUrl();
return defaultBlockUrl.stream().anyMatch(pattern -> antPathMatcher.match(pattern, path)) ||
blockUrl.stream().anyMatch(pattern -> antPathMatcher.match(pattern, path));
}
/**
* 是否拦截请求
*
* @param path 请求路径
* @param ip ip地址
* @return boolean
*/
private boolean isRequestBlock(String path, String ip) {
return (isRequestBlock(path) && !isWhiteList(ip)) || isBlackList(ip);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,64 +24,63 @@ import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.lang.NonNull;
import org.springframework.web.server.ResponseStatusException; import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.util.Map;
/** /**
* 异常处理 * 异常处理
* *
* @author Chill * @author Chill
*/ */
@Order(-1) @Order(-1)
@Configuration @Configuration(proxyBeanMethods = false)
@RequiredArgsConstructor @RequiredArgsConstructor
public class ErrorExceptionHandler implements ErrorWebExceptionHandler { public class ErrorExceptionHandler implements ErrorWebExceptionHandler {
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
@NonNull
@Override @Override
public Mono<Void> handle(ServerWebExchange exchange, @NonNull Throwable ex) { public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
ServerHttpRequest request = exchange.getRequest(); ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse(); ServerHttpResponse response = exchange.getResponse();
if (response.isCommitted()) { if (response.isCommitted()) {
return Mono.error(ex); return Mono.error(ex);
} }
response.getHeaders().setContentType(MediaType.APPLICATION_JSON); response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
if (ex instanceof ResponseStatusException) { if (ex instanceof ResponseStatusException) {
response.setStatusCode(((ResponseStatusException) ex).getStatus()); response.setStatusCode(((ResponseStatusException) ex).getStatusCode());
} }
return response.writeWith(Mono.fromSupplier(() -> { return response.writeWith(Mono.fromSupplier(() -> {
DataBufferFactory bufferFactory = response.bufferFactory(); DataBufferFactory bufferFactory = response.bufferFactory();
try { try {
HttpStatus status = HttpStatus.BAD_GATEWAY; int status = 500;
if (ex instanceof ResponseStatusException) { if (response.getStatusCode() != null) {
status = ((ResponseStatusException) ex).getStatus(); status = response.getStatusCode().value();
} }
return bufferFactory.wrap(objectMapper.writeValueAsBytes(ResponseProvider.response(status.value(), buildMessage(request, ex)))); Map<String, Object> result = ResponseProvider.response(status, this.buildMessage(request, ex));
return bufferFactory.wrap(objectMapper.writeValueAsBytes(result));
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
e.printStackTrace();
return bufferFactory.wrap(new byte[0]); return bufferFactory.wrap(new byte[0]);
} }
})); }));
} }
/** /**
* 构建异常信息 * 构建异常信息
*/ */
private String buildMessage(ServerHttpRequest request, Throwable ex) { private String buildMessage(ServerHttpRequest request, Throwable ex) {
String uri = request.getURI().toString();
if (uri.endsWith("doc.html")) {
return "[Swagger聚合网关] 已迁移至 [blade-swagger] 服务,请开启 [blade-swagger] 服务并访问 [http://127.0.0.1:18000/doc.html]";
}
StringBuilder message = new StringBuilder("Failed to handle request ["); StringBuilder message = new StringBuilder("Failed to handle request [");
message.append(request.getMethodValue()); message.append(request.getMethod().name());
message.append(" "); message.append(" ");
message.append(request.getURI()); message.append(request.getURI());
message.append("]"); message.append("]");
@ -92,4 +91,5 @@ public class ErrorExceptionHandler implements ErrorWebExceptionHandler {
return message.toString(); return message.toString();
} }
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -0,0 +1,57 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.gateway.props;
import io.jsonwebtoken.JwtException;
import lombok.Data;
import org.springblade.core.launch.constant.TokenConstant;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* JWT配置
*
* @author Chill
*/
@Data
@ConfigurationProperties("blade.token")
public class JwtProperties {
/**
* token是否有状态
*/
private Boolean state = Boolean.FALSE;
/**
* 是否只可同时在线一人
*/
private Boolean single = Boolean.FALSE;
/**
* token签名
*/
private String signKey = "";
/**
* 获取签名规则
*/
public String getSignKey() {
if (this.signKey.length() < TokenConstant.SIGN_KEY_LENGTH) {
throw new JwtException("请配置 blade.token.sign-key 的值, 长度32位以上");
}
return this.signKey;
}
}

View File

@ -0,0 +1,58 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.gateway.props;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.ArrayList;
import java.util.List;
/**
* Request配置类
*
* @author Chill
*/
@Data
@ConfigurationProperties("blade.request")
public class RequestProperties {
/**
* 开启自定义request
*/
private Boolean enabled = true;
/**
* 放行url
*/
private List<String> skipUrl = new ArrayList<>();
/**
* 禁用url
*/
private List<String> blockUrl = new ArrayList<>();
/**
* 白名单支持通配符例如10.20.0.8*10.20.0.*
*/
private List<String> whiteList = new ArrayList<>();
/**
* 黑名单支持通配符例如10.20.0.8*10.20.0.*
*/
private List<String> blackList = new ArrayList<>();
}

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -35,7 +35,7 @@ public class AuthProvider {
DEFAULT_SKIP_URL.add("/token/**"); DEFAULT_SKIP_URL.add("/token/**");
DEFAULT_SKIP_URL.add("/captcha/**"); DEFAULT_SKIP_URL.add("/captcha/**");
DEFAULT_SKIP_URL.add("/actuator/health/**"); DEFAULT_SKIP_URL.add("/actuator/health/**");
DEFAULT_SKIP_URL.add("/v2/api-docs/**"); DEFAULT_SKIP_URL.add("/v3/api-docs/**");
DEFAULT_SKIP_URL.add("/auth/**"); DEFAULT_SKIP_URL.add("/auth/**");
DEFAULT_SKIP_URL.add("/oauth/**"); DEFAULT_SKIP_URL.add("/oauth/**");
DEFAULT_SKIP_URL.add("/log/**"); DEFAULT_SKIP_URL.add("/log/**");

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -0,0 +1,202 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.gateway.utils;
import lombok.SneakyThrows;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import reactor.util.annotation.Nullable;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.Objects;
/**
* JwtCrypto
*
* @author Chill
*/
public class JwtCrypto {
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
public static final String BLADE_CRYPTO_AES_KEY = "blade.token.aes-key";
/**
* Base64加密
*
* @param content 文本内容
* @param aesTextKey 文本密钥
* @return {String}
*/
public static String encryptToString(String content, String aesTextKey) {
return Base64.getEncoder().encodeToString(encrypt(content, aesTextKey));
}
/**
* Base64加密
*
* @param content 内容
* @param aesTextKey 文本密钥
* @return {String}
*/
public static String encryptToString(byte[] content, String aesTextKey) {
return Base64.getEncoder().encodeToString(encrypt(content, aesTextKey));
}
/**
* 加密
*
* @param content 文本内容
* @param aesTextKey 文本密钥
* @return byte[]
*/
public static byte[] encrypt(String content, String aesTextKey) {
return encrypt(content.getBytes(DEFAULT_CHARSET), aesTextKey);
}
/**
* 加密
*
* @param content 文本内容
* @param charset 编码
* @param aesTextKey 文本密钥
* @return byte[]
*/
public static byte[] encrypt(String content, Charset charset, String aesTextKey) {
return encrypt(content.getBytes(charset), aesTextKey);
}
/**
* 加密
*
* @param content 内容
* @param aesTextKey 文本密钥
* @return byte[]
*/
public static byte[] encrypt(byte[] content, String aesTextKey) {
return encrypt(content, Objects.requireNonNull(aesTextKey).getBytes(DEFAULT_CHARSET));
}
/**
* Base64解密
*
* @param content 文本内容
* @param aesTextKey 文本密钥
* @return {String}
*/
@Nullable
public static String decryptToString(@Nullable String content, @Nullable String aesTextKey) {
if (!StringUtils.hasText(content) || !StringUtils.hasText(aesTextKey)) {
return null;
}
byte[] hexBytes = decrypt(Base64.getDecoder().decode(content.getBytes(DEFAULT_CHARSET)), aesTextKey);
return new String(hexBytes, DEFAULT_CHARSET);
}
/**
* 解密
*
* @param content 内容
* @param aesTextKey 文本密钥
* @return byte[]
*/
public static byte[] decrypt(byte[] content, String aesTextKey) {
return decrypt(content, Objects.requireNonNull(aesTextKey).getBytes(DEFAULT_CHARSET));
}
/**
* 解密
*
* @param content 内容
* @param aesKey 密钥
* @return byte[]
*/
public static byte[] encrypt(byte[] content, byte[] aesKey) {
return aes(Pkcs7Encoder.encode(content), aesKey, Cipher.ENCRYPT_MODE);
}
/**
* 加密
*
* @param encrypted 内容
* @param aesKey 密钥
* @return byte[]
*/
public static byte[] decrypt(byte[] encrypted, byte[] aesKey) {
return Pkcs7Encoder.decode(aes(encrypted, aesKey, Cipher.DECRYPT_MODE));
}
/**
* ase加密
*
* @param encrypted 内容
* @param aesKey 密钥
* @param mode 模式
* @return byte[]
*/
@SneakyThrows
private static byte[] aes(byte[] encrypted, byte[] aesKey, int mode) {
Assert.isTrue(aesKey.length == 32, "IllegalAesKey, aesKey's length must be 32");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
cipher.init(mode, keySpec, iv);
return cipher.doFinal(encrypted);
}
/**
* 提供基于PKCS7算法的加解密接口.
*/
private static class Pkcs7Encoder {
private static final int BLOCK_SIZE = 32;
private static byte[] encode(byte[] src) {
int count = src.length;
// 计算需要填充的位数
int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
// 获得补位所用的字符
byte pad = (byte) (amountToPad & 0xFF);
byte[] pads = new byte[amountToPad];
for (int index = 0; index < amountToPad; index++) {
pads[index] = pad;
}
int length = count + amountToPad;
byte[] dest = new byte[length];
System.arraycopy(src, 0, dest, 0, count);
System.arraycopy(pads, 0, dest, count, amountToPad);
return dest;
}
private static byte[] decode(byte[] decrypted) {
int pad = decrypted[decrypted.length - 1];
if (pad < 1 || pad > BLOCK_SIZE) {
pad = 0;
}
if (pad > 0) {
return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
}
return decrypted;
}
}
}

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,7 +17,9 @@ package org.springblade.gateway.utils;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Jwts;
import lombok.Getter;
import org.springblade.core.launch.constant.TokenConstant; import org.springblade.core.launch.constant.TokenConstant;
import org.springblade.gateway.props.JwtProperties;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Base64; import java.util.Base64;
@ -29,29 +31,70 @@ import java.util.Base64;
*/ */
public class JwtUtil { public class JwtUtil {
public static String SIGN_KEY = TokenConstant.SIGN_KEY;
public static String BEARER = TokenConstant.BEARER; public static String BEARER = TokenConstant.BEARER;
public static String CRYPTO = TokenConstant.CRYPTO;
public static Integer AUTH_LENGTH = 7; public static Integer AUTH_LENGTH = 7;
public static String BASE64_SECURITY = Base64.getEncoder().encodeToString(SIGN_KEY.getBytes(StandardCharsets.UTF_8)); /**
* jwt配置
*/
@Getter
private static JwtProperties jwtProperties;
public static void setJwtProperties(JwtProperties properties) {
if (JwtUtil.jwtProperties == null) {
JwtUtil.jwtProperties = properties;
}
}
/** /**
* 获取token串 * 签名加密
*/
public static String getBase64Security() {
return Base64.getEncoder().encodeToString(getJwtProperties().getSignKey().getBytes(StandardCharsets.UTF_8));
}
/**
* 获取请求传递的token串
* *
* @param auth token * @param auth token
* @return String * @return String
*/ */
public static String getToken(String auth) { public static String getToken(String auth) {
if ((auth != null) && (auth.length() > AUTH_LENGTH)) { if (isBearer(auth) || isCrypto(auth)) {
String headStr = auth.substring(0, 6).toLowerCase(); return auth.substring(AUTH_LENGTH);
if (headStr.compareTo(BEARER) == 0) {
auth = auth.substring(7);
}
return auth;
} }
return null; return null;
} }
/**
* 判断token类型为bearer
*
* @param auth token
* @return String
*/
public static Boolean isBearer(String auth) {
if ((auth != null) && (auth.length() > AUTH_LENGTH)) {
String headStr = auth.substring(0, 6).toLowerCase();
return headStr.compareTo(BEARER) == 0;
}
return false;
}
/**
* 判断token类型为crypto
*
* @param auth token
* @return String
*/
public static Boolean isCrypto(String auth) {
if ((auth != null) && (auth.length() > AUTH_LENGTH)) {
String headStr = auth.substring(0, 6).toLowerCase();
return headStr.compareTo(CRYPTO) == 0;
}
return false;
}
/** /**
* 解析jsonWebToken * 解析jsonWebToken
* *
@ -61,7 +104,7 @@ public class JwtUtil {
public static Claims parseJWT(String jsonWebToken) { public static Claims parseJWT(String jsonWebToken) {
try { try {
return Jwts.parserBuilder() return Jwts.parserBuilder()
.setSigningKey(Base64.getDecoder().decode(JwtUtil.BASE64_SECURITY)).build() .setSigningKey(Base64.getDecoder().decode(getBase64Security())).build()
.parseClaimsJws(jsonWebToken).getBody(); .parseClaimsJws(jsonWebToken).getBody();
} catch (Exception ex) { } catch (Exception ex) {
return null; return null;

View File

@ -0,0 +1,11 @@
blade:
#多团队协作服务配置
loadbalancer:
#开启配置
enabled: true
#灰度版本
#version: 3.0.0
#负载均衡优先调用的ip段
prior-ip-pattern:
- 192.168.0.*
- 127.0.0.1

View File

@ -0,0 +1,16 @@
knife4j:
gateway:
enabled: true
tags-sorter: order
operations-sorter: order
# 指定服务发现的模式聚合微服务文档,并且是默认`default`分组
strategy: discover
discover:
enabled: true
# 指定版本号(Swagger2|OpenAPI3)
version : openapi3
# 需要排除的微服务(eg:网关服务)
excluded-services:
- blade-admin
- blade-gateway
- blade-log

View File

@ -1,6 +1,6 @@
FROM anapsix/alpine-java:8_server-jre_unlimited FROM bladex/alpine-java:openjdk17_cn_slim
MAINTAINER smallchill@163.com MAINTAINER bladejava@qq.com
RUN mkdir -p /blade/admin RUN mkdir -p /blade/admin
@ -10,6 +10,6 @@ EXPOSE 7002
ADD ./target/blade-admin.jar ./app.jar ADD ./target/blade-admin.jar ./app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"] ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
CMD ["--spring.profiles.active=test"] CMD ["--spring.profiles.active=test"]

View File

@ -5,13 +5,12 @@
<parent> <parent>
<artifactId>blade-ops</artifactId> <artifactId>blade-ops</artifactId>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<version>3.0.3</version> <version>${revision}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>blade-admin</artifactId> <artifactId>blade-admin</artifactId>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<version>${blade.project.version}</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
@ -19,22 +18,18 @@
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-common</artifactId> <artifactId>blade-common</artifactId>
<version>${blade.project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-launch</artifactId> <artifactId>blade-core-launch</artifactId>
<version>${blade.tool.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-tool</artifactId> <artifactId>blade-core-tool</artifactId>
<version>${blade.tool.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-cloud</artifactId> <artifactId>blade-core-cloud</artifactId>
<version>${blade.tool.version}</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
@ -46,7 +41,6 @@
<dependency> <dependency>
<groupId>de.codecentric</groupId> <groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId> <artifactId>spring-boot-admin-starter-server</artifactId>
<version>${spring.boot.admin.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
@ -75,22 +69,6 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId> <artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<!--suppress UnresolvedMavenProperty -->
<copy overwrite="true"
tofile="${session.executionRootDirectory}/target/${artifactId}.jar"
file="${project.build.directory}/${artifactId}.jar" />
</tasks>
</configuration>
</execution>
</executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
FROM anapsix/alpine-java:8_server-jre_unlimited FROM bladex/alpine-java:openjdk17_cn_slim
MAINTAINER smallchill@163.com MAINTAINER bladejava@qq.com
RUN mkdir -p /blade/develop RUN mkdir -p /blade/develop
@ -10,6 +10,6 @@ EXPOSE 7007
ADD ./target/blade-develop.jar ./app.jar ADD ./target/blade-develop.jar ./app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"] ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
CMD ["--spring.profiles.active=test"] CMD ["--spring.profiles.active=test"]

View File

@ -6,14 +6,13 @@
<parent> <parent>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-ops</artifactId> <artifactId>blade-ops</artifactId>
<version>3.0.3</version> <version>${revision}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>blade-develop</artifactId> <artifactId>blade-develop</artifactId>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<version>${blade.project.version}</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
@ -21,39 +20,18 @@
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-boot</artifactId> <artifactId>blade-core-boot</artifactId>
<version>${blade.tool.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-common</artifactId> <artifactId>blade-common</artifactId>
<version>${blade.project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-develop</artifactId> <artifactId>blade-starter-develop</artifactId>
<version>${blade.tool.version}</version>
</dependency>
<!--Swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>${swagger.models.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-dict-api</artifactId> <artifactId>blade-dict-api</artifactId>
<version>${blade.project.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
@ -82,22 +60,6 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId> <artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<!--suppress UnresolvedMavenProperty -->
<copy overwrite="true"
tofile="${session.executionRootDirectory}/target/${artifactId}.jar"
file="${project.build.directory}/${artifactId}.jar" />
</tasks>
</configuration>
</execution>
</executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,7 +17,14 @@ package org.springblade.develop.controller;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.*; import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController; import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.mp.support.Condition; import org.springblade.core.mp.support.Condition;
@ -32,9 +39,7 @@ import org.springblade.develop.service.ICodeService;
import org.springblade.develop.service.IDatasourceService; import org.springblade.develop.service.IDatasourceService;
import org.springblade.develop.support.BladeCodeGenerator; import org.springblade.develop.support.BladeCodeGenerator;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
import javax.validation.Valid;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
@ -43,11 +48,11 @@ import java.util.Map;
* *
* @author Chill * @author Chill
*/ */
@ApiIgnore @Hidden
@RestController @RestController
@AllArgsConstructor @AllArgsConstructor
@RequestMapping("/code") @RequestMapping("/code")
@Api(value = "代码生成", tags = "代码生成") @Tag(name = "代码生成", description = "代码生成")
@PreAuth(RoleConstant.HAS_ROLE_ADMIN) @PreAuth(RoleConstant.HAS_ROLE_ADMIN)
public class CodeController extends BladeController { public class CodeController extends BladeController {
@ -59,7 +64,7 @@ public class CodeController extends BladeController {
*/ */
@GetMapping("/detail") @GetMapping("/detail")
@ApiOperationSupport(order = 1) @ApiOperationSupport(order = 1)
@ApiOperation(value = "详情", notes = "传入code") @Operation(summary = "详情", description = "传入code")
public R<Code> detail(Code code) { public R<Code> detail(Code code) {
Code detail = codeService.getOne(Condition.getQueryWrapper(code)); Code detail = codeService.getOne(Condition.getQueryWrapper(code));
return R.data(detail); return R.data(detail);
@ -69,14 +74,14 @@ public class CodeController extends BladeController {
* 分页 * 分页
*/ */
@GetMapping("/list") @GetMapping("/list")
@ApiImplicitParams({ @Parameters({
@ApiImplicitParam(name = "codeName", value = "模块名", paramType = "query", dataType = "string"), @Parameter(name = "codeName", description = "模块名", in = ParameterIn.QUERY, schema = @Schema(type = "string")),
@ApiImplicitParam(name = "tableName", value = "表名", paramType = "query", dataType = "string"), @Parameter(name = "tableName", description = "表名", in = ParameterIn.QUERY, schema = @Schema(type = "string")),
@ApiImplicitParam(name = "modelName", value = "实体名", paramType = "query", dataType = "string") @Parameter(name = "modelName", description = "实体名", in = ParameterIn.QUERY, schema = @Schema(type = "string"))
}) })
@ApiOperationSupport(order = 2) @ApiOperationSupport(order = 2)
@ApiOperation(value = "分页", notes = "传入code") @Operation(summary = "分页", description = "传入code")
public R<IPage<Code>> list(@ApiIgnore @RequestParam Map<String, Object> code, Query query) { public R<IPage<Code>> list(@Parameter(hidden = true) @RequestParam Map<String, Object> code, Query query) {
IPage<Code> pages = codeService.page(Condition.getPage(query), Condition.getQueryWrapper(code, Code.class)); IPage<Code> pages = codeService.page(Condition.getPage(query), Condition.getQueryWrapper(code, Code.class));
return R.data(pages); return R.data(pages);
} }
@ -86,7 +91,7 @@ public class CodeController extends BladeController {
*/ */
@PostMapping("/submit") @PostMapping("/submit")
@ApiOperationSupport(order = 3) @ApiOperationSupport(order = 3)
@ApiOperation(value = "新增或修改", notes = "传入code") @Operation(summary = "新增或修改", description = "传入code")
public R submit(@Valid @RequestBody Code code) { public R submit(@Valid @RequestBody Code code) {
return R.status(codeService.submit(code)); return R.status(codeService.submit(code));
} }
@ -97,8 +102,8 @@ public class CodeController extends BladeController {
*/ */
@PostMapping("/remove") @PostMapping("/remove")
@ApiOperationSupport(order = 4) @ApiOperationSupport(order = 4)
@ApiOperation(value = "删除", notes = "传入ids") @Operation(summary = "删除", description = "传入ids")
public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) { public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(codeService.removeByIds(Func.toLongList(ids))); return R.status(codeService.removeByIds(Func.toLongList(ids)));
} }
@ -107,8 +112,8 @@ public class CodeController extends BladeController {
*/ */
@PostMapping("/copy") @PostMapping("/copy")
@ApiOperationSupport(order = 5) @ApiOperationSupport(order = 5)
@ApiOperation(value = "复制", notes = "传入id") @Operation(summary = "复制", description = "传入id")
public R copy(@ApiParam(value = "主键", required = true) @RequestParam Long id) { public R copy(@Parameter(description = "主键", required = true) @RequestParam Long id) {
Code code = codeService.getById(id); Code code = codeService.getById(id);
code.setId(null); code.setId(null);
code.setCodeName(code.getCodeName() + "-copy"); code.setCodeName(code.getCodeName() + "-copy");
@ -120,8 +125,8 @@ public class CodeController extends BladeController {
*/ */
@PostMapping("/gen-code") @PostMapping("/gen-code")
@ApiOperationSupport(order = 6) @ApiOperationSupport(order = 6)
@ApiOperation(value = "代码生成", notes = "传入ids") @Operation(summary = "代码生成", description = "传入ids")
public R genCode(@ApiParam(value = "主键集合", required = true) @RequestParam String ids, @RequestParam(defaultValue = "sword") String system) { public R genCode(@Parameter(description = "主键集合", required = true) @RequestParam String ids, @RequestParam(defaultValue = "saber3") String system) {
Collection<Code> codes = codeService.listByIds(Func.toLongList(ids)); Collection<Code> codes = codeService.listByIds(Func.toLongList(ids));
codes.forEach(code -> { codes.forEach(code -> {
BladeCodeGenerator generator = new BladeCodeGenerator(); BladeCodeGenerator generator = new BladeCodeGenerator();

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,9 +17,9 @@ package org.springblade.develop.controller;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api; import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.annotations.ApiOperation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.annotations.ApiParam; import io.swagger.v3.oas.annotations.Parameter;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController; import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.mp.support.Condition; import org.springblade.core.mp.support.Condition;
@ -30,7 +30,7 @@ import org.springblade.develop.entity.Datasource;
import org.springblade.develop.service.IDatasourceService; import org.springblade.develop.service.IDatasourceService;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import jakarta.validation.Valid;
import java.util.List; import java.util.List;
/** /**
@ -41,7 +41,7 @@ import java.util.List;
@RestController @RestController
@AllArgsConstructor @AllArgsConstructor
@RequestMapping("/datasource") @RequestMapping("/datasource")
@Api(value = "数据源配置表", tags = "数据源配置表接口") @Tag(name = "数据源配置表", description = "数据源配置表接口")
public class DatasourceController extends BladeController { public class DatasourceController extends BladeController {
private IDatasourceService datasourceService; private IDatasourceService datasourceService;
@ -51,7 +51,7 @@ public class DatasourceController extends BladeController {
*/ */
@GetMapping("/detail") @GetMapping("/detail")
@ApiOperationSupport(order = 1) @ApiOperationSupport(order = 1)
@ApiOperation(value = "详情", notes = "传入datasource") @Operation(summary = "详情", description = "传入datasource")
public R<Datasource> detail(Datasource datasource) { public R<Datasource> detail(Datasource datasource) {
Datasource detail = datasourceService.getOne(Condition.getQueryWrapper(datasource)); Datasource detail = datasourceService.getOne(Condition.getQueryWrapper(datasource));
return R.data(detail); return R.data(detail);
@ -62,7 +62,7 @@ public class DatasourceController extends BladeController {
*/ */
@GetMapping("/list") @GetMapping("/list")
@ApiOperationSupport(order = 2) @ApiOperationSupport(order = 2)
@ApiOperation(value = "分页", notes = "传入datasource") @Operation(summary = "分页", description = "传入datasource")
public R<IPage<Datasource>> list(Datasource datasource, Query query) { public R<IPage<Datasource>> list(Datasource datasource, Query query) {
IPage<Datasource> pages = datasourceService.page(Condition.getPage(query), Condition.getQueryWrapper(datasource)); IPage<Datasource> pages = datasourceService.page(Condition.getPage(query), Condition.getQueryWrapper(datasource));
return R.data(pages); return R.data(pages);
@ -73,7 +73,7 @@ public class DatasourceController extends BladeController {
*/ */
@PostMapping("/save") @PostMapping("/save")
@ApiOperationSupport(order = 4) @ApiOperationSupport(order = 4)
@ApiOperation(value = "新增", notes = "传入datasource") @Operation(summary = "新增", description = "传入datasource")
public R save(@Valid @RequestBody Datasource datasource) { public R save(@Valid @RequestBody Datasource datasource) {
return R.status(datasourceService.save(datasource)); return R.status(datasourceService.save(datasource));
} }
@ -83,7 +83,7 @@ public class DatasourceController extends BladeController {
*/ */
@PostMapping("/update") @PostMapping("/update")
@ApiOperationSupport(order = 5) @ApiOperationSupport(order = 5)
@ApiOperation(value = "修改", notes = "传入datasource") @Operation(summary = "修改", description = "传入datasource")
public R update(@Valid @RequestBody Datasource datasource) { public R update(@Valid @RequestBody Datasource datasource) {
return R.status(datasourceService.updateById(datasource)); return R.status(datasourceService.updateById(datasource));
} }
@ -93,7 +93,7 @@ public class DatasourceController extends BladeController {
*/ */
@PostMapping("/submit") @PostMapping("/submit")
@ApiOperationSupport(order = 6) @ApiOperationSupport(order = 6)
@ApiOperation(value = "新增或修改", notes = "传入datasource") @Operation(summary = "新增或修改", description = "传入datasource")
public R submit(@Valid @RequestBody Datasource datasource) { public R submit(@Valid @RequestBody Datasource datasource) {
datasource.setUrl(datasource.getUrl().replace("&amp;", "&")); datasource.setUrl(datasource.getUrl().replace("&amp;", "&"));
return R.status(datasourceService.saveOrUpdate(datasource)); return R.status(datasourceService.saveOrUpdate(datasource));
@ -105,8 +105,8 @@ public class DatasourceController extends BladeController {
*/ */
@PostMapping("/remove") @PostMapping("/remove")
@ApiOperationSupport(order = 7) @ApiOperationSupport(order = 7)
@ApiOperation(value = "逻辑删除", notes = "传入ids") @Operation(summary = "逻辑删除", description = "传入ids")
public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) { public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(datasourceService.deleteLogic(Func.toLongList(ids))); return R.status(datasourceService.deleteLogic(Func.toLongList(ids)));
} }
@ -115,7 +115,7 @@ public class DatasourceController extends BladeController {
*/ */
@GetMapping("/select") @GetMapping("/select")
@ApiOperationSupport(order = 8) @ApiOperationSupport(order = 8)
@ApiOperation(value = "下拉数据源", notes = "查询列表") @Operation(summary = "下拉数据源", description = "查询列表")
public R<List<Datasource>> select() { public R<List<Datasource>> select() {
List<Datasource> list = datasourceService.list(); List<Datasource> list = datasourceService.list();
return R.data(list); return R.data(list);

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,10 +21,10 @@ import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel; import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
/** /**
@ -34,15 +34,16 @@ import java.io.Serializable;
*/ */
@Data @Data
@TableName("blade_code") @TableName("blade_code")
@ApiModel(value = "Code对象", description = "Code对象") @Schema(description = "Code对象")
public class Code implements Serializable { public class Code implements Serializable {
@Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 主键 * 主键
*/ */
@ApiModelProperty(value = "主键") @Schema(description = "主键")
@TableId(value = "id", type = IdType.ASSIGN_ID) @TableId(value = "id", type = IdType.ASSIGN_ID)
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long id; private Long id;
@ -50,75 +51,75 @@ public class Code implements Serializable {
/** /**
* 数据源主键 * 数据源主键
*/ */
@ApiModelProperty(value = "数据源主键") @Schema(description = "数据源主键")
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long datasourceId; private Long datasourceId;
/** /**
* 模块名称 * 模块名称
*/ */
@ApiModelProperty(value = "服务名称") @Schema(description = "服务名称")
private String serviceName; private String serviceName;
/** /**
* 模块名称 * 模块名称
*/ */
@ApiModelProperty(value = "模块名称") @Schema(description = "模块名称")
private String codeName; private String codeName;
/** /**
* 表名 * 表名
*/ */
@ApiModelProperty(value = "表名") @Schema(description = "表名")
private String tableName; private String tableName;
/** /**
* 实体名 * 实体名
*/ */
@ApiModelProperty(value = "表前缀") @Schema(description = "表前缀")
private String tablePrefix; private String tablePrefix;
/** /**
* 主键名 * 主键名
*/ */
@ApiModelProperty(value = "主键名") @Schema(description = "主键名")
private String pkName; private String pkName;
/** /**
* 基础业务模式 * 基础业务模式
*/ */
@ApiModelProperty(value = "基础业务模式") @Schema(description = "基础业务模式")
private Integer baseMode; private Integer baseMode;
/** /**
* 包装器模式 * 包装器模式
*/ */
@ApiModelProperty(value = "包装器模式") @Schema(description = "包装器模式")
private Integer wrapMode; private Integer wrapMode;
/** /**
* 后端包名 * 后端包名
*/ */
@ApiModelProperty(value = "后端包名") @Schema(description = "后端包名")
private String packageName; private String packageName;
/** /**
* 后端路径 * 后端路径
*/ */
@ApiModelProperty(value = "后端路径") @Schema(description = "后端路径")
private String apiPath; private String apiPath;
/** /**
* 前端路径 * 前端路径
*/ */
@ApiModelProperty(value = "前端路径") @Schema(description = "前端路径")
private String webPath; private String webPath;
/** /**
* 是否已删除 * 是否已删除
*/ */
@TableLogic @TableLogic
@ApiModelProperty(value = "是否已删除") @Schema(description = "是否已删除")
private Integer isDeleted; private Integer isDeleted;

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,12 +20,13 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel; import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity; import org.springblade.core.mp.base.BaseEntity;
import java.io.Serial;
/** /**
* 数据源配置表实体类 * 数据源配置表实体类
* *
@ -34,15 +35,16 @@ import org.springblade.core.mp.base.BaseEntity;
@Data @Data
@TableName("blade_datasource") @TableName("blade_datasource")
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ApiModel(value = "Datasource对象", description = "数据源配置表") @Schema(description = "Datasource对象")
public class Datasource extends BaseEntity { public class Datasource extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 主键 * 主键
*/ */
@ApiModelProperty(value = "主键") @Schema(description = "主键")
@TableId(value = "id", type = IdType.ASSIGN_ID) @TableId(value = "id", type = IdType.ASSIGN_ID)
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long id; private Long id;
@ -50,32 +52,32 @@ public class Datasource extends BaseEntity {
/** /**
* 名称 * 名称
*/ */
@ApiModelProperty(value = "名称") @Schema(description = "名称")
private String name; private String name;
/** /**
* 驱动类 * 驱动类
*/ */
@ApiModelProperty(value = "驱动类") @Schema(description = "驱动类")
private String driverClass; private String driverClass;
/** /**
* 连接地址 * 连接地址
*/ */
@ApiModelProperty(value = "连接地址") @Schema(description = "连接地址")
private String url; private String url;
/** /**
* 用户名 * 用户名
*/ */
@ApiModelProperty(value = "用户名") @Schema(description = "用户名")
private String username; private String username;
/** /**
* 密码 * 密码
*/ */
@ApiModelProperty(value = "密码") @Schema(description = "密码")
private String password; private String password;
/** /**
* 备注 * 备注
*/ */
@ApiModelProperty(value = "备注") @Schema(description = "备注")
private String remark; private String remark;

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,11 +1,11 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* <p> * <p>
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.gnu.org/licenses/lgpl.html
* <p> * <p>
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@ -15,12 +15,12 @@
*/ */
package $!{package.Controller}; package $!{package.Controller};
import io.swagger.annotations.Api; import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.annotations.ApiOperation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import javax.validation.Valid; import jakarta.validation.Valid;
import org.springblade.core.mp.support.Condition; import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query; import org.springblade.core.mp.support.Query;
@ -35,14 +35,15 @@ import $!{package.Entity}.$!{entity};
#set($voPackage=$package.Entity.replace("entity","vo")) #set($voPackage=$package.Entity.replace("entity","vo"))
import $!{voPackage}.$!{entity}VO; import $!{voPackage}.$!{entity}VO;
#set($wrapperPackage=$package.Entity.replace("entity","wrapper")) #set($wrapperPackage=$package.Entity.replace("entity","wrapper"))
#if($!{hasWrapper})
import $!{wrapperPackage}.$!{entity}Wrapper; import $!{wrapperPackage}.$!{entity}Wrapper;
#end
import $!{package.Service}.$!{table.serviceName}; import $!{package.Service}.$!{table.serviceName};
#if($!{superControllerClassPackage}) #if($!{superControllerClassPackage})
import $!{superControllerClassPackage}; import $!{superControllerClassPackage};
#end #end
#if(!$!{superEntityClass}) #if(!$!{superEntityClass})
#end #end
import java.util.List;
/** /**
* $!{table.comment} 控制器 * $!{table.comment} 控制器
@ -52,8 +53,8 @@ import java.util.List;
*/ */
@RestController @RestController
@AllArgsConstructor @AllArgsConstructor
@RequestMapping("#if($!{package.ModuleName})/$!{package.ModuleName}#end/$!{cfg.entityKey}") @RequestMapping("#if($!{package.ModuleName})$!{package.ModuleName}#end/$!{entityKey}")
@Api(value = "$!{table.comment}", tags = "$!{table.comment}接口") @Tag(name = "$!{table.comment}", description = "$!{table.comment}接口")
#if($!{superControllerClass}) #if($!{superControllerClass})
public class $!{table.controllerName} extends $!{superControllerClass} { public class $!{table.controllerName} extends $!{superControllerClass} {
#else #else
@ -62,12 +63,13 @@ public class $!{table.controllerName} {
private $!{table.serviceName} $!{table.entityPath}Service; private $!{table.serviceName} $!{table.entityPath}Service;
#if($!{hasWrapper})
/** /**
* 详情 * 详情
*/ */
@GetMapping("/detail") @GetMapping("/detail")
@ApiOperationSupport(order = 1) @ApiOperationSupport(order = 1)
@ApiOperation(value = "详情", notes = "传入$!{table.entityPath}") @Operation(summary = "详情", description = "传入$!{table.entityPath}")
public R<$!{entity}VO> detail($!{entity} $!{table.entityPath}) { public R<$!{entity}VO> detail($!{entity} $!{table.entityPath}) {
$!{entity} detail = $!{table.entityPath}Service.getOne(Condition.getQueryWrapper($!{table.entityPath})); $!{entity} detail = $!{table.entityPath}Service.getOne(Condition.getQueryWrapper($!{table.entityPath}));
return R.data($!{entity}Wrapper.build().entityVO(detail)); return R.data($!{entity}Wrapper.build().entityVO(detail));
@ -78,18 +80,42 @@ public class $!{table.controllerName} {
*/ */
@GetMapping("/list") @GetMapping("/list")
@ApiOperationSupport(order = 2) @ApiOperationSupport(order = 2)
@ApiOperation(value = "分页", notes = "传入$!{table.entityPath}") @Operation(summary = "分页", description = "传入$!{table.entityPath}")
public R<IPage<$!{entity}VO>> list($!{entity} $!{table.entityPath}, Query query) { public R<IPage<$!{entity}VO>> list($!{entity} $!{table.entityPath}, Query query) {
IPage<$!{entity}> pages = $!{table.entityPath}Service.page(Condition.getPage(query), Condition.getQueryWrapper($!{table.entityPath})); IPage<$!{entity}> pages = $!{table.entityPath}Service.page(Condition.getPage(query), Condition.getQueryWrapper($!{table.entityPath}));
return R.data($!{entity}Wrapper.build().pageVO(pages)); return R.data($!{entity}Wrapper.build().pageVO(pages));
} }
#else
/**
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入$!{table.entityPath}")
public R<$!{entity}> detail($!{entity} $!{table.entityPath}) {
$!{entity} detail = $!{table.entityPath}Service.getOne(Condition.getQueryWrapper($!{table.entityPath}));
return R.data(detail);
}
/**
* 分页 $!{table.comment}
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@Operation(summary = "分页", description = "传入$!{table.entityPath}")
public R<IPage<$!{entity}>> list($!{entity} $!{table.entityPath}, Query query) {
IPage<$!{entity}> pages = $!{table.entityPath}Service.page(Condition.getPage(query), Condition.getQueryWrapper($!{table.entityPath}));
return R.data(pages);
}
#end
/** /**
* 自定义分页 $!{table.comment} * 自定义分页 $!{table.comment}
*/ */
@GetMapping("/page") @GetMapping("/page")
@ApiOperationSupport(order = 3) @ApiOperationSupport(order = 3)
@ApiOperation(value = "分页", notes = "传入$!{table.entityPath}") @Operation(summary = "分页", description = "传入$!{table.entityPath}")
public R<IPage<$!{entity}VO>> page($!{entity}VO $!{table.entityPath}, Query query) { public R<IPage<$!{entity}VO>> page($!{entity}VO $!{table.entityPath}, Query query) {
IPage<$!{entity}VO> pages = $!{table.entityPath}Service.select$!{entity}Page(Condition.getPage(query), $!{table.entityPath}); IPage<$!{entity}VO> pages = $!{table.entityPath}Service.select$!{entity}Page(Condition.getPage(query), $!{table.entityPath});
return R.data(pages); return R.data(pages);
@ -100,7 +126,7 @@ public class $!{table.controllerName} {
*/ */
@PostMapping("/save") @PostMapping("/save")
@ApiOperationSupport(order = 4) @ApiOperationSupport(order = 4)
@ApiOperation(value = "新增", notes = "传入$!{table.entityPath}") @Operation(summary = "新增", description = "传入$!{table.entityPath}")
public R save(@Valid @RequestBody $!{entity} $!{table.entityPath}) { public R save(@Valid @RequestBody $!{entity} $!{table.entityPath}) {
return R.status($!{table.entityPath}Service.save($!{table.entityPath})); return R.status($!{table.entityPath}Service.save($!{table.entityPath}));
} }
@ -110,7 +136,7 @@ public class $!{table.controllerName} {
*/ */
@PostMapping("/update") @PostMapping("/update")
@ApiOperationSupport(order = 5) @ApiOperationSupport(order = 5)
@ApiOperation(value = "修改", notes = "传入$!{table.entityPath}") @Operation(summary = "修改", description = "传入$!{table.entityPath}")
public R update(@Valid @RequestBody $!{entity} $!{table.entityPath}) { public R update(@Valid @RequestBody $!{entity} $!{table.entityPath}) {
return R.status($!{table.entityPath}Service.updateById($!{table.entityPath})); return R.status($!{table.entityPath}Service.updateById($!{table.entityPath}));
} }
@ -120,7 +146,7 @@ public class $!{table.controllerName} {
*/ */
@PostMapping("/submit") @PostMapping("/submit")
@ApiOperationSupport(order = 6) @ApiOperationSupport(order = 6)
@ApiOperation(value = "新增或修改", notes = "传入$!{table.entityPath}") @Operation(summary = "新增或修改", description = "传入$!{table.entityPath}")
public R submit(@Valid @RequestBody $!{entity} $!{table.entityPath}) { public R submit(@Valid @RequestBody $!{entity} $!{table.entityPath}) {
return R.status($!{table.entityPath}Service.saveOrUpdate($!{table.entityPath})); return R.status($!{table.entityPath}Service.saveOrUpdate($!{table.entityPath}));
} }
@ -132,8 +158,8 @@ public class $!{table.controllerName} {
*/ */
@PostMapping("/remove") @PostMapping("/remove")
@ApiOperationSupport(order = 7) @ApiOperationSupport(order = 7)
@ApiOperation(value = "逻辑删除", notes = "传入ids") @Operation(summary = "逻辑删除", description = "传入ids")
public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) { public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status($!{table.entityPath}Service.deleteLogic(Func.toLongList(ids))); return R.status($!{table.entityPath}Service.deleteLogic(Func.toLongList(ids)));
} }
@ -143,9 +169,9 @@ public class $!{table.controllerName} {
* 删除 $!{table.comment} * 删除 $!{table.comment}
*/ */
@PostMapping("/remove") @PostMapping("/remove")
@ApiOperationSupport(order = 7) @ApiOperationSupport(order = 8)
@ApiOperation(value = "删除", notes = "传入ids") @Operation(summary = "删除", description = "传入ids")
public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) { public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status($!{table.entityPath}Service.removeByIds(Func.toLongList(ids))); return R.status($!{table.entityPath}Service.removeByIds(Func.toLongList(ids)));
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -37,7 +37,7 @@ public class $!{entity}Wrapper extends BaseEntityWrapper<$!{entity}, $!{entity}V
@Override @Override
public $!{entity}VO entityVO($!{entity} $!{table.entityPath}) { public $!{entity}VO entityVO($!{entity} $!{table.entityPath}) {
$!{entity}VO $!{table.entityPath}VO = BeanUtil.copy($!{table.entityPath}, $!{entity}VO.class); $!{entity}VO $!{table.entityPath}VO = BeanUtil.copyProperties($!{table.entityPath}, $!{entity}VO.class);
return $!{table.entityPath}VO; return $!{table.entityPath}VO;
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,11 +1,11 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* <p> * <p>
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.gnu.org/licenses/lgpl.html
* <p> * <p>
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@ -15,12 +15,12 @@
*/ */
package $!{package.Controller}; package $!{package.Controller};
import io.swagger.annotations.Api; import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.annotations.ApiOperation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import javax.validation.Valid; import jakarta.validation.Valid;
import org.springblade.core.mp.support.Condition; import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query; import org.springblade.core.mp.support.Query;
@ -35,14 +35,15 @@ import $!{package.Entity}.$!{entity};
#set($voPackage=$package.Entity.replace("entity","vo")) #set($voPackage=$package.Entity.replace("entity","vo"))
import $!{voPackage}.$!{entity}VO; import $!{voPackage}.$!{entity}VO;
#set($wrapperPackage=$package.Entity.replace("entity","wrapper")) #set($wrapperPackage=$package.Entity.replace("entity","wrapper"))
#if($!{hasWrapper})
import $!{wrapperPackage}.$!{entity}Wrapper; import $!{wrapperPackage}.$!{entity}Wrapper;
#end
import $!{package.Service}.$!{table.serviceName}; import $!{package.Service}.$!{table.serviceName};
#if($!{superControllerClassPackage}) #if($!{superControllerClassPackage})
import $!{superControllerClassPackage}; import $!{superControllerClassPackage};
#end #end
#if(!$!{superEntityClass}) #if(!$!{superEntityClass})
#end #end
import java.util.List;
/** /**
* $!{table.comment} 控制器 * $!{table.comment} 控制器
@ -52,8 +53,8 @@ import java.util.List;
*/ */
@RestController @RestController
@AllArgsConstructor @AllArgsConstructor
@RequestMapping("#if($!{package.ModuleName})/$!{package.ModuleName}#end/$!{cfg.entityKey}") @RequestMapping("#if($!{package.ModuleName})$!{package.ModuleName}#end/$!{entityKey}")
@Api(value = "$!{table.comment}", tags = "$!{table.comment}接口") @Tag(name = "$!{table.comment}", description = "$!{table.comment}接口")
#if($!{superControllerClass}) #if($!{superControllerClass})
public class $!{table.controllerName} extends $!{superControllerClass} { public class $!{table.controllerName} extends $!{superControllerClass} {
#else #else
@ -62,12 +63,13 @@ public class $!{table.controllerName} {
private $!{table.serviceName} $!{table.entityPath}Service; private $!{table.serviceName} $!{table.entityPath}Service;
#if($!{hasWrapper})
/** /**
* 详情 * 详情
*/ */
@GetMapping("/detail") @GetMapping("/detail")
@ApiOperationSupport(order = 1) @ApiOperationSupport(order = 1)
@ApiOperation(value = "详情", notes = "传入$!{table.entityPath}") @Operation(summary = "详情", description = "传入$!{table.entityPath}")
public R<$!{entity}VO> detail($!{entity} $!{table.entityPath}) { public R<$!{entity}VO> detail($!{entity} $!{table.entityPath}) {
$!{entity} detail = $!{table.entityPath}Service.getOne(Condition.getQueryWrapper($!{table.entityPath})); $!{entity} detail = $!{table.entityPath}Service.getOne(Condition.getQueryWrapper($!{table.entityPath}));
return R.data($!{entity}Wrapper.build().entityVO(detail)); return R.data($!{entity}Wrapper.build().entityVO(detail));
@ -78,18 +80,42 @@ public class $!{table.controllerName} {
*/ */
@GetMapping("/list") @GetMapping("/list")
@ApiOperationSupport(order = 2) @ApiOperationSupport(order = 2)
@ApiOperation(value = "分页", notes = "传入$!{table.entityPath}") @Operation(summary = "分页", description = "传入$!{table.entityPath}")
public R<IPage<$!{entity}VO>> list($!{entity} $!{table.entityPath}, Query query) { public R<IPage<$!{entity}VO>> list($!{entity} $!{table.entityPath}, Query query) {
IPage<$!{entity}> pages = $!{table.entityPath}Service.page(Condition.getPage(query), Condition.getQueryWrapper($!{table.entityPath})); IPage<$!{entity}> pages = $!{table.entityPath}Service.page(Condition.getPage(query), Condition.getQueryWrapper($!{table.entityPath}));
return R.data($!{entity}Wrapper.build().pageVO(pages)); return R.data($!{entity}Wrapper.build().pageVO(pages));
} }
#else
/**
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入$!{table.entityPath}")
public R<$!{entity}> detail($!{entity} $!{table.entityPath}) {
$!{entity} detail = $!{table.entityPath}Service.getOne(Condition.getQueryWrapper($!{table.entityPath}));
return R.data(detail);
}
/**
* 分页 $!{table.comment}
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@Operation(summary = "分页", description = "传入$!{table.entityPath}")
public R<IPage<$!{entity}>> list($!{entity} $!{table.entityPath}, Query query) {
IPage<$!{entity}> pages = $!{table.entityPath}Service.page(Condition.getPage(query), Condition.getQueryWrapper($!{table.entityPath}));
return R.data(pages);
}
#end
/** /**
* 自定义分页 $!{table.comment} * 自定义分页 $!{table.comment}
*/ */
@GetMapping("/page") @GetMapping("/page")
@ApiOperationSupport(order = 3) @ApiOperationSupport(order = 3)
@ApiOperation(value = "分页", notes = "传入$!{table.entityPath}") @Operation(summary = "分页", description = "传入$!{table.entityPath}")
public R<IPage<$!{entity}VO>> page($!{entity}VO $!{table.entityPath}, Query query) { public R<IPage<$!{entity}VO>> page($!{entity}VO $!{table.entityPath}, Query query) {
IPage<$!{entity}VO> pages = $!{table.entityPath}Service.select$!{entity}Page(Condition.getPage(query), $!{table.entityPath}); IPage<$!{entity}VO> pages = $!{table.entityPath}Service.select$!{entity}Page(Condition.getPage(query), $!{table.entityPath});
return R.data(pages); return R.data(pages);
@ -100,7 +126,7 @@ public class $!{table.controllerName} {
*/ */
@PostMapping("/save") @PostMapping("/save")
@ApiOperationSupport(order = 4) @ApiOperationSupport(order = 4)
@ApiOperation(value = "新增", notes = "传入$!{table.entityPath}") @Operation(summary = "新增", description = "传入$!{table.entityPath}")
public R save(@Valid @RequestBody $!{entity} $!{table.entityPath}) { public R save(@Valid @RequestBody $!{entity} $!{table.entityPath}) {
return R.status($!{table.entityPath}Service.save($!{table.entityPath})); return R.status($!{table.entityPath}Service.save($!{table.entityPath}));
} }
@ -110,7 +136,7 @@ public class $!{table.controllerName} {
*/ */
@PostMapping("/update") @PostMapping("/update")
@ApiOperationSupport(order = 5) @ApiOperationSupport(order = 5)
@ApiOperation(value = "修改", notes = "传入$!{table.entityPath}") @Operation(summary = "修改", description = "传入$!{table.entityPath}")
public R update(@Valid @RequestBody $!{entity} $!{table.entityPath}) { public R update(@Valid @RequestBody $!{entity} $!{table.entityPath}) {
return R.status($!{table.entityPath}Service.updateById($!{table.entityPath})); return R.status($!{table.entityPath}Service.updateById($!{table.entityPath}));
} }
@ -120,7 +146,7 @@ public class $!{table.controllerName} {
*/ */
@PostMapping("/submit") @PostMapping("/submit")
@ApiOperationSupport(order = 6) @ApiOperationSupport(order = 6)
@ApiOperation(value = "新增或修改", notes = "传入$!{table.entityPath}") @Operation(summary = "新增或修改", description = "传入$!{table.entityPath}")
public R submit(@Valid @RequestBody $!{entity} $!{table.entityPath}) { public R submit(@Valid @RequestBody $!{entity} $!{table.entityPath}) {
return R.status($!{table.entityPath}Service.saveOrUpdate($!{table.entityPath})); return R.status($!{table.entityPath}Service.saveOrUpdate($!{table.entityPath}));
} }
@ -132,8 +158,8 @@ public class $!{table.controllerName} {
*/ */
@PostMapping("/remove") @PostMapping("/remove")
@ApiOperationSupport(order = 7) @ApiOperationSupport(order = 7)
@ApiOperation(value = "逻辑删除", notes = "传入ids") @Operation(summary = "逻辑删除", description = "传入ids")
public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) { public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status($!{table.entityPath}Service.deleteLogic(Func.toLongList(ids))); return R.status($!{table.entityPath}Service.deleteLogic(Func.toLongList(ids)));
} }
@ -143,9 +169,9 @@ public class $!{table.controllerName} {
* 删除 $!{table.comment} * 删除 $!{table.comment}
*/ */
@PostMapping("/remove") @PostMapping("/remove")
@ApiOperationSupport(order = 7) @ApiOperationSupport(order = 8)
@ApiOperation(value = "删除", notes = "传入ids") @Operation(summary = "删除", description = "传入ids")
public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) { public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status($!{table.entityPath}Service.removeByIds(Func.toLongList(ids))); return R.status($!{table.entityPath}Service.removeByIds(Func.toLongList(ids)));
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -37,7 +37,7 @@ public class $!{entity}Wrapper extends BaseEntityWrapper<$!{entity}, $!{entity}V
@Override @Override
public $!{entity}VO entityVO($!{entity} $!{table.entityPath}) { public $!{entity}VO entityVO($!{entity} $!{table.entityPath}) {
$!{entity}VO $!{table.entityPath}VO = BeanUtil.copy($!{table.entityPath}, $!{entity}VO.class); $!{entity}VO $!{table.entityPath}VO = BeanUtil.copyProperties($!{table.entityPath}, $!{entity}VO.class);
return $!{table.entityPath}VO; return $!{table.entityPath}VO;
} }

View File

@ -1,6 +1,6 @@
FROM anapsix/alpine-java:8_server-jre_unlimited FROM bladex/alpine-java:openjdk17_cn_slim
MAINTAINER smallchill@163.com MAINTAINER bladejava@qq.com
RUN mkdir -p /blade/report RUN mkdir -p /blade/report
@ -10,6 +10,6 @@ EXPOSE 8108
ADD ./target/blade-report.jar ./app.jar ADD ./target/blade-report.jar ./app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"] ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
CMD ["--spring.profiles.active=test"] CMD ["--spring.profiles.active=test"]

View File

@ -5,14 +5,13 @@
<parent> <parent>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-ops</artifactId> <artifactId>blade-ops</artifactId>
<version>3.0.3</version> <version>${revision}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>blade-report</artifactId> <artifactId>blade-report</artifactId>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<version>${blade.project.version}</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
@ -20,17 +19,14 @@
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-boot</artifactId> <artifactId>blade-core-boot</artifactId>
<version>${blade.tool.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-report</artifactId> <artifactId>blade-starter-report</artifactId>
<version>${blade.tool.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-common</artifactId> <artifactId>blade-common</artifactId>
<version>${blade.project.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
@ -59,22 +55,6 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId> <artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<!--suppress UnresolvedMavenProperty -->
<copy overwrite="true"
tofile="${session.executionRootDirectory}/target/${artifactId}.jar"
file="${project.build.directory}/${artifactId}.jar" />
</tasks>
</configuration>
</execution>
</executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -27,7 +27,7 @@ import javax.sql.DataSource;
* *
* @author Chill * @author Chill
*/ */
@Configuration @Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "report.enabled", havingValue = "true", matchIfMissing = true) @ConditionalOnProperty(value = "report.enabled", havingValue = "true", matchIfMissing = true)
public class BladeReportConfiguration { public class BladeReportConfiguration {

View File

@ -1,6 +1,6 @@
FROM anapsix/alpine-java:8_server-jre_unlimited FROM bladex/alpine-java:openjdk17_cn_slim
MAINTAINER smallchill@163.com MAINTAINER bladejava@qq.com
RUN mkdir -p /blade/resource RUN mkdir -p /blade/resource
@ -10,6 +10,6 @@ EXPOSE 8010
ADD ./target/blade-resource.jar ./app.jar ADD ./target/blade-resource.jar ./app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"] ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
CMD ["--spring.profiles.active=test"] CMD ["--spring.profiles.active=test"]

View File

@ -5,30 +5,26 @@
<parent> <parent>
<artifactId>blade-ops</artifactId> <artifactId>blade-ops</artifactId>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<version>3.0.3</version> <version>${revision}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>blade-resource</artifactId> <artifactId>blade-resource</artifactId>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<version>${blade.project.version}</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-common</artifactId> <artifactId>blade-common</artifactId>
<version>${blade.project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-tool</artifactId> <artifactId>blade-core-tool</artifactId>
<version>${blade.tool.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-cloud</artifactId> <artifactId>blade-core-cloud</artifactId>
<version>${blade.tool.version}</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
@ -38,8 +34,11 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-oss</artifactId> <artifactId>blade-starter-oss</artifactId>
<version>${blade.tool.version}</version> </dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-swagger</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>
@ -68,22 +67,6 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId> <artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<!--suppress UnresolvedMavenProperty -->
<copy overwrite="true"
tofile="${session.executionRootDirectory}/target/${artifactId}.jar"
file="${project.build.directory}/${artifactId}.jar" />
</tasks>
</configuration>
</execution>
</executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,7 +15,7 @@
*/ */
package org.springblade.resource.endpoint; package org.springblade.resource.endpoint;
import io.swagger.annotations.Api; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.springblade.core.oss.QiniuTemplate; import org.springblade.core.oss.QiniuTemplate;
@ -34,7 +34,7 @@ import org.springframework.web.multipart.MultipartFile;
@RestController @RestController
@AllArgsConstructor @AllArgsConstructor
@RequestMapping("/oss/endpoint") @RequestMapping("/oss/endpoint")
@Api(value = "对象存储端点", tags = "对象存储端点") @Tag(name = "对象存储端点", description = "对象存储端点")
public class OssEndpoint { public class OssEndpoint {
private QiniuTemplate qiniuTemplate; private QiniuTemplate qiniuTemplate;

View File

@ -5,30 +5,26 @@
<parent> <parent>
<artifactId>blade-ops</artifactId> <artifactId>blade-ops</artifactId>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<version>3.0.3</version> <version>${revision}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>blade-seata-order</artifactId> <artifactId>blade-seata-order</artifactId>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<version>${blade.project.version}</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-common</artifactId> <artifactId>blade-common</artifactId>
<version>${blade.project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-boot</artifactId> <artifactId>blade-core-boot</artifactId>
<version>${blade.tool.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-transaction</artifactId> <artifactId>blade-starter-transaction</artifactId>
<version>${blade.tool.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
@ -45,22 +41,6 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId> <artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<!--suppress UnresolvedMavenProperty -->
<copy overwrite="true"
tofile="${session.executionRootDirectory}/target/${artifactId}.jar"
file="${project.build.directory}/${artifactId}.jar" />
</tasks>
</configuration>
</execution>
</executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -19,6 +20,7 @@ import java.math.BigDecimal;
@TableName("tb_order") @TableName("tb_order")
public class Order implements Serializable { public class Order implements Serializable {
@Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)

View File

@ -5,30 +5,26 @@
<parent> <parent>
<artifactId>blade-ops</artifactId> <artifactId>blade-ops</artifactId>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<version>3.0.3</version> <version>${revision}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>blade-seata-storage</artifactId> <artifactId>blade-seata-storage</artifactId>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<version>${blade.project.version}</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-common</artifactId> <artifactId>blade-common</artifactId>
<version>${blade.project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-boot</artifactId> <artifactId>blade-core-boot</artifactId>
<version>${blade.tool.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-core-transaction</artifactId> <artifactId>blade-starter-transaction</artifactId>
<version>${blade.tool.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
@ -45,22 +41,6 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId> <artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<!--suppress UnresolvedMavenProperty -->
<copy overwrite="true"
tofile="${session.executionRootDirectory}/target/${artifactId}.jar"
file="${project.build.directory}/${artifactId}.jar" />
</tasks>
</configuration>
</execution>
</executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -4,6 +4,7 @@ package org.springblade.seata.storage.entity;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
/** /**
@ -15,6 +16,7 @@ import java.io.Serializable;
@TableName("tb_storage") @TableName("tb_storage")
public class Storage implements Serializable { public class Storage implements Serializable {
@Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private Long id; private Long id;

View File

@ -1,15 +0,0 @@
FROM anapsix/alpine-java:8_server-jre_unlimited
MAINTAINER smallchill@163.com
RUN mkdir -p /blade/swagger
WORKDIR /blade/swagger
EXPOSE 18000
ADD ./target/blade-swagger.jar ./app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
CMD ["--spring.profiles.active=test"]

View File

@ -1,76 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>blade-ops</artifactId>
<groupId>org.springblade</groupId>
<version>3.0.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>blade-swagger</artifactId>
<name>${project.artifactId}</name>
<version>${blade.project.version}</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-launch</artifactId>
<version>${blade.tool.version}</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-aggregation-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>${docker.plugin.version}</version>
<configuration>
<imageName>${docker.registry.url}/blade/${project.artifactId}:${project.version}</imageName>
<dockerDirectory>${project.basedir}</dockerDirectory>
<dockerHost>${docker.registry.host}</dockerHost>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
<registryUrl>${docker.registry.url}</registryUrl>
<serverId>${docker.registry.url}</serverId>
<pushImage>true</pushImage>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<!--suppress UnresolvedMavenProperty -->
<copy overwrite="true"
tofile="${session.executionRootDirectory}/target/${artifactId}.jar"
file="${project.build.directory}/${artifactId}.jar" />
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,16 +0,0 @@
server:
port: 18000
knife4j:
enableAggregation: true
cloud:
enable: true
routes:
- name: 授权模块
uri: 127.0.0.1
location: /blade-auth/v2/api-docs
- name: 工作台模块
uri: 127.0.0.1
location: /blade-desk/v2/api-docs
- name: 系统模块
uri: 127.0.0.1
location: /blade-system/v2/api-docs

View File

@ -1,10 +0,0 @@
${AnsiColor.BRIGHT_CYAN} _____ _ ${AnsiColor.BLUE} ______ _ _
${AnsiColor.BRIGHT_CYAN}/ ___| (_) ${AnsiColor.BLUE} | ___ \| | | |
${AnsiColor.BRIGHT_CYAN}\ `--. _ __ _ __ _ _ __ __ _ ${AnsiColor.BLUE} | |_/ /| | __ _ __| | ___
${AnsiColor.BRIGHT_CYAN} `--. \| '_ \ | '__|| || '_ \ / _` | ${AnsiColor.BLUE} | ___ \| | / _` | / _` | / _ \
${AnsiColor.BRIGHT_CYAN}/\__/ /| |_) || | | || | | || (_| | ${AnsiColor.BLUE} | |_/ /| || (_| || (_| || __/
${AnsiColor.BRIGHT_CYAN}\____/ | .__/ |_| |_||_| |_| \__, | ${AnsiColor.BLUE} \____/ |_| \__,_| \__,_| \___|
${AnsiColor.BRIGHT_CYAN} | | __/ |
${AnsiColor.BRIGHT_CYAN} |_| |___/
${AnsiColor.BLUE}:: SpringBlade :: ${spring.application.name}:${AnsiColor.RED}${blade.env}${AnsiColor.BLUE} :: Running SpringBoot ${spring-boot.version} :: ${AnsiColor.BRIGHT_BLACK}

View File

@ -5,13 +5,12 @@
<parent> <parent>
<artifactId>SpringBlade</artifactId> <artifactId>SpringBlade</artifactId>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<version>3.0.3</version> <version>${revision}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>blade-ops</artifactId> <artifactId>blade-ops</artifactId>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<version>3.0.3</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>
<module>blade-admin</module> <module>blade-admin</module>
@ -20,7 +19,6 @@
<module>blade-resource</module> <module>blade-resource</module>
<module>blade-seata-order</module> <module>blade-seata-order</module>
<module>blade-seata-storage</module> <module>blade-seata-storage</module>
<module>blade-swagger</module>
</modules> </modules>
</project> </project>

View File

@ -5,13 +5,12 @@
<parent> <parent>
<artifactId>blade-service-api</artifactId> <artifactId>blade-service-api</artifactId>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<version>3.0.3</version> <version>${revision}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>blade-demo-api</artifactId> <artifactId>blade-demo-api</artifactId>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<version>${blade.project.version}</version>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,11 +20,12 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModelProperty; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity; import org.springblade.core.mp.base.BaseEntity;
import java.io.Serial;
import java.util.Date; import java.util.Date;
/** /**
@ -37,12 +38,13 @@ import java.util.Date;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class Notice extends BaseEntity { public class Notice extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 主键id * 主键id
*/ */
@ApiModelProperty(value = "主键") @Schema(description = "主键")
@TableId(value = "id", type = IdType.ASSIGN_ID) @TableId(value = "id", type = IdType.ASSIGN_ID)
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long id; private Long id;
@ -50,25 +52,25 @@ public class Notice extends BaseEntity {
/** /**
* 标题 * 标题
*/ */
@ApiModelProperty(value = "标题") @Schema(description = "标题")
private String title; private String title;
/** /**
* 通知类型 * 通知类型
*/ */
@ApiModelProperty(value = "通知类型") @Schema(description = "通知类型")
private Integer category; private Integer category;
/** /**
* 发布日期 * 发布日期
*/ */
@ApiModelProperty(value = "发布日期") @Schema(description = "发布日期")
private Date releaseTime; private Date releaseTime;
/** /**
* 内容 * 内容
*/ */
@ApiModelProperty(value = "内容") @Schema(description = "内容")
private String content; private String content;

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
package com.example.demo.vo; package com.example.demo.vo;
import io.swagger.annotations.ApiModelProperty; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import com.example.demo.entity.Notice; import com.example.demo.entity.Notice;
@ -14,7 +14,7 @@ import com.example.demo.entity.Notice;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class NoticeVO extends Notice { public class NoticeVO extends Notice {
@ApiModelProperty(value = "通知类型名") @Schema(description = "通知类型名")
private String categoryName; private String categoryName;
} }

View File

@ -5,13 +5,12 @@
<parent> <parent>
<artifactId>blade-service-api</artifactId> <artifactId>blade-service-api</artifactId>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<version>3.0.3</version> <version>${revision}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>blade-desk-api</artifactId> <artifactId>blade-desk-api</artifactId>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<version>${blade.project.version}</version>
<packaging>jar</packaging> <packaging>jar</packaging>
</project> </project>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,11 +20,12 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModelProperty; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity; import org.springblade.core.mp.base.BaseEntity;
import java.io.Serial;
import java.util.Date; import java.util.Date;
/** /**
@ -37,12 +38,13 @@ import java.util.Date;
@TableName("blade_notice") @TableName("blade_notice")
public class Notice extends BaseEntity { public class Notice extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 主键id * 主键id
*/ */
@ApiModelProperty(value = "主键") @Schema(description = "主键")
@TableId(value = "id", type = IdType.ASSIGN_ID) @TableId(value = "id", type = IdType.ASSIGN_ID)
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long id; private Long id;
@ -50,25 +52,25 @@ public class Notice extends BaseEntity {
/** /**
* 标题 * 标题
*/ */
@ApiModelProperty(value = "标题") @Schema(description = "标题")
private String title; private String title;
/** /**
* 通知类型 * 通知类型
*/ */
@ApiModelProperty(value = "通知类型") @Schema(description = "通知类型")
private Integer category; private Integer category;
/** /**
* 发布日期 * 发布日期
*/ */
@ApiModelProperty(value = "发布日期") @Schema(description = "发布日期")
private Date releaseTime; private Date releaseTime;
/** /**
* 内容 * 内容
*/ */
@ApiModelProperty(value = "内容") @Schema(description = "内容")
private String content; private String content;

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
package org.springblade.desk.vo; package org.springblade.desk.vo;
import io.swagger.annotations.ApiModelProperty; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.springblade.desk.entity.Notice; import org.springblade.desk.entity.Notice;
@ -14,7 +14,7 @@ import org.springblade.desk.entity.Notice;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class NoticeVO extends Notice { public class NoticeVO extends Notice {
@ApiModelProperty(value = "通知类型名") @Schema(description = "通知类型名")
private String categoryName; private String categoryName;
} }

View File

@ -5,13 +5,12 @@
<parent> <parent>
<artifactId>blade-service-api</artifactId> <artifactId>blade-service-api</artifactId>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<version>3.0.3</version> <version>${revision}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>blade-dict-api</artifactId> <artifactId>blade-dict-api</artifactId>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<version>${blade.project.version}</version>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,6 +19,8 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.springblade.system.entity.Dict; import org.springblade.system.entity.Dict;
import java.io.Serial;
/** /**
* 数据传输对象实体类 * 数据传输对象实体类
* *
@ -28,6 +30,7 @@ import org.springblade.system.entity.Dict;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class DictDTO extends Dict { public class DictDTO extends Dict {
@Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,10 +21,10 @@ import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel; import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
/** /**
@ -35,15 +35,16 @@ import java.io.Serializable;
*/ */
@Data @Data
@TableName("blade_dict") @TableName("blade_dict")
@ApiModel(value = "Dict对象", description = "Dict对象") @Schema(description = "Dict对象")
public class Dict implements Serializable { public class Dict implements Serializable {
@Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 主键 * 主键
*/ */
@ApiModelProperty(value = "主键") @Schema(description = "主键")
@TableId(value = "id", type = IdType.ASSIGN_ID) @TableId(value = "id", type = IdType.ASSIGN_ID)
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long id; private Long id;
@ -51,45 +52,45 @@ public class Dict implements Serializable {
/** /**
* 父主键 * 父主键
*/ */
@ApiModelProperty(value = "父主键") @Schema(description = "父主键")
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long parentId; private Long parentId;
/** /**
* 字典码 * 字典码
*/ */
@ApiModelProperty(value = "字典码") @Schema(description = "字典码")
private String code; private String code;
/** /**
* 字典值 * 字典值
*/ */
@ApiModelProperty(value = "字典值") @Schema(description = "字典值")
private Integer dictKey; private Integer dictKey;
/** /**
* 字典名称 * 字典名称
*/ */
@ApiModelProperty(value = "字典名称") @Schema(description = "字典名称")
private String dictValue; private String dictValue;
/** /**
* 排序 * 排序
*/ */
@ApiModelProperty(value = "排序") @Schema(description = "排序")
private Integer sort; private Integer sort;
/** /**
* 字典备注 * 字典备注
*/ */
@ApiModelProperty(value = "字典备注") @Schema(description = "字典备注")
private String remark; private String remark;
/** /**
* 是否已删除 * 是否已删除
*/ */
@TableLogic @TableLogic
@ApiModelProperty(value = "是否已删除") @Schema(description = "是否已删除")
private Integer isDeleted; private Integer isDeleted;

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,12 +18,13 @@ package org.springblade.system.vo;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.springblade.core.tool.node.INode; import org.springblade.core.tool.node.INode;
import org.springblade.system.entity.Dict; import org.springblade.system.entity.Dict;
import java.io.Serial;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -35,8 +36,9 @@ import java.util.List;
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ApiModel(value = "DictVO对象", description = "DictVO对象") @Schema(description = "DictVO对象")
public class DictVO extends Dict implements INode { public class DictVO extends Dict implements INode<DictVO> {
@Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 主键ID * 主键ID
@ -54,10 +56,10 @@ public class DictVO extends Dict implements INode {
* 子孙节点 * 子孙节点
*/ */
@JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<INode> children; private List<DictVO> children;
@Override @Override
public List<INode> getChildren() { public List<DictVO> getChildren() {
if (this.children == null) { if (this.children == null) {
this.children = new ArrayList<>(); this.children = new ArrayList<>();
} }

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>blade-service-api</artifactId>
<groupId>org.springblade</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>blade-scope-api</artifactId>
<name>${project.artifactId}</name>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-secure</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-datascope</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,92 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.system.cache;
import org.springblade.core.datascope.model.DataScopeModel;
import org.springblade.core.tool.utils.*;
import org.springblade.system.feign.IDataScopeClient;
import java.util.List;
import static org.springblade.core.tool.utils.CacheUtil.SYS_CACHE;
/**
* 数据权限缓存
*
* @author Chill
*/
public class DataScopeCache {
private static final String SCOPE_CACHE_CODE = "dataScope:code:";
private static final String SCOPE_CACHE_CLASS = "dataScope:class:";
private static final String DEPT_CACHE_ANCESTORS = "dept:ancestors:";
private static IDataScopeClient dataScopeClient;
private static IDataScopeClient getDataScopeClient() {
if (dataScopeClient == null) {
dataScopeClient = SpringUtil.getBean(IDataScopeClient.class);
}
return dataScopeClient;
}
/**
* 获取数据权限
*
* @param mapperId 数据权限mapperId
* @param roleId 用户角色集合
* @return DataScopeModel
*/
public static DataScopeModel getDataScopeByMapper(String mapperId, String roleId) {
DataScopeModel dataScope = CacheUtil.get(SYS_CACHE, SCOPE_CACHE_CLASS, mapperId + StringPool.COLON + roleId, DataScopeModel.class);
if (dataScope == null || !dataScope.getSearched()) {
dataScope = getDataScopeClient().getDataScopeByMapper(mapperId, roleId);
CacheUtil.put(SYS_CACHE, SCOPE_CACHE_CLASS, mapperId + StringPool.COLON + roleId, dataScope);
}
return StringUtil.isNotBlank(dataScope.getResourceCode()) ? dataScope : null;
}
/**
* 获取数据权限
*
* @param code 数据权限资源编号
* @return DataScopeModel
*/
public static DataScopeModel getDataScopeByCode(String code) {
DataScopeModel dataScope = CacheUtil.get(SYS_CACHE, SCOPE_CACHE_CODE, code, DataScopeModel.class);
if (dataScope == null || !dataScope.getSearched()) {
dataScope = getDataScopeClient().getDataScopeByCode(code);
CacheUtil.put(SYS_CACHE, SCOPE_CACHE_CODE, code, dataScope);
}
return StringUtil.isNotBlank(dataScope.getResourceCode()) ? dataScope : null;
}
/**
* 获取部门子级
*
* @param deptId 部门id
* @return deptIds
*/
public static List<Long> getDeptAncestors(Long deptId) {
List ancestors = CacheUtil.get(SYS_CACHE, DEPT_CACHE_ANCESTORS, deptId, List.class);
if (CollectionUtil.isEmpty(ancestors)) {
ancestors = getDataScopeClient().getDeptAncestors(deptId);
CacheUtil.put(SYS_CACHE, DEPT_CACHE_ANCESTORS, deptId, ancestors);
}
return ancestors;
}
}

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