diff --git a/pom.xml b/pom.xml index 6798c157..fde84309 100644 --- a/pom.xml +++ b/pom.xml @@ -14,26 +14,26 @@ 1.0.0 - 3.0.6 + 3.4.4 UTF-8 UTF-8 17 8.0.33 - 3.0.1 + 3.5.16 2.1.0 0.15.0 5.2.3 3.2.1 2.3 1.34.0 - 3.5.3.1 + 3.5.11 3.9.1 - 5.8.18 + 5.8.35 4.10.0 + 4.3.1 3.0.3 3.20.1 2.2.4 - 3.6.1 2.14.2 2.4.0 1.2.1 @@ -42,10 +42,6 @@ 1.72 2.7.0 - - - 1.33 - 1.12.400 @@ -202,22 +198,22 @@ ${satoken.version} - - - com.baomidou - dynamic-datasource-spring-boot-starter - ${dynamic-ds.version} - - org.mybatis.spring.boot - mybatis-spring-boot-starter - ${spring-boot.mybatis} + org.mybatis + mybatis + ${mybatis.version} com.baomidou - mybatis-plus-boot-starter + mybatis-plus-spring-boot3-starter + ${mybatis-plus.version} + + + + com.baomidou + mybatis-plus-jsqlparser ${mybatis-plus.version} @@ -227,6 +223,13 @@ ${mybatis-plus.version} + + + com.baomidou + dynamic-datasource-spring-boot3-starter + ${dynamic-ds.version} + + p6spy @@ -277,13 +280,6 @@ ${alibaba-ttl.version} - - - org.yaml - snakeyaml - ${snakeyaml.version} - - org.bouncycastle @@ -341,11 +337,11 @@ ${revision} - - org.ruoyi - ruoyi-demo - ${revision} - + + + + + @@ -354,7 +350,8 @@ ruoyi-common ruoyi-modules ruoyi-modules-api - ruoyi-modules/ruoyi-mcp-server + ruoyi-admin + ruoyi-extend pom diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index a8276a4c..89003c2a 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -42,10 +42,11 @@ mssql-jdbc - - org.ruoyi - ruoyi-common-doc - + + + + + org.ruoyi @@ -54,38 +55,7 @@ org.ruoyi - ruoyi-fusion - - - - org.ruoyi - ruoyi-knowledge - - - - - - org.ruoyi - ruoyi-demo - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - net.coobird - thumbnailator - 0.4.11 - - - io.github.ollama4j - ollama4j - 1.0.79 - compile + ruoyi-chat diff --git a/ruoyi-admin/src/main/java/org/ruoyi/controller/AuthController.java b/ruoyi-admin/src/main/java/org/ruoyi/controller/AuthController.java index e78d09c0..5a7a514c 100644 --- a/ruoyi-admin/src/main/java/org/ruoyi/controller/AuthController.java +++ b/ruoyi-admin/src/main/java/org/ruoyi/controller/AuthController.java @@ -14,18 +14,17 @@ import org.ruoyi.common.core.utils.StreamUtils; import org.ruoyi.common.core.utils.StringUtils; import org.ruoyi.common.satoken.utils.LoginHelper; import org.ruoyi.common.tenant.helper.TenantHelper; -import org.ruoyi.system.domain.bo.SysTenantBo; -import org.ruoyi.system.domain.vo.LoginTenantVo; -import org.ruoyi.system.domain.vo.SysTenantVo; -import org.ruoyi.system.domain.vo.TenantListVo; -import org.ruoyi.system.service.ISysTenantService; - -import org.ruoyi.system.service.SysLoginService; -import org.ruoyi.system.service.SysRegisterService; -import org.ruoyi.system.domain.vo.LoginVo; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; +import org.ruoyi.system.domain.bo.SysTenantBo; +import org.ruoyi.system.domain.vo.LoginTenantVo; +import org.ruoyi.system.domain.vo.LoginVo; +import org.ruoyi.system.domain.vo.SysTenantVo; +import org.ruoyi.system.domain.vo.TenantListVo; +import org.ruoyi.system.service.ISysTenantService; +import org.ruoyi.system.service.SysLoginService; +import org.ruoyi.system.service.SysRegisterService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; diff --git a/ruoyi-admin/src/main/java/org/ruoyi/controller/IndexController.java b/ruoyi-admin/src/main/java/org/ruoyi/controller/IndexController.java index 4da12bc8..2a4ee1f0 100644 --- a/ruoyi-admin/src/main/java/org/ruoyi/controller/IndexController.java +++ b/ruoyi-admin/src/main/java/org/ruoyi/controller/IndexController.java @@ -4,6 +4,7 @@ import cn.dev33.satoken.annotation.SaIgnore; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; /** * 首页 @@ -11,8 +12,7 @@ import org.springframework.web.bind.annotation.GetMapping; * @author Lion Li */ @SaIgnore -@RequiredArgsConstructor -@Controller +@RestController public class IndexController { /** @@ -20,17 +20,9 @@ public class IndexController { */ @GetMapping("/") public String index() { - return "index.html"; + return "RuoYi AI启动成功!"; } - @GetMapping("/success") - public String success(){ - return "paySuccess.html"; - } - @GetMapping("/cancel") - public String cancel(){ - return "cancel"; - } } diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index 09c609c3..66a63e71 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -60,9 +60,6 @@ spring.data: # password: 123456 # 连接超时时间 timeout: 10S - # 是否开启ssl - ssl: false - redisson: # redis key前缀 keyPrefix: @@ -97,22 +94,3 @@ sms: # 腾讯专用 sdkAppId: -spring: - ai: - openai: - api-key: sk-xX - base-url: https://api.pandarobot.chat - ollama: - base-url: http://localhost:11434 - init: - pull-model-strategy: always - timeout: 60s - max-retries: 1 - mcp: - client: - enabled: true - name: call-mcp-server - sse: - connections: - server1: - url: http://127.0.0.1:8080 diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 26173564..84be163e 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -49,8 +49,10 @@ server: # 日志配置 logging: level: - org.ruoyi: @logging.level@ + org.dromara: @logging.level@ org.springframework: warn + org.mybatis.spring.mapper: error + org.apache.fury: warn config: classpath:logback-plus.xml # 用户配置 @@ -318,5 +320,16 @@ wechat: token: '' aesKey: '' - +spring: + ai: + ollama: + base-url: http://localhost:11434 + mcp: + client: + enabled: true + name: call-mcp-server + sse: + connections: + server1: + url: http://127.0.0.1:6040 diff --git a/ruoyi-admin/src/main/resources/static/.gitignore b/ruoyi-admin/src/main/resources/static/.gitignore deleted file mode 100644 index 9e339689..00000000 --- a/ruoyi-admin/src/main/resources/static/.gitignore +++ /dev/null @@ -1,46 +0,0 @@ -###################################################################### -# Build Tools - -.gradle -/build/ -!gradle/wrapper/gradle-wrapper.jar - -target/ -!.mvn/wrapper/maven-wrapper.jar - -###################################################################### -# IDE - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### JRebel ### -rebel.xml - -### NetBeans ### -nbproject/private/ -build/* -nbbuild/ -nbdist/ -.nb-gradle/ - -###################################################################### -# Others -*.log -*.xml.versionsBackup -*.swp - -!*/build/*.java -!*/build/*.html -!*/build/*.xml diff --git a/ruoyi-admin/src/main/resources/static/.nojekyll b/ruoyi-admin/src/main/resources/static/.nojekyll deleted file mode 100644 index e69de29b..00000000 diff --git a/ruoyi-admin/src/main/resources/static/CNAME b/ruoyi-admin/src/main/resources/static/CNAME deleted file mode 100644 index 3a194c70..00000000 --- a/ruoyi-admin/src/main/resources/static/CNAME +++ /dev/null @@ -1 +0,0 @@ -plus-doc.dromara.org \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/README.md b/ruoyi-admin/src/main/resources/static/README.md deleted file mode 100644 index b50e2523..00000000 --- a/ruoyi-admin/src/main/resources/static/README.md +++ /dev/null @@ -1,74 +0,0 @@ -# 框架介绍 -- - - -- `RuoYi-Vue-Plus` 分布式集群框架 [文档跳转](/ruoyi-vue-plus/home.md) -- `RuoYi-Cloud-Plus` 微服务框架 [文档跳转](/ruoyi-cloud-plus/home.md) -- `plus-ui` 统一 Vue3 前端项目 [文档跳转](/plus-ui/home.md) -- `plus-doc` 统一文档项目 - -## 特别赞助 - - - -
- - -
- - -[如何成为赞助商 加群联系作者详谈](/common/add_group.md) - -## 代码地址 - -| 介绍 | 项目名 | 项目地址 | 注意事项 | -|------------|:-----------------|------------------------------------------------------------------------------------------------------------------------|----------------------------| -| 🔥 分布式集群框架 | RuoYi-Vue-Plus | - [Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus)
- [GitHub](https://github.com/dromara/RuoYi-Vue-Plus) | 重写RuoYi-Vue全方位升级(不兼容原框架) | -| 🔥 微服务框架 | RuoYi-Cloud-Plus | - [Gitee](https://gitee.com/dromara/RuoYi-Cloud-Plus)
- [GitHub](https://github.com/dromara/RuoYi-Cloud-Plus) | 重写RuoYi-Cloud全方位升级(不兼容原框架) | -| 🔥 统一前端项目 | plus-ui | - [Gitee](https://gitee.com/JavaLionLi/plus-ui)
- [GitHub](https://github.com/JavaLionLi/plus-ui) | Vue与Cloud项目通用前端 | -| 🔥 统一文档项目 | plus-doc | - [Gitee](https://gitee.com/dromara/plus-doc)
- [GitHub](https://github.com/dromara/plus-doc) | 通用文档 | - - -## 业务功能 - -| 功能 | 介绍 | -|-------|---------------------------------------| -| 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能。 | -| 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置。 | -| 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 | -| 岗位管理 | 配置系统用户所属担任职务。 | -| 菜单管理 | 配置系统菜单,操作权限,按钮权限标识等。 | -| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分。 | -| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护。 | -| 参数管理 | 对系统动态配置常用参数。 | -| 通知公告 | 系统通知公告信息发布维护。 | -| 操作日志 | 系统正常操作日志记录和查询;系统异常信息日志记录和查询。 | -| 登录日志 | 系统登录日志记录查询包含登录异常。 | -| 文件管理 | 系统文件上传、下载等管理。 | -| 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志。 | -| 代码生成 | 前后端代码的生成(java、html、xml、sql)支持CRUD下载 。 | -| 系统接口 | 根据业务代码自动生成相关的api接口文档。 | -| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等。 | -| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | -| 在线构建器 | 拖动表单元素生成相应的HTML代码。 | -| 使用案例 | 系统的一些功能案例 | - -## 关注作者 - -作者博客: [https://lionli.blog.csdn.net/?type=blog](https://lionli.blog.csdn.net/?type=blog) - -公众号: **<狮子领域 程序圈>** -
-![输入图片说明](https://foruda.gitee.com/images/1678975769377570440/507062df_1766278.png "屏幕截图") - -## 捐献作者 - -**作者为兼职做开源,平时还需要工作,如果帮到了您可以请作者吃个盒饭** -
- - -## Dromara 全家福 - -社区仓库地址: [dromara开源社区](https://gitee.com/organizations/dromara/projects) - -![输入图片说明](https://foruda.gitee.com/images/1706071866226295002/68cffcf6_1766278.png "屏幕截图") - - diff --git a/ruoyi-admin/src/main/resources/static/_coverpage.md b/ruoyi-admin/src/main/resources/static/_coverpage.md deleted file mode 100644 index d84bf0dc..00000000 --- a/ruoyi-admin/src/main/resources/static/_coverpage.md +++ /dev/null @@ -1,32 +0,0 @@ - - - -
-
-
百搭AI
- - -[![码云Gitee](https://gitee.com/ageerle/ruoyi-ai/badge/star.svg?theme=blue)](https://gitee.com/ageerle/ruoyi-ai) -[![GitHub](https://img.shields.io/github/stars/ageerle/ruoyi-ai.svg?style=social&label=Stars)](https://github.com/dromara/RuoYi-Vue-Plus) -[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/ageerle/ruoyi-ai/blob/master/LICENSE) -
-[![ruoyi-ai](https://img.shields.io/badge/ruoyi-ai-5.2.2-success.svg)](https://gitee.com/ageerle/ruoyi-ai) -[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.2-blue.svg)]() - -
-
- -
- -
- - -> 百搭AI是一个整合了多种大语言模型API的开源平台,实现了AI对话、绘图、声音克隆和私有知识库等功能。 -> -> 平台配备管理后台,支持微信支付、微信公众号、微信多开、Stripe国际支付和百度文本审核等运营功能。 -> -> 项目采用Java+Vue+Vben5技术栈构建,遵循MIT License,允许二次开发并用于商业销售。 - -Copyright © 2023-2024 版权所有:ageerle@163.com 备案号:鄂ICP备2023007672号 - -[开始使用 Let's Go](/README.md) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/_footer.md b/ruoyi-admin/src/main/resources/static/_footer.md deleted file mode 100644 index 7f5f9a3f..00000000 --- a/ruoyi-admin/src/main/resources/static/_footer.md +++ /dev/null @@ -1,2 +0,0 @@ - -对文档有疑问?欢迎您帮助我们 [完善此文档](https://gitee.com/JavaLionLi/plus-doc) ! \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/_navbar.md b/ruoyi-admin/src/main/resources/static/_navbar.md deleted file mode 100644 index e893825f..00000000 --- a/ruoyi-admin/src/main/resources/static/_navbar.md +++ /dev/null @@ -1,9 +0,0 @@ - - -* [文档导航](/README.md) -* [Vue版本](/ruoyi-vue-plus/home.md) -* [Cloud版本](/ruoyi-cloud-plus/home.md) -* [前端文档](/plus-ui/home.md) -* [常见问题](/questions/lombok.md) -* [视频教程](/common/video.md) -* [演示系统](/common/demo_system.md) diff --git a/ruoyi-admin/src/main/resources/static/_sidebar.md b/ruoyi-admin/src/main/resources/static/_sidebar.md deleted file mode 100644 index 0446edc6..00000000 --- a/ruoyi-admin/src/main/resources/static/_sidebar.md +++ /dev/null @@ -1,16 +0,0 @@ - -- **特别赞助** -- [![输入图片说明](https://foruda.gitee.com/images/1704162419429172656/d0521e59_1766278.png "2024-01-02=>2028-01-02")](http://ccflow.org/?frm=ryPlus) -- [![输入图片说明](https://foruda.gitee.com/images/1705569347386939952/3f187980_1766278.jpeg "2024-01-18=>2025-01-18")](http://www.shuduokeji.com) -- [![输入图片说明](https://foruda.gitee.com/images/1711681233267310022/2ffbcff2_1766278.png "2024-03-29=>2025-03-29")](https://www.jnpfsoft.com/index.html?from=plus-doc) - -- **开始** - - [框架介绍](/README.md) - - [演示系统](/common/demo_system.md) - - [官方视频教程](/common/video.md) - - [粉丝专栏](/common/column.md) - - [参与贡献项目](/common/contribution.md) - - [如何提交PR](/common/pr.md) - - [如何加群](/common/add_group.md) - - [使用者登记](/common/user_register.md) - - [黑名单](/common/blacklist.md) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/common/add_group.md b/ruoyi-admin/src/main/resources/static/common/add_group.md deleted file mode 100644 index f6957bc4..00000000 --- a/ruoyi-admin/src/main/resources/static/common/add_group.md +++ /dev/null @@ -1,27 +0,0 @@ -# 加群方式 -- - - -### 交流群(不提供任何问题解答 纯交流) - -**加 <小助手> 微信备注 <加群>**
-**视频课程咨询或其他问题咨询请查看下方信息(小助手是机器人)** - - - -### VIP群(付费加群 提供问题解答、技术支持、技术分享) - -首先感谢 `RuoYi` 提供分享开源 框架基于 `RuoYi` 重写大部分功能实现
-项目代码、文档 均开源免费可商用 遵循开源协议在项目中保留开源协议文件即可
-VIP群是作者提供的私人服务 不代表着项目收费 - -> 问问题等于做习题 听作者解答问题等于习题讲解
-> 一个人接触的问题有限 一群人接触的问题无限 早进群早接触更多的问题(每天99+)
-> 承诺: 看见必回复 让你感受作者有多话痨
- -两种途径: -1. 购买官方视频进群 [官方视频](/common/video.md) -2. 扫描下方二维码付款进群(无视频) - -支付后申请加群即可 QQ群号 : **<637757165>**
- -**加群扫码**
- diff --git a/ruoyi-admin/src/main/resources/static/common/blacklist.md b/ruoyi-admin/src/main/resources/static/common/blacklist.md deleted file mode 100644 index 67594bd3..00000000 --- a/ruoyi-admin/src/main/resources/static/common/blacklist.md +++ /dev/null @@ -1,7 +0,0 @@ -# 黑名单 -- - - - -地址: https://github.com/QNAV/RuoYi-X-Plus -
-上榜缘由 使用本框架二次开源并未有任何声明与标注 将所有代码的作者名全都改成了自己 剽窃本框架代码 - diff --git a/ruoyi-admin/src/main/resources/static/common/column.md b/ruoyi-admin/src/main/resources/static/common/column.md deleted file mode 100644 index b2155a3c..00000000 --- a/ruoyi-admin/src/main/resources/static/common/column.md +++ /dev/null @@ -1,18 +0,0 @@ -# 粉丝专栏 -- - - -**由上到下 从易到难** - -> 粉丝整理 欢迎投稿 - -| 作者 | 文档地址 | 说明 | -|---------------|---------------------------------------------------------------|--------------------| -| 抓蛙师 | https://www.bilibili.com/video/BV1TG41157Ef/ | 学会问问题(小白必看) | -| 抓蛙师 | https://www.bilibili.com/video/BV1mr4y1j75M | Vue框架基础视频专栏(新人必看) | -| 抓蛙师 | https://www.bilibili.com/video/BV1Na411u7eC | Vue框架改造视频专栏(新人必看) | -| 抓蛙师 | https://www.bilibili.com/video/BV1te4y1D7hi | 小程序鉴权与uniapp联动 | -| 抓蛙师 | https://www.bilibili.com/video/BV1zt4y137UP | 公众号集成 | -| mayuanfei | https://note.youdao.com/s/XpvKnxAb | 入门专栏(新人必看) | -| 程序猿一枚_ | https://blog.csdn.net/zhaozhiqiang1981/category_12221291.html | 玩转RuoYi-Cloud-Plus | -| 程序猿一枚_ | https://www.bilibili.com/video/BV1yA411r7ji/ | Cloud环境搭建以及进阶开发 | -| MichelleChung | https://blog.csdn.net/michelle_zhong/category_11109741.html | 源码解析专栏(进阶必看) | -| MichelleChung | https://blog.csdn.net/michelle_zhong/category_12058476.html | Cloud源码解析专栏 | diff --git a/ruoyi-admin/src/main/resources/static/common/contribution.md b/ruoyi-admin/src/main/resources/static/common/contribution.md deleted file mode 100644 index 6b5909e6..00000000 --- a/ruoyi-admin/src/main/resources/static/common/contribution.md +++ /dev/null @@ -1,69 +0,0 @@ -# 参与贡献的方式 -- - - -参与贡献开源的方式有很多种 听作者来介绍 - -## 为开源项目点一个Star - -> Star的多少关系到项目能否被更多人看到 -
-同时Star也是作者前进的动力(作者每天都在盯着Star 涨了会开心 跌了会失落) -
-
-> 大家在寻找开源项目的时候, 大多数情况也是会先看Star比较多的项目 -
-所以请给您觉得好的开源项目点一个小小的Star, 让好的项目能够被更多人看到 -
- -![输入图片说明](https://foruda.gitee.com/images/1678934493115487351/0c45121e_1766278.png "屏幕截图") -
-Vue版本: [Gitee我要点Star](https://gitee.com/dromara/RuoYi-Vue-Plus/stargazers) [Github我要点Star](https://github.com/dromara/RuoYi-Vue-Plus) -
-Cloud版本: [Gitee我要点Star](https://gitee.com/dromara/RuoYi-Cloud-Plus/stargazers) [Github我要点Star](https://github.com/dromara/RuoYi-Cloud-Plus) - -## 为社区处理问题 - -> Issue是社区的交流地 大家会在这里提出自己的问题 或者是项目的功能异常 - -> 提问的规范在Issue的模板里已经写好了 按照模板填写有助于作者或者其他社区人员快速有效的回答问题 -![输入图片说明](https://foruda.gitee.com/images/1678935068341532603/4b9d7af9_1766278.png "屏幕截图") - -> 为提出问题的小伙伴答疑 可以有效降的帮助别人
-> 而且可以降低社区人员的精力分散 使精力全部投入到项目设计研发中 -![输入图片说明](https://foruda.gitee.com/images/1678935380481365514/dddc9ce9_1766278.png "屏幕截图") - -## 改进社区文档 - -> 大家都知道 我们程序员都不擅长写作
-> 有时候作者把文档写完了也不知道用户是什么感觉 是否能看懂
- -> 所以参与社区文档建设绝对是一件意义重大的事情
-> 大家可以在Issue提出观后感 觉得哪看不懂 觉得哪应该详细说明
-> 当然了 大家也可以对文档进行改进后提交PR修改申请 - -文档仓库: [plus-doc](https://gitee.com/JavaLionLi/plus-doc) 👈点他点他 -![输入图片说明](https://foruda.gitee.com/images/1678935992827063291/d7c4dc5b_1766278.png "屏幕截图") - -## 贡献代码 - -> 想参与贡献代码的小伙伴 重点来了: 作者会经常在Issue里发布需求认领
-> 觉得自己能做的可以在Issue里跟作者讨论 如需求还不够清晰 或者做的过程中遇到了什么问题 - - - -> 需求确定了以后就可以开始专注的写代码了
-> 但在开始写代码之前 一定要先看一下如何正确的提交PR - -一点要仔细看: [如何提交PR](/common/pr.md) 👈点他点他 - -## 如何成为项目成员 - -> 1.对框架有重大贡献者(由作者与团队成员判定)
-> 2.完成社区发布的两项复杂任务
-> 3.持续完成社区发布的简单任务若干(作者会关注到)
-> 4.持续为社区优化文档或处理issue若干(作者会关注到)
- -## 项目成员待遇 - -> 1.可免费进入vip收费群
-> 2.每年还会发放IDEA正版授权
- diff --git a/ruoyi-admin/src/main/resources/static/common/demo_system.md b/ruoyi-admin/src/main/resources/static/common/demo_system.md deleted file mode 100644 index 18424e90..00000000 --- a/ruoyi-admin/src/main/resources/static/common/demo_system.md +++ /dev/null @@ -1,13 +0,0 @@ -# 系统演示(请大家不要乱改数据 影响他人体验 谢谢配合) -- - - -**感谢 `孤舟烟雨` 贡献的演示服务器** - -**1核2G 小服务器 经不起压测 请理性操作 违者直接封IP** - -> 访问地址: [http://43.138.9.96/](http://43.138.9.96/) - -> 登录账户 admin/admin123 - -> Admin监控中心 ruoyi/123456 - -> 任务调度中心 admin/123456 diff --git a/ruoyi-admin/src/main/resources/static/common/pr.md b/ruoyi-admin/src/main/resources/static/common/pr.md deleted file mode 100644 index e9684dd4..00000000 --- a/ruoyi-admin/src/main/resources/static/common/pr.md +++ /dev/null @@ -1,37 +0,0 @@ -# 如何提交PR贡献代码 -- - - -### 步骤一 Fork项目到自己仓库 - -![输入图片说明](https://foruda.gitee.com/images/1673427084798343408/142a55d0_1766278.png "屏幕截图") - -### 步骤二 基于dev分支 新建一个此PR功能点的专属分支 - -![输入图片说明](https://foruda.gitee.com/images/1673427220695789412/14c4f4ff_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1673427193964585607/16ea99d9_1766278.png "屏幕截图") - -### 步骤三 使用Git工具 将自己仓库的项目拉去到本地做代码编写 - -![输入图片说明](https://foruda.gitee.com/images/1673427313201488937/f2df59bf_1766278.png "屏幕截图") - -### 步骤四 使用Idea打开项目 切换到新建的功能分支 - -![输入图片说明](https://foruda.gitee.com/images/1673427394686229310/c479a5a5_1766278.png "屏幕截图") - -### 步骤五 将编写好的代码 提交到自己的远程仓库 - -![输入图片说明](https://foruda.gitee.com/images/1673427519150795591/d88c2bc9_1766278.png "屏幕截图") - -### 步骤六 创建PR申请(此操作在自己仓库或者要PR的仓库都可以) - -![输入图片说明](https://foruda.gitee.com/images/1673427616155043776/fe2ce097_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1673427865031025513/0f58a137_1766278.png "屏幕截图") - -### 步骤七 等待作者评审 按要求更改 直到没有问题后被作者合并 - -![输入图片说明](https://foruda.gitee.com/images/1673428029932524584/93234628_1766278.png "屏幕截图") - -### 评审期间 如需对PR内容做更改 直接在新功能分支提交代码即可 -### 无需重复提交PR申请 这边会自动比对两个分支的差异 - -![输入图片说明](https://foruda.gitee.com/images/1673428054139366497/4ecb6e98_1766278.png "屏幕截图") - diff --git a/ruoyi-admin/src/main/resources/static/common/user_register.md b/ruoyi-admin/src/main/resources/static/common/user_register.md deleted file mode 100644 index 9c221cd1..00000000 --- a/ruoyi-admin/src/main/resources/static/common/user_register.md +++ /dev/null @@ -1,80 +0,0 @@ -# 使用者登记 -- - - -**使用此开源项目的公司或者组织** -> Vue版本登记地址: https://gitee.com/dromara/RuoYi-Vue-Plus/issues/I4QP39 - -> Cloud版本登记地址: https://gitee.com/dromara/RuoYi-Cloud-Plus/issues/I4VJ7G - -| 公司名 | 官网 | LOGO | -|-------------------|:-------------------------------|----------------------------------------------------------------------------------------------------------------| -| 中国联通(长春分公司) | http://www.10010.com | | -| 中国电信(湖南分公司) | http://www.189.cn/hn/ | | -| 南京感知信息技术有限公司 | https://njgzxx.cn/ | | -| 陕西骏景索道运营管理有限公司 | https://www.junjingsuodao.com/ | | -| 悠码科技有限公司 | https://orise.trytowish.cn/ | | -| 苏州龙的信息系统股份有限公司 | http://www.longdayinfo.com/ | | -| 北京数通智达科技有限公司 | http://www.bzdtech.com/ | | -| 广州六六七七科技有限公司 | https://artiversehub.ai/ | | -| 宁波三品软件科技有限公司 | http://nbsanpin.com/ | | -| 北京御一科技信息技术有限公司 | https://www.yudoctor.com | | -| 成都卡恩特医疗科技有限公司 | http://www.scknot.com | | -| 无锡科艾思科技有限公司 | https://www.kyoeis.com | | -| 深圳市海联天下科技有限公司 | www.sealinkin.com | | -| 上海非定义旅游服务有限公司 | http://www.anonymity.love/ | | -| 重庆威爱云科技有限公司 | https://www.51vive.com | | -| 中城智联(成都)创新科技有限公司 | http://www.zc-zl.com/ | | -| 浙江海亮股份有限公司 | https://www.hailiangstock.com | | -| 河北雄安山禾咨询工程有限公司 | https://shanheqei.club/ | | -| 数舵(河北雄安)信息科技有限公司 | http://www.shuduokeji.com | | -| 南昌鼎欣科技股份有限公司 | https://www.openzt.com | | -| 东莞市码载网络科技有限公司 | https://www.codeload.top | | -| 北京农信通科技有限责任公司 | http://www.nxt.com.cn | | -| 中康腾华网络科技(重庆)有限公司 | https://www.zkthwlkj.com/ | | -| 杭州码恒信息科技有限公司 | http://www.mh-barcode.com/ | | -| 南京晶益科技有限公司 | https://www.nanjingjingyi.com/ | | -| 合肥智享亿云科技有限公司 | http://www.izxyy.com | | -| 锡简科技 | https://www.xj-fast.com | | -| 福建亘前科技有限公司 | https://genqian.top | | -| 北京联宇信通科技有限公司 | http://www.lyxtkj.com/ | | -| 厦门市熵时光科技有限公司 | https://www.xetsoft.com | | -| 广州润沁教育科技有限公司 | https://www.ca163.net | | -| 广东乐善智能装备股份有限公司 | https://www.china-leshan.com/ | | -| 数字江西科技有限公司 | https://www.digitaljx.com/ | | -| 上海极锐星瀚传感技术有限公司 | http://www.jrsensing.com/ | | -| 北京数影互联科技有限公司 | http://www.dataflying.top/ | | -| 广州创服信息科技有限公司 | https://www.cfkjcloud.com | | -| 茂名云智科技有限公司 | http://www.winzkj.com | | -| 成都时光旅迹科技有限公司 | https://www.ttmup.com/ | | -| 成都炫影全息科技有限公司 | http://xyqxgs.com | | -| 中山厚德快速模具有限公司 | http://hordrt.com | | -| 深圳市深南夙星科技有限公司 | http://www.szsnsx.com/ | | -| 陕西华恒军创信息科技有限公司 | http://hhjc.cc | | -| 河南小牛信息科技有限公司 | http://www.hnxn888.com/ | | -| 武汉华智讯网络信息技术有限公司 | http://www.xun188.com | | -| 易税信息技术有限公司 | https://www.etax.top | | -| 广西华景城建筑设计有限公司 | http://www.hjcadc.com | | -| 铭创科技有限公司 | https://www.mcck.cn/ | | -| 西安鼎慧网络科技有限公司 | | | -| 营口鼎瑞网络科技有限公司 | | | -| 南昌漫库书店有限公司 | | | -| 广西文韬智能科技有限公司 | | | -| 贵州亿瑞祺科技有限公司 | | -| 贵州新绿视界环保科技有限公司 | | -| 湖南智才伯乐数据科技有限公司 | | -| 德州商储超市有限公司 | | -| 曲沃亿分科技中心 | | -| 南京杰度信息技术有限公司 | | -| 武汉忆秋科技有限公司 | | -| 济南千惠网络科技有限公司 | | -| 江苏泛联科技有限公司 | | -| 沈阳市果冻网络信息科技有限责任公司 | | -| 灵劲科技有限公司 | | -| 亿世达餐饮管理(北京)有限公司 | | -| 深圳市凯帝电子商务有限公司 | | -| 成都数智源蓉卡科技有限公司 | | -| 上海振福信息科技有限公司 | | -| 重庆六客会科技有限公司 | | -| 无限创优(西安)科技有限公司 | | -| 惠族网络科技发展有限公司 | | -| 纳森科技有限公司 | | - diff --git a/ruoyi-admin/src/main/resources/static/common/video.md b/ruoyi-admin/src/main/resources/static/common/video.md deleted file mode 100644 index 14fc2752..00000000 --- a/ruoyi-admin/src/main/resources/static/common/video.md +++ /dev/null @@ -1,85 +0,0 @@ -# 视频教程(联合出品) - -### 主讲与后期剪辑: `抓蛙师` - -抓蛙师简介: B站知名UP主 B站首页: https://space.bilibili.com/520725002 - -### 知识点统筹与内容审核: `疯狂的狮子Li` - -疯狂的狮子Li简介: RuoYi-Vue-Plus 与 RuoYi-Cloud-Plus 作者 - -## 已完结🎉🎉🎉 优惠价: 598(仅限前500名) ~~原价: 698~~ - -**注意: 视频采用 RuoYi-Vue-Plus 版本 4.X 分支讲解!!! (内容为通用技术与版本关联性不大)**
-**内容为框架内所用到的技术与设计原理(打破不知道、不会用、不知应用场景等问题)** - -课程简介: https://www.bilibili.com/video/BV16j411D7BX/ -
-试看课程: https://www.bilibili.com/video/BV1uS411P7JD/ -
-试看课程: https://www.bilibili.com/video/BV1vLbNeuESn/ -
-试看课程: https://www.bilibili.com/video/BV1xV4y127KM/ -
-试看课程: https://www.bilibili.com/video/BV1W5v8eBEgs/ -
-课程总结: https://www.bilibili.com/video/BV1734y1g7fk/ -
- -## 购买方式 - -**小本生意 用心录制 拒绝砍价 已更新到 236 集 课程完结**
-> 课程咨询或购买请联系 价格598
-> QQ: 906670865 (疯狂的狮子Li)
-> QQ: 770492966 (抓蛙师) - -## 购买前常见问题答疑 -> 问题1: 购买后是否有群可以解答问题
-> 答: 购买后有专属课程付费群(千人大群)讲师在线答疑 -> -> 问题2: 是否持续更新 如新版本功能
-> 答: 课程目录即为全部课程内容 以课程目录为准 明年大概会出二期来讲新版本内容
-> 因为持续更新会导致前面的技术老旧 新购买的人无法及时学习新技术
-> 故而采用分期出课程制度 已经购买过的老客户 再次购买下一次会给力度非常大的折扣 -> -> 问题3: 目前视频未全部录制完成 后续更新是否二次收费
-> 答: 视频目录即为全部视频内容 一次收费后续更新仍然可看直到视频全部更新完成(明年出二期课程不算在内) -> -> 问题4: 视频如何下载如何观看
-> 答: 视频文件已加密 采用专门的播放器(播放器只限制截图录屏等不限制其他软件使用) 由管理员发放授权码观看
-> 支持通过 百度云 或者 阿里云 网盘下载视频资源 -> -> 问题5: 视频平均时长和总时长大概多久
-> 答: 视频每集短的大概10分钟以上 长的大概40个分钟左右 平均时长20多分钟每集
-> 目前已经录制了236集总时长为80多个小时 -> -> 问题6: 是否有讲解 Cloud 版本相关内容
-> 答: 视频主要讲解内容为框架内所用到的技术与设计原理 无论什么版本 功能和设计都是一样的
-> Cloud 版本只是多了 alibaba 的几个组件完全可以B站自学 - -## 课程目录 - -![输入图片说明](https://foruda.gitee.com/images/1695105467795304336/58fcd6db_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1695105494170842444/10f98fed_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1695105523526589287/f131c614_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1695105547992880680/9f4137f3_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1695105560849590514/d19fad6a_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1695105586641712428/349a971b_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1695105595501187093/fb819d35_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1695105609163585390/833dd89c_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1695105630469565265/8dbba1d2_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1695105659037093525/09a4f6e1_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1695714493079698007/311980ee_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1697446957351573520/cab3617d_1766278.png "屏幕截图") - -## 学员观后感 - -| | | -|---------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| -| ![输入图片说明](https://foruda.gitee.com/images/1691386100129796781/44b69dae_1766278.jpeg "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1691386076834242484/a6073f7d_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1691386089186649583/98ac8b7c_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1691386108722171132/b937b23a_1766278.jpeg "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1695714607596127461/513b6893_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1692804549604261480/09ef12f6_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1692804541482477905/578e5448_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1695714614517941469/cac681fb_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1698225407961714462/4d271901_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1698225416488201339/30572e7f_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1698807198508085566/16c37a1b_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1698807208125772586/ceed632e_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1698807214013013096/ad3bc016_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1698807221010472627/72b10901_1766278.png "屏幕截图") | diff --git a/ruoyi-admin/src/main/resources/static/index.html b/ruoyi-admin/src/main/resources/static/index.html deleted file mode 100644 index 76e44328..00000000 --- a/ruoyi-admin/src/main/resources/static/index.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - plus-doc - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/_sidebar.md b/ruoyi-admin/src/main/resources/static/plus-ui/_sidebar.md deleted file mode 100644 index 00197250..00000000 --- a/ruoyi-admin/src/main/resources/static/plus-ui/_sidebar.md +++ /dev/null @@ -1,22 +0,0 @@ - -- **特别赞助** -- [![输入图片说明](https://foruda.gitee.com/images/1704162419429172656/d0521e59_1766278.png "2024-01-02=>2028-01-02")](http://ccflow.org/?frm=ryPlus) -- [![输入图片说明](https://foruda.gitee.com/images/1705569347386939952/3f187980_1766278.jpeg "2024-01-18=>2025-01-18")](http://www.shuduokeji.com) -- [![输入图片说明](https://foruda.gitee.com/images/1711681233267310022/2ffbcff2_1766278.png "2024-03-29=>2025-03-29")](https://www.jnpfsoft.com/index.html?from=plus-doc) - - -* **简介** - * [项目简介](/plus-ui/home.md) -* **开发文档** - * [通用方法](/plus-ui/devdoc/common_func.md) - * [开发规范](/plus-ui/devdoc/dev_norm.md) - * [请求流程](/plus-ui/devdoc/request_process.md) - * [路由使用](/plus-ui/devdoc/router_use.md) - * [组件使用](/plus-ui/devdoc/component_use.md) - * [权限使用](/plus-ui/devdoc/permissions_use.md) - * [页签缓存](/plus-ui/devdoc/page_cache.md) - * [使用图标](/plus-ui/devdoc/icon_use.md) - * [使用字典](/plus-ui/devdoc/dict_use.md) - * [使用参数](/plus-ui/devdoc/param_use.md) - * [异常处理](/plus-ui/devdoc/exception_handling.md) - * [内容复制](/plus-ui/devdoc/content_copy.md) diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/common_func.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/common_func.md deleted file mode 100644 index e359c03c..00000000 --- a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/common_func.md +++ /dev/null @@ -1,234 +0,0 @@ -# 通用方法 -- - - - -### $tab对象 -> `$tab`对象用于做页签操作、刷新页签、关闭页签、打开页签、修改页签等,它定义在`plugins/tab.ts`文件中,它有如下方法 -* 打开页签 - -```typescript -// 打开页签 -proxy?.$tab.openPage('/system/user'); -// 打开页签并指定页签标题 -proxy?.$tab.openPage('/system/user', '用户管理'); -proxy?.$tab.openPage('/system/user', '用户管理').then(() => { - // 执行结束的逻辑 -}) -``` - -* 修改页签 - -```typescript -// 修改当前页签 -const obj = Object.assign({}, route, { title: '自定义标题' }); -proxy?.$tab.updatePage(obj); -``` -* 关闭页签 - -```typescript -// 关闭当前 -proxy?.$tab.closePage(); -// 关闭指定页签 -const obj = { path: "/system/user", name: "User" }; -proxy?.$tab.closePage(obj); - -proxy?.$tab.closePage(obj).then(() => { - // 执行结束的逻辑 -}) -``` - -* 刷新页签 - -```typescript -// 刷新当前页签 -proxy?.$tab.refreshPage(); - -// 刷新指定页签 -const obj = { path: "/system/user", name: "User" }; -proxy?.$tab.refreshPage(obj); - -proxy?.$tab.refreshPage(obj).then(() => { - // 执行结束的逻辑 -}) -``` - -* 关闭所有页签 - -```typescript -proxy?.$tab.closeAllPage(); - -proxy?.$tab.closeAllPage().then(() => { - // 执行结束的逻辑 -}) -``` - -* 关闭左侧页签 - -```typescript -// 关闭当前页签的左侧页签 -proxy?.$tab.closeLeftPage(); - -// 关闭指定页签的左侧页签 -const obj = { path: "/system/user", name: "User" }; -proxy?.$tab.closeLeftPage(obj); - -proxy?.$tab.closeLeftPage(obj).then(() => { - // 执行结束的逻辑 -}) -``` - -* 关闭右侧页签 - -```typescript -// 关闭当前页签的右侧页签 -proxy?.$tab.closeRightPage(); - -// 关闭指定页签的右侧页签 -const obj = { path: "/system/user", name: "User" }; -proxy?.$tab.closeRightPage(obj); - -proxy?.$tab.closeRightPage(obj).then(() => { - // 执行结束的逻辑 -}) -``` - -* 关闭其他页签 - -```typescript -proxy?.$tab.closeOtherPage(); - -const obj = { path: "/system/user", name: "User" }; -proxy?.$tab.closeOtherPage(obj); - -proxy?.$tab.closeOtherPage(obj).then(() => { - // 执行结束的逻辑 -}) -``` - -### $modal对象 -> `$modal`对象用于做消息提示、通知提示、对话框提醒、二次确认、遮罩等,它定义在`plugins/modal.ts`文件中,它有如下方法 - -* 提供成功、警告和错误等反馈信息 - -```typescript -proxy?.$modal.msg("默认反馈"); -proxy?.$modal.msgError("错误反馈"); -proxy?.$modal.msgSuccess("成功反馈"); -proxy?.$modal.msgWarning("警告反馈"); -``` - -* 提供成功、警告和错误等提示信息 - -```typescript -proxy?.$modal.alert("默认提示"); -proxy?.$modal.alertError("错误提示"); -proxy?.$modal.alertSuccess("成功提示"); -proxy?.$modal.alertWarning("警告提示"); -``` - -* 提供成功、警告和错误等通知信息 - -```typescript -proxy?.$modal.notify("默认通知"); -proxy?.$modal.notifyError("错误通知"); -proxy?.$modal.notifySuccess("成功通知"); -proxy?.$modal.notifyWarning("警告通知"); -``` - -* 提供确认窗体信息 - -```typescript -proxy?.$modal.confirm('确认信息').then(function() { - ... -}).then(() => { - ... -}).catch(() => {}); -``` - -* 提供遮罩层信息 - -```typescript -// 打开遮罩层 -proxy?.$modal.loading("正在导出数据,请稍后..."); - -// 关闭遮罩层 -proxy?.$modal.closeLoading(); -``` - -### $auth对象 -> `$auth`对象用于验证用户是否拥有某(些)权限或角色,它定义在`plugins/auth.ts`文件中,它有如下方法 - -* 验证用户权限 - -```typescript -// 验证用户是否具备某权限 -proxy?.$auth.hasPermi("system:user:add"); -// 验证用户是否含有指定权限,只需包含其中一个 -proxy?.$auth.hasPermiOr(["system:user:add", "system:user:update"]); -// 验证用户是否含有指定权限,必须全部拥有 -proxy?.$auth.hasPermiAnd(["system:user:add", "system:user:update"]); -``` - -* 验证用户角色 - -```typescript -// 验证用户是否具备某角色 -proxy?.$auth.hasRole("admin"); -// 验证用户是否含有指定角色,只需包含其中一个 -proxy?.$auth.hasRoleOr(["admin", "common"]); -// 验证用户是否含有指定角色,必须全部拥有 -proxy?.$auth.hasRoleAnd(["admin", "common"]); -``` - -### $cache对象 -> `$cache`对象用于处理缓存。我们并不建议您直接使用`sessionStorage`或`localStorage`(vue3版本推荐使用useStorage),因为项目的缓存策略可能发生变化,通过`$cache`对象做一层调用代理则是一个不错的选择。`$cache`提供`session`和`local`两种级别的缓存,如下: - -| 对象名称 | 缓存类型 | -| -------- | ---------------------------------- | -| session | 会话级缓存,通过sessionStorage实现 | -| local | 本地级缓存,通过localStorage实现 | - - -**示例** - -```typescript -// local 普通值 -proxy?.$cache.local.set('key', 'local value') -console.log(proxy?.$cache.local.get('key')) // 输出'local value' - -// session 普通值 -proxy?.$cache.session.set('key', 'session value') -console.log(proxy?.$cache.session.get('key')) // 输出'session value' - -// local JSON值 -proxy?.$cache.local.setJSON('jsonKey', { localProp: 1 }) -console.log(proxy?.$cache.local.getJSON('jsonKey')) // 输出'{localProp: 1}' - -// session JSON值 -proxy?.$cache.session.setJSON('jsonKey', { sessionProp: 1 }) -console.log(proxy?.$cache.session.getJSON('jsonKey')) // 输出'{sessionProp: 1}' - -// 删除值 -proxy?.$cache.local.remove('key') -proxy?.$cache.session.remove('key') -``` - -### $download对象 - -> `$download`对象用于文件下载,它定义在`plugins/download.ts`文件中,它有如下方法 - -* 通过ossId从存储中下载文件 - -``` typescript -// 默认下载方法 -proxy?.$download.oss(ossId); -``` - -* 根据请求地址下载zip包 - -```typescript -const url = '/tool/gen/batchGenCode?tables=' + tableNames; -const name = 'ruoyi'; - -// 默认方法 -proxy?.$download.zip(url, name); -``` diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/component_use.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/component_use.md deleted file mode 100644 index 18886db5..00000000 --- a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/component_use.md +++ /dev/null @@ -1,55 +0,0 @@ -# 组件使用 -- - - - -vue 注册组件的两种方式 -在 `@/components` 下创建的.vue文件自动为全局组件,可直接在任意位置使用。 - -### 局部注册 -在对应页使用`components`注册组件。 -```typescript - - - -``` - -### 全局注册 -我们可以使用[ Vue 应用实例](https://cn.vuejs.org/guide/essentials/application.html)的 `.component()` 方法,让组件在当前 Vue 应用中全局可用。 -```typescript -import { createApp } from 'vue' - -const app = createApp({}) - -app.component( - // 注册的名字 - 'MyComponent', - // 组件的实现 - { - /* ... */ - } -) -``` -如果使用单文件组件,你可以注册被导入的 `.vue` 文件: -```typescript -import MyComponent from './App.vue' - -app.component('MyComponent', MyComponent) -``` -`.component()` 方法可以被链式调用: -```typescript -app - .component('ComponentA', ComponentA) - .component('ComponentB', ComponentB) - .component('ComponentC', ComponentC) -``` -全局注册的组件可以在此应用的任意组件的模板中使用: -```Typescript -// 这在当前应用的任意组件中都可用 - - - -``` -所有的子组件也可以使用全局注册的组件,这意味着这三个组件也都可以在彼此内部使用。 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/content_copy.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/content_copy.md deleted file mode 100644 index a4150d72..00000000 --- a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/content_copy.md +++ /dev/null @@ -1,4 +0,0 @@ -# 内容复制 -- - - - -文档建设中 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/dev_norm.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/dev_norm.md deleted file mode 100644 index de714a13..00000000 --- a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/dev_norm.md +++ /dev/null @@ -1,16 +0,0 @@ -# 开发规范 -- - - - -### 新增view -> 在`@/views`文件下创建对应的文件夹,一般性一个路由对应一个文件, 该模块下的功能就建议在本文件夹下创建一个新文件夹,各个功能模块维护自己的`utils`或`components`组件。 - -### 新增api -> 在`@/api`文件夹下创建本模块对应的api服务。 -> 在api服务同级创建`types.ts`类型声明文件。 - -### 新增组件 -> 在全局的`@/components`写一些全局的组件,如富文本,各种搜索组件,封装的分页组件等等能被公用的组件。 每个页面或者模块特定的业务组件则会写在当前`@/views`下面。 -如:`@/views/system/user/components/xxx.vue`。这样拆分大大减轻了维护成本。 - -### 新增样式 -> 页面的样式和组件是一个道理,全局的`@/style`放置一下全局公用的样式,每一个页面的样式就写在当前 views下面,请记住加上scoped 就只会作用在当前组件内了,避免造成全局的样式污染。 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/dict_use.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/dict_use.md deleted file mode 100644 index 7c6f9ba5..00000000 --- a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/dict_use.md +++ /dev/null @@ -1,4 +0,0 @@ -# 使用字典 -- - - - -文档建设中 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/exception_handling.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/exception_handling.md deleted file mode 100644 index 8de87fa2..00000000 --- a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/exception_handling.md +++ /dev/null @@ -1,4 +0,0 @@ -# 异常处理 -- - - - -文档建设中 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/icon_use.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/icon_use.md deleted file mode 100644 index 923e66ae..00000000 --- a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/icon_use.md +++ /dev/null @@ -1,4 +0,0 @@ -# 使用图标 -- - - - -文档建设中 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/page_cache.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/page_cache.md deleted file mode 100644 index 0531b465..00000000 --- a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/page_cache.md +++ /dev/null @@ -1,4 +0,0 @@ -# 页签缓存 -- - - - -文档建设中 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/param_use.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/param_use.md deleted file mode 100644 index 0cd93759..00000000 --- a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/param_use.md +++ /dev/null @@ -1,4 +0,0 @@ -# 使用参数 -- - - - -文档建设中 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/permissions_use.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/permissions_use.md deleted file mode 100644 index e18642f4..00000000 --- a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/permissions_use.md +++ /dev/null @@ -1,4 +0,0 @@ -# 权限使用 -- - - - -文档建设中 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/request_process.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/request_process.md deleted file mode 100644 index 146f7a8c..00000000 --- a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/request_process.md +++ /dev/null @@ -1,65 +0,0 @@ -# 请求流程 -- - - - -### 交互流程 -一个完整的前端UI交互到服务器端处理流程是这样的: - -1. UI 组件交互操作; -2. 调用统一管理的 api service 请求函数; -3. 使用封装的 request.js 发送请求; -4. 获取服务端返回; -5. 更新 data; - -为了方便管理维护,统一的请求处理都放在`@/src/api`文件夹中,并且一般按照`model`维度进行拆分文件,如: -``` -api/ - system/ - user/ - index.ts - types.ts - role/ - index.ts - types.ts - monitor/ - operlog/ - index.ts - types.ts - logininfor/ - index.ts - types.ts - ... -``` -> **提示** -> 其中`@/src/utils/request.ts`是基于 axios 的封装,便于统一处理 POST,GET 等请求参数,请求头,以及错误提示信息等。 它封装了全局request拦截器、response拦截器、统一的错误处理、统一做了超时处理、baseURL设置等。 - -### 请求示例 -```typescript -// @/api/system/user/index.ts -import request from '@/utils/request'; -import { AxiosPromise } from 'axios'; -import { UserQuery, UserVO } from './types'; - -export const listUser = (query: UserQuery): AxiosPromise => { - return request({ - url: '/system/user/list', - method: 'get', - params: query - }); -}; - -// @/views/system/user/index.vue -import api from '@/api/system/user'; -const res = await api.listUser(proxy?.addDateRange(queryParams.value, dateRange.value)); -``` -> **提示** -> 如果有不同的`baseURL`,直接通过覆盖的方式,让它具有不同的`baseURL`。 -> ```typescript -> export const listUser = (query: UserQuery): AxiosPromise => { -> return request({ -> url: '/system/user/list', -> method: 'get', -> params: query, -> baseURL: process.env.BASE_API -> }); -> }; -> ``` diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/router_use.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/router_use.md deleted file mode 100644 index b13812bc..00000000 --- a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/router_use.md +++ /dev/null @@ -1,82 +0,0 @@ -# 路由使用 -- - - - -框架的核心是通过路由自动生成对应导航,所以除了路由的基本配置,还需要了解框架提供了哪些配置项。 -### 路由配置 -```typescript -// 当设置 true 的时候该路由不会在侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1 -hidden: true // (默认 false) - -//当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 -redirect: 'noRedirect' - -// 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 -// 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面 -// 若你想不管路由下面的 children 声明的个数都显示你的根路由 -// 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由 -alwaysShow: true - -name: 'router-name' // 设定路由的名字,一定要填写不然使用时会出现各种问题 -query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数 -roles: ['admin', 'common'] // 访问路由的角色权限 -permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限 - -meta: { - title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字 - icon: 'svg-name' // 设置该路由的图标,支持 svg-class,也支持 el-icon-x element-ui 的 icon - noCache: true // 如果设置为true,则不会被 缓存(默认 false) - breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示(默认 true) - affix: true // 如果设置为true,它则会固定在tags-view中(默认 false) - - // 当路由设置了该属性,则会高亮相对应的侧边栏。 - // 这在某些场景非常有用,比如:一个文章的列表页路由为:/article/list - // 点击文章进入文章详情页,这时候路由为/article/1,但你想在侧边栏高亮文章列表的路由,就可以进行如下设置 - activeMenu: '/article/list' -} -``` -**普通示例** -```json -{ - path: '/system/test', - component: Layout, - redirect: 'noRedirect', - hidden: false, - alwaysShow: true, - meta: { title: '系统管理', icon : "system" }, - children: [{ - path: 'index', - component: (resolve) => require(['@/views/index'], resolve), - name: 'Test', - meta: { - title: '测试管理', - icon: 'user' - } - }] -} -``` -**外链示例** -```json -{ - path: 'http://ruoyi.vip', - meta: { title: '若依官网', icon : "guide" } -} -``` -### 静态路由 -代表那些不需要动态判断权限的路由,如登录页、404、等通用页面,在`@/router/index.ts`配置对应的公共路由。 -### 动态路由 -代表那些需要根据用户动态判断权限并通过addRoutes动态添加的页面,在`@/store/modules/permission.ts`加载后端接口路由配置。 -> **提示** -> * 动态路由可以在系统管理-菜单管理进行新增和修改操作,前端加载会自动请求接口获取菜单信息并转换成前端对应的路由。 -> * 动态路由在生产环境下会默认使用路由懒加载,实现方式参考loadView方法的判断。 -### 常用方法 -想要跳转到不同的页面,使用`router.push`方法 -```Typescript -const router = useRouter(); -router.push({ path: "/system/user" }); -``` -跳转页面并设置请求参数,使用`query`属性 -```Typescript -const router = useRouter(); -router.push({ path: "/system/user", query: {id: "1", name: "若依"} }); -``` -更多使用可以参考[vue-router](https://router.vuejs.org/zh/)官方文档。 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/home.md b/ruoyi-admin/src/main/resources/static/plus-ui/home.md deleted file mode 100644 index b389b5ca..00000000 --- a/ruoyi-admin/src/main/resources/static/plus-ui/home.md +++ /dev/null @@ -1,53 +0,0 @@ -# 项目简介 - ---- - -## 平台简介 - -- 本仓库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) 版本。 -- 配套后端代码仓库地址 -- [RuoYi-Vue-Plus 5.X(注意版本号)](https://gitee.com/dromara/RuoYi-Vue-Plus) -- [RuoYi-Cloud-Plus 2.X(注意版本号)](https://gitee.com/dromara/RuoYi-Cloud-Plus) - -## 前端运行 - -```bash -# 克隆项目 -git clone https://gitee.com/JavaLionLi/plus-ui.git - -# 安装依赖 -npm install --registry=https://registry.npmmirror.com - -# 启动服务 -npm run dev - -# 推荐使用yarn或pnpm包管理工具 -# 构建测试环境 yarn build:stage -# 构建生产环境 yarn build:prod -# 前端访问地址 http://localhost:80 -``` - -## 后端改造 - -参考后端代码内 `ruoyi-gen/resources/vm/vue/v3/readme.txt` 说明 - -## 内置功能 - -1. 租户管理:配置系统租户,支持 SaaS 场景下的多租户功能。 -2. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 -3. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 -4. 岗位管理:配置系统用户所属担任职务。 -5. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 -6. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 -7. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。 -8. 参数管理:对系统动态配置常用参数。 -9. 通知公告:系统通知公告信息发布维护。 -10. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 -11. 登录日志:系统登录日志记录查询包含登录异常。 -12. 在线用户:当前系统中活跃用户状态监控。 -13. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 -14. 代码生成:前后端代码的生成(java、html、xml、sql)支持 CRUD 下载 。 -15. 系统接口:根据业务代码自动生成相关的 api 接口文档。 -16. 服务监控:监视当前系统 CPU、内存、磁盘、堆栈等相关信息。 -17. 缓存监控:对系统的缓存信息查询,命令统计等。 -18. 在线构建器:拖动表单元素生成相应的 HTML 代码。(TS 版本正在开发中。) diff --git a/ruoyi-admin/src/main/resources/static/questions/_sidebar.md b/ruoyi-admin/src/main/resources/static/questions/_sidebar.md deleted file mode 100644 index 2d74fb20..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/_sidebar.md +++ /dev/null @@ -1,34 +0,0 @@ - -- **特别赞助** -- [![输入图片说明](https://foruda.gitee.com/images/1704162419429172656/d0521e59_1766278.png "2024-01-02=>2028-01-02")](http://ccflow.org/?frm=ryPlus) -- [![输入图片说明](https://foruda.gitee.com/images/1705569347386939952/3f187980_1766278.jpeg "2024-01-18=>2025-01-18")](http://www.shuduokeji.com) -- [![输入图片说明](https://foruda.gitee.com/images/1711681233267310022/2ffbcff2_1766278.png "2024-03-29=>2025-03-29")](https://www.jnpfsoft.com/index.html?from=plus-doc) - - - -* **常见问题** - * [Lombok注解爆红](/questions/lombok.md) - * [如何使用Tomcat](/questions/use_tomcat.md) - * [如何使用druid连接池](/questions/use_druid.md) - * [vue与boot整合部署](/questions/deploy_vue.md) - * [导入excel实体类为空](/questions/import_excel.md) - * [如何同步项目更新](/questions/synchronous_update.md) - * [ParseException SQL解析异常](/questions/parse_exception.md) - * [swagger相关问题](/questions/swagger.md) - * [实体bean为空问题](/questions/bean_null.md) - * [Redis 报错 Permission denied](/questions/permission_denied.md) - * [关于HTTPS配置](/questions/https_config.md) - * [放行接口提示认证失败](/questions/identify_fail.md) - * [打包jar运行报错](/questions/jar_run_fail.md) - * [如何指定dubbo注册ip](/questions/dubbo_ip.md) - * [Sentinel页面404问题](/questions/sentinel_404.md) - * [无法读取nacos配置](/questions/nacos_read_fail.md) - * [接口文档对接knife4j](/questions/kinfe4j.md) - * [不支持ST请求](/questions/st_not_support.md) - * [Only one connection receive subscriber allowed](/questions/only_one_subscriber.md) - * [nacos 报错 The Raft Group [naming_instance_metadata]](/questions/nacos_naming_instance_metadata.md) - * [unable to read meta-data for class xxx](/questions/read_metadata.md) - * [JCE cannot authenticate the provider BC](/questions/jce_cannot.md) - * [关于请求响应参数解密](/questions/api_encrypt.md) - * [关于登录调试步骤](/questions/login_step.md) - * [如何对接国产数据库](/questions/domestic_databases.md) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/api_encrypt.md b/ruoyi-admin/src/main/resources/static/questions/api_encrypt.md deleted file mode 100644 index 95b516d4..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/api_encrypt.md +++ /dev/null @@ -1,148 +0,0 @@ -# 关于请求响应参数解密 ---- -## 1:前端加密请求 - -![输入图片说明](https://foruda.gitee.com/images/1717033672316716771/8e30a2f1_4959041.png "屏幕截图") - -通过控制台获取加密结果: - -![输入图片说明](https://foruda.gitee.com/images/1717033792384655437/900a0e0d_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1717033896868612970/55581f0a_4959041.png "屏幕截图") - - -加密密钥: - -``` -PAg/fZzpV/cz0T1fMUJMJo/LEZvwVLb4bZgtCHkbB6FQAJWlLm/RLKtQ5fOo1blMjAkY+9ryWhsAfCqoMPTU4w== -``` - -请求参数加密结果: - -``` -F+Qxq6PzShcudDsUZHhp50lA67eBeTe63x5uGbdm/HJGgcDmjKncUk5VQm0evD8pz1sbmCbmmSl3X1D07K/qgHvP1YhjYSRBJf/M0GTfMkfOZqIkOtvfE5Z6fSFd8RYf6ji/qYxAmCiRmP/uADyJUAoBY1gMi5+zuvyHH3In/FyoFeD0rmJWvO4o4fn3n5GElHMWbP0O/HWPfgHFfg1F7bZQPuf4zAuDKQIqUG3jJTem3O97kAbTWw6lSSuYi1/8tV4cE9rq8SMSjx36/ZLSog== -``` - -### 解密步骤 - -1. 使用配置文件私钥对加密密钥解密 - -```java -// 参数说明: -// requestKey:即请求标头加密密钥 -// privateKey:application.yml 配置文件私钥 -String decryptByRsa = EncryptUtils.decryptByRsa(requestKey, privateKey); -``` - -2. 对步骤一结果进行 Base64 解密,得到 AES 加密密钥 - -```java -String aesPassword = EncryptUtils.decryptByBase64(decryptByRsa); -``` - -3. 使用步骤二得到的密钥,对请求参数进行解密 - -```java -String decryptBody = EncryptUtils.decryptByAes(requestBody, aesPassword); -``` - -得到解密请求参数(已格式化): - -```json -{ - "tenantId": "000000", - "username": "admin", - "password": "admin123", - "rememberMe": false, - "uuid": "a39962b22c874f60872ef5db1cd811f5", - "code": "5", - "clientId": "e5cd7e4891bf95d1d19206ce24a7b32e", - "grantType": "password" -} -``` - -|参数名|说明| -|---|---| -|tenantId| 租户id | -|username| 用户名 | -|password| 密码 | -|rememberMe| 记住密码 | -|uuid| - | -|code| 验证码结果 | -|clientId| 客户端id(表 sys_client) | -|grantType| 授权类型(表 sys_client) | - -## 2:后端加密响应 - -对请求使用了注解 `@ApiEncrypt(response = true)` - -![输入图片说明](https://foruda.gitee.com/images/1717035066844744866/2286b394_4959041.png "屏幕截图") - -通过控制台获取加密结果: - -![输入图片说明](https://foruda.gitee.com/images/1717035156784270596/156f2aa7_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1717035193189175688/214631e5_4959041.png "屏幕截图") - -加密密钥: - -``` -MXnKYnXcXeFYWKZg8utuhDtbz54cPDcov11E1KT5l19/vMt37d4NhzzwBWnqug72SOgOK5URGaWPJSs9VdaP0Q== -``` - -响应参数加密结果: - -``` -70 O63EMmwvbAyWPqDDmVOGTy+BOQnIVgKInMFNRtp8Zwzs8DEL20VgL2IslYrL8bc1u7lPhYNU/6 Q3iTYebm4EokwiG+styaT+LO3M9bUimggoAGpBTW8gCRF/34 kJaOITSRqYqYcXIJKn73+Gqn7jevyKUHyRXog/3 q/PlBdmUjNiB4gtxlOO/Vm+4 o+0 W4jcEe0xwwzV91+Ze3S6Eu/1 XN21g0iOsYT34emv/vhd9Hy3p5LfJlAHvn96x/c3MQBQUU32uM3Vkk3o6IpVHjJljE64gnGximSwB9vrmMA21xX+fq9HYioumknmDDbaY/JAKh32CDgn5M5hdaIklf08sU38r1IyvipySzrHX+ci9GmOZhP2ttCtoZ7SGvFFbNEuyojssxwxXEmJHAsG/OhIAeRXMUr3+dzDJ++XvvMuMgNJR0BMldNydFAjNOQEszgcVM1QEGwxfW5rElW8VxQaaqPyDATX+y2JrK1vdKxxdI/hF5dGpQMdU4FAEhHIftoIbD/FH4XcWJamZjJpbVtZvTkFYpbhiU7sz9MICSuKwaoSFJ8JGANc0bDdVoWpA8sXi7a27IM0pDzk9gD/FADcFGHXxPYUhENkXiUcnmg5LSdigiY4J6HrqEJdH6zNSwoGubcsXhiPdlB3V0DqcLAHFt+GYj5lcxZeqUAmixGVGCV7gSBWNiyo9/NnXcynA/EIlV3OZIvgzjWxiKzcVJ1HOKoXGEcg3Q54QNh5pCqEa7AtqVkKO7/Ffgg8nSEeCdJPzTV7zmr3n94Hn671OL8A== -``` - -### 解密步骤 - -1. 使用前端配置文件私钥对加密密钥解密 - -```java -// 参数说明: -// responseKey:即响应标头加密密钥 -// privateKey:前端 .env.development | .env.production 配置文件私钥,注意和后端私钥区分 -String decryptByRsa = EncryptUtils.decryptByRsa(responseKey, privateKey); -``` - -2. 对步骤一结果进行 Base64 解密,得到 AES 加密密钥 - -```java -String aesPassword = EncryptUtils.decryptByBase64(decryptByRsa); -``` - -3. 使用步骤二得到的密钥,对响应参数进行解密 - -```java -String decryptBody = EncryptUtils.decryptByAes(responseBody, aesPassword); -``` - -得到解密请求参数(已格式化): - -```json -{ - "code": 200, - "msg": "操作成功", - "data": { - "scope": null, - "openid": null, - "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJzeXNfdXNlcjoxIiwicm5TdHIiOiJjOVNWU1hRRVY4QVhFRkt4b2FrbndSSWxPczd4ajdRZCIsImNsaWVudGlkIjoiZTVjZDdlNDg5MWJmOTVkMWQxOTIwNmNlMjRhN2IzMmUiLCJ0ZW5hbnRJZCI6IjAwMDAwMCIsInVzZXJJZCI6MSwidXNlck5hbWUiOiJhZG1pbiIsImRlcHRJZCI6MTAzLCJkZXB0TmFtZSI6IueglOWPkemDqOmXqCJ9.YuaXPu6eTzJVkLyQC3ekzmPS_jXp50ykaIB2nWy11qM", - "refresh_token": null, - "expire_in": 604799, - "refresh_expire_in": null, - "client_id": "e5cd7e4891bf95d1d19206ce24a7b32e" - } -} -``` - -|参数名|说明| -|---|---| -|scope| 令牌权限 | -|openid| 用户 openid | -|access_token| 授权令牌 | -|refresh_token| 刷新令牌 | -|expire_in| 授权令牌 access_token 的有效期 | -|refresh_expire_in| 刷新令牌 refresh_token 的有效期 | -|clientId| 客户端id(表 sys_client) | \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/bean_null.md b/ruoyi-admin/src/main/resources/static/questions/bean_null.md deleted file mode 100644 index bf04048c..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/bean_null.md +++ /dev/null @@ -1,10 +0,0 @@ -# 实体bean为空问题 -- - - -### 问题排查 - -检查是否存在 `链式调用` 注解 `@Accessors(chain = true)` 删除即可 - -### 原因 -java 规范 set 返回值为 `void` 链式调用 set 返回值为 `this`
-故多数框架底层使用 jdk 工具导致找不到 set 方法
-例如: `easyexcel` `cglib` `mybatis` 等 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/deploy_vue.md b/ruoyi-admin/src/main/resources/static/questions/deploy_vue.md deleted file mode 100644 index 348a1680..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/deploy_vue.md +++ /dev/null @@ -1,13 +0,0 @@ -# 关于vue与boot整合部署 -- - - -* [前端静态资源如何整合到后端访问](https://doc.ruoyi.vip/ruoyi-vue/other/faq.html#前端静态资源如何整合到后端访问) - -3.X 需在 `pom.xml` 增加资源过滤排除 - -```xml - - src/main/resources/页面目录 - - false - -``` diff --git a/ruoyi-admin/src/main/resources/static/questions/domestic_databases.md b/ruoyi-admin/src/main/resources/static/questions/domestic_databases.md deleted file mode 100644 index e79762ba..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/domestic_databases.md +++ /dev/null @@ -1,41 +0,0 @@ -# 如何对接国产数据库 - -> 1. 框架采用 mybatis-plus 几乎支持大部分市面上的数据库且框架内几乎没有sql语句存在 -
-所以不用担心兼容性问题(顶多就是有一些关键字什么的 对接很简单) -
-> 2. 国产数据库大多都兼容主流三大数据库 mysql oracle postgresql -
-例如 达梦兼容oracle 人大金仓兼容mysql oceanbase兼容mysql 等等 - -# 对接方式 - -### 这里用 `达梦` 数据库为例 - -1.首先增加 jdbc依赖包 `vue版本在ruoyi-admin模块下` `cloud版本在ruoyi-common-mybatis模块下` - -![输入图片说明](https://foruda.gitee.com/images/1723288594335994875/216ae8e7_1766278.png "屏幕截图") - -2.在配置文件yml内配置数据库连接 - -![输入图片说明](https://foruda.gitee.com/images/1723288760519808620/3db91ba5_1766278.png "屏幕截图") - -3.sql脚本使用框架内自带的sql文件根据兼容的数据库模式 例如 达梦用oracle的sql脚本 - -![输入图片说明](https://foruda.gitee.com/images/1723289018873298537/4d95c892_1766278.png "屏幕截图") - -4.在代码生成器内 增加对应的数据库生成器依赖 代码生成器使用 anyline 支持几百种数据库只需要增加对应的依赖即可 - -![输入图片说明](https://foruda.gitee.com/images/1723288974693848785/3e8fc61f_1766278.png "屏幕截图") - -这样基本就完成了所有需要做的事可以尝试启动项目了 - -5.如果项目启或者运行动过程中有sql报错 不要慌基本上都是一些关键字引起的 -
-例如 达梦内的`domain`就是关键字 在我们的`SysOssConfig`表内使用`domain`进行自定义的域名存储 -
-我们只需要在`SysOssConfig`实体类的`domain`属性增加一个注解即可解决此问题 -
-**注意: 各种数据库处理关键字的标识符不一样注意替换** - -![输入图片说明](https://foruda.gitee.com/images/1723289232470339283/480d5172_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/questions/dubbo_ip.md b/ruoyi-admin/src/main/resources/static/questions/dubbo_ip.md deleted file mode 100644 index 43cb2346..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/dubbo_ip.md +++ /dev/null @@ -1,18 +0,0 @@ -# 如何指定dubbo注册ip -- - - -## 重点说明 -以下方法指定IP必须是本地有网卡的自己可以访问的IP 不可以随意乱写
-(云服务器公网IP是没有网卡的) - -## 在`nacos`指定协议IP地址(全局生效) -```yml -dubbo: - protocol: - # 指定dubbo协议注册ip - host: 192.168.0.100 -``` - -## docker指定dubbo环境变量(单服务生效) - -![输入图片说明](https://foruda.gitee.com/images/1678981332028792584/7eeef9c5_1766278.png "屏幕截图") - diff --git a/ruoyi-admin/src/main/resources/static/questions/https_config.md b/ruoyi-admin/src/main/resources/static/questions/https_config.md deleted file mode 100644 index e590729e..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/https_config.md +++ /dev/null @@ -1,27 +0,0 @@ -# 关于HTTPS配置 -- - - -### 后端 HTTPS 改造 - -将申请的 `https` 证书放置到 `nginx` 对应目录内
-根据框架 `nginx https` 示例 更改后端代理为 `https`
- -![输入图片说明](https://foruda.gitee.com/images/1678981283573122208/87cf19ad_1766278.png "屏幕截图") - -### 监控中心 与 任务调度中心 改造 - -`监控中心` 与 `任务调度中心` 属于系统管控服务
-应在内网使用 不应该暴漏到外网 也无需配置 `https` - -更改 `系统 -> 菜单管理 -> 监控中心 与 任务调度中心` 菜单配置
-将其改为 `外链访问` 访问路径为 **注意: 如果是外网使用 url需配置为 http://外网ip:端口** - -![输入图片说明](https://foruda.gitee.com/images/1678981287686638349/3734f085_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1678981292545287978/f2471f97_1766278.png "屏幕截图") - -`nginx` 配置 `独立的端口` 进行反向代理即可访问(代理编写方式参考后端反向代理) - -### Minio https 改造 - -下方链接包含 minio+nginx 与 minio本身配置https 两种方案
-[终极版minio配置https教程](https://blog.csdn.net/Michelle_Zhong/article/details/126484358) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/identify_fail.md b/ruoyi-admin/src/main/resources/static/questions/identify_fail.md deleted file mode 100644 index 4e258067..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/identify_fail.md +++ /dev/null @@ -1,10 +0,0 @@ -# 放行接口提示认证失败 -- - - -## 可能的原因 -接口放行后不需要token即可访问
-但是没有token也就无法获取用户信息与鉴权 - -## 解决方案 -删除接口上的鉴权注解
-删除接口内获取用户信息功能
-删除数据库实体类 自动注入 `createBy` `updateBy` 因为会获取用户数据 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/import_excel.md b/ruoyi-admin/src/main/resources/static/questions/import_excel.md deleted file mode 100644 index 431863e8..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/import_excel.md +++ /dev/null @@ -1,4 +0,0 @@ -# 关于导入excel实体类为空 -- - - -* 禁止在导入实体使用 `lombok` 链式调用注解 `@Accessors(chain = true)` -* 会导致找不到 `set` 方法无法注入内容 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/jar_run_fail.md b/ruoyi-admin/src/main/resources/static/questions/jar_run_fail.md deleted file mode 100644 index cef9bcd2..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/jar_run_fail.md +++ /dev/null @@ -1,12 +0,0 @@ -# 打包jar运行报错问题 -- - - - -**常见于 windows 平台以命令方式启动** - -windows 平台默认编码为 GBK 所以读取到所有的配置都是乱码 - -## 解决方案 - -需要在命令增加 `-Dfile.encoding=utf-8` 指定文件编码 - -例如: `java -Dfile.encoding=utf-8 -jar ruoyi-xxx.jar` \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/jce_cannot.md b/ruoyi-admin/src/main/resources/static/questions/jce_cannot.md deleted file mode 100644 index a1baf9dd..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/jce_cannot.md +++ /dev/null @@ -1,3 +0,0 @@ -# 问题说明 由于 OracleJDK 强校验加密证书导致 - -解决方案 禁止使用 oraclejdk 更换为其他例如 openjdk \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/kinfe4j.md b/ruoyi-admin/src/main/resources/static/questions/kinfe4j.md deleted file mode 100644 index 5051a782..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/kinfe4j.md +++ /dev/null @@ -1,66 +0,0 @@ -# 对接前声明 - -经常有小伙伴希望可以对接 knife4j - -那么这里将介绍如何使用 框架生成的 openapi 对接 knife4j - -# 如何对接 - -**重点声明: 本框架生成标准openapi结构 如对接后遇到不好用等问题 皆与本框架无关** - -knife4j 本身提供了独立的文档中间件 可以零成本的介入 openapi - -文档地址: https://doc.xiaominfo.com/docs/middleware-sources - -**注意: 此组件应单独搞一个boot项目 不要往框架里做任何代码上的更改** - -使用文档提供的 Cloud 模式 对接咱们框架的 openapi 地址即可完成对接 - -![输入图片说明](https://foruda.gitee.com/images/1685953873117929554/22dce56e_1766278.png "屏幕截图") - -vue版本对接配置如下: - -```yml -knife4j: - enable-aggregation: true - cloud: - enable: true - routes: - - name: 演示模块 - uri: localhost:8080 - location: /v3/api-docs/1.演示模块 - - name: 系统模块 - uri: localhost:8080 - location: /v3/api-docs/2.系统模块 - - name: 代码生成模块 - uri: localhost:8080 - location: /v3/api-docs/3.代码生成模块 -``` - -cloud版本对接配置如下: - -```yml -knife4j: - enable-aggregation: true - cloud: - enable: true - routes: - - name: 演示模块 - uri: localhost:8080 - location: /demo/v3/api-docs - - name: 认证服务 - uri: localhost:8080 - location: /auth/v3/api-docs - - name: 资源服务 - uri: localhost:8080 - location: /resource/v3/api-docs - - name: 系统服务 - uri: localhost:8080 - location: /system/v3/api-docs - - name: 监控服务 - uri: localhost:8080 - location: /monitor/v3/api-docs - - name: 代码生成服务 - uri: localhost:8080 - location: /gen/v3/api-docs -``` \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/login_step.md b/ruoyi-admin/src/main/resources/static/questions/login_step.md deleted file mode 100644 index c1d4fcc9..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/login_step.md +++ /dev/null @@ -1,69 +0,0 @@ -# 关于登录调试步骤 - -## 1:关闭 api 接口加密 - -1. 修改后端配置文件 `application.yml` - -![输入图片说明](https://foruda.gitee.com/images/1717037518256330645/c5a9f0fc_4959041.png "屏幕截图") - -2. 修改前端配置文件 `.env.development` | `.env.production` - -![输入图片说明](https://foruda.gitee.com/images/1717037555118359683/0e73a369_4959041.png "屏幕截图") - -## 2:登录参数 - -![输入图片说明](https://foruda.gitee.com/images/1717038201634120005/e02882d3_4959041.png "屏幕截图") - -|参数名|说明| -|---|---| -|tenantId| 租户id | -|username| 用户名 | -|password| 密码 | -|rememberMe| 记住密码 | -|uuid| - | -|code| 验证码结果 | -|clientId| 客户端id(表 sys_client) | -|grantType| 授权类型(表 sys_client) | - -## 3:使用接口文档调试 - -### 3.1:使用接口文档请求 - -1. 配置接口文档([参考文档](/ruoyi-vue-plus/framework/association/doc)) -2. 请求接口 `http://localhost:8080/auth/login` - -![输入图片说明](https://foruda.gitee.com/images/1717039200581756307/97efbc9c_4959041.png "屏幕截图") - -### 3.2:使用 idea 请求 - -![输入图片说明](https://foruda.gitee.com/images/1717039459944753490/040d2b9d_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1717039534863944601/df91df67_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1717039598067298052/cc9fe61b_4959041.png "屏幕截图") - -### 3.3:获取验证码以及 uuid - -!> 验证码以及 uuid 获取方式: Redis | 控制台 - -方式一、Redis: - -![输入图片说明](https://foruda.gitee.com/images/1717040260329977942/42f7ed62_4959041.png "屏幕截图") - -> **如果没有验证码相关 key,说明已经过期被清理了,去前端页面刷新一下即可。** - -方式二、控制台: - -![输入图片说明](https://foruda.gitee.com/images/1717040428227070908/1ef7562a_4959041.png "屏幕截图") - -### 3.4:关闭验证码 - -如果嫌验证码太麻烦,可以关闭,修改后端配置文件 `application.yml` - -![输入图片说明](https://foruda.gitee.com/images/1717040533266608114/054fd984_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1717040745251872562/374267e8_4959041.png "屏幕截图") - -请求参数: - -![输入图片说明](https://foruda.gitee.com/images/1717040762860943102/81c9b44a_4959041.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/lombok.md b/ruoyi-admin/src/main/resources/static/questions/lombok.md deleted file mode 100644 index 47125153..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/lombok.md +++ /dev/null @@ -1,4 +0,0 @@ -# 关于lombok注解爆红 -- - - -* 已知 lombok 插件与 idea中文插件 存在兼容性问题 -* 移除中文插件或手动关闭idea检查 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/nacos_naming_instance_metadata.md b/ruoyi-admin/src/main/resources/static/questions/nacos_naming_instance_metadata.md deleted file mode 100644 index ae35d937..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/nacos_naming_instance_metadata.md +++ /dev/null @@ -1,35 +0,0 @@ -# nacos 报错 The Raft Group [naming_instance_metadata] -- - - -## Nacos 服务下线报错问题 - -问题描述: - -Nacos 服务管理 > 服务列表 > 详情 > 下线 报错 - - - -报错详情: - -``` -caused: errCode: 500, errMsg: do metadata operation failed ;caused: com.alibaba.nacos.consistency.exception.ConsistencyException: The Raft Group [naming_instance_metadata] did not find the Leader node;caused: The Raft Group [naming_instance_metadata] did not find the Leader node; -``` - - - -解决方案: - -**删除 Nacos 根目录下 data 文件夹下的 protocol 文件夹** - -(推荐使用全局搜索软件查询,windows 环境根目录一般在 C:\Users\用户名\nacos) - - - -问题原因: - -> Nacos 采用 raft 算法来计算 Leader,并且会记录上次启动的集群地址,所以当我们自己的服务器 IP 改变时(网络环境不稳定,如WIFI, IP 地址也经常变化),导致 raft 记录的集群地址失效,导致选 Leader 出现问题。 - - - -参考目录: - -[解决疑难问题之服务下线报:The Raft Group naming_instance_metadata\] did not find the Leader node; - 嘉美祥瑞 - 博客园 (cnblogs.com)](https://www.cnblogs.com/whl-jx911/p/16736625.html) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/nacos_read_fail.md b/ruoyi-admin/src/main/resources/static/questions/nacos_read_fail.md deleted file mode 100644 index f6cc36d9..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/nacos_read_fail.md +++ /dev/null @@ -1,15 +0,0 @@ -# 无法读取nacos配置 -- - - -### 检查 `group` 与 `namespace` 是否一致 - -如果未使用框架自带 `ry-config.sql` 文件进行配置 会导致 `namespace` 不一致 无法查询配置 - -### 检查 `8848` `9848` `9849` 端口是否开启可用 - -### 检查配置文件名是否一致 例如: "xxx" 与 "xxx.yml" 的区别 - -### 检查是否手动改过 `nacos` 数据库数据 - -`nacos` 数据表层层关联 不要自作聪明手动改数据库 - -已经改过的 需要重新导入 `ry-config.sql` 之后在页面进行改数据操作 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/only_one_subscriber.md b/ruoyi-admin/src/main/resources/static/questions/only_one_subscriber.md deleted file mode 100644 index f8d690e1..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/only_one_subscriber.md +++ /dev/null @@ -1,11 +0,0 @@ -# Only one connection receive subscriber allowed -- - - -## 问题原因 -**经多人反馈 共同点为全都是做`小程序开发`使用的`uniapp`发送的网络请求而出现这种问题** - -`uniapp` 错误设置 `Content-Type` 将所有请求类型全都设置成了 `json` 导致不该读body的请求也读取了body 最终导致报错 - -## 解决方案 - -方案1: 升级 1.4.0 已经对这种不合规发的请求做了兼容处理(被迫)
-方案2: `uniapp` 内的请求设置正确的 `Content-Type` diff --git a/ruoyi-admin/src/main/resources/static/questions/parse_exception.md b/ruoyi-admin/src/main/resources/static/questions/parse_exception.md deleted file mode 100644 index 67a7a114..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/parse_exception.md +++ /dev/null @@ -1,40 +0,0 @@ -# ParseException SQL解析异常 -- - - -## 异常内容 - -`net.sf.jsqlparser.parser.ParseException: Encountered unexpected token:` - -![输入图片说明](https://foruda.gitee.com/images/1678981169309778625/a17ff852_1766278.png "屏幕截图") - -此异常为 SQL 解析异常, 应检查 SQL 语句内是否包含 SQL 关键字 - -异常通常都会提供坐标 - -![输入图片说明](https://foruda.gitee.com/images/1678981173813116217/a6f9ee32_1766278.png "屏幕截图") - -检查报错 SQL 相关坐标位置 - -![输入图片说明](https://foruda.gitee.com/images/1678981179153564043/bf4912b4_1766278.png "屏幕截图") - -## 异常由来 -由 Mybatis-Plus 拦截器进行 SQL 解析导致
-常见拦截器导致问题 `TenantLineInnerInterceptor` `DataPermissionInterceptor` - -## 解决方案 - -> 将关键字增加标识符区别开 - -1.实体类字段处理(以下仅限于mysql 其他数据库方法各不相同) - -![输入图片说明](https://foruda.gitee.com/images/1678981183515542682/fccd85ad_1766278.png "屏幕截图") - -2.自定义 SQL 或 XML 处理 - -![输入图片说明](https://foruda.gitee.com/images/1678981187926917963/38437edb_1766278.png "屏幕截图") - -3.Mapper排除 -> 查看具体使用了哪些拦截器导致问题 使用忽略注解依次进行排除即可 - -![输入图片说明](https://foruda.gitee.com/images/1678981192902044584/fb1c41eb_1766278.png "屏幕截图") - - diff --git a/ruoyi-admin/src/main/resources/static/questions/permission_denied.md b/ruoyi-admin/src/main/resources/static/questions/permission_denied.md deleted file mode 100644 index 76d955db..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/permission_denied.md +++ /dev/null @@ -1,15 +0,0 @@ -# Redis 报错 Permission denied -- - - -### 此报错为无权限 - -需确保 redis 数据存储文件夹具有写权限 - -```shell -chmod 777 /docker/redis/data -``` - -没有写权限无法对数据进行存储 - -### 关于RDB报错 `/etc` 无权限问题 - -增加redis密码校验 无密码导致配置不安全 diff --git a/ruoyi-admin/src/main/resources/static/questions/read_metadata.md b/ruoyi-admin/src/main/resources/static/questions/read_metadata.md deleted file mode 100644 index b91165fd..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/read_metadata.md +++ /dev/null @@ -1,11 +0,0 @@ -# unable to read meta-data for class xxx -- - - -## 问题原因 - -此问题由改包名导致框架内组件 spring 的 spi 配置文件包名被改乱套 - -## 解决方案 - -更正组件包下的 spring spi 配置文件内的类包名 - -![输入图片说明](https://foruda.gitee.com/images/1668608724503582409/50a77b4b_1766278.jpeg "test.jpg") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/sentinel_404.md b/ruoyi-admin/src/main/resources/static/questions/sentinel_404.md deleted file mode 100644 index 7e51fb58..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/sentinel_404.md +++ /dev/null @@ -1,8 +0,0 @@ -# Sentinel页面404问题 -- - - -## 原因 -检查 `webapp` 目录是否为资源目录 低版本 `idea` 不会自动解析 -## 解决方案 -手动设置 `webapp` 为资源目录即可
- -![输入图片说明](https://foruda.gitee.com/images/1678981354612151228/52f2a886_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/questions/st_not_support.md b/ruoyi-admin/src/main/resources/static/questions/st_not_support.md deleted file mode 100644 index a3012805..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/st_not_support.md +++ /dev/null @@ -1,11 +0,0 @@ -# 不支持ST请求 -- - - -## 问题原因 -**经多人反馈 共同点为全都是做`小程序开发`使用的`uniapp`发送的网络请求而出现这种问题** - -`uniapp` 错误设置 `Content-Type` 将所有请求类型全都设置成了 `json` 导致不该读body的请求也读取了body 最终导致报错 - -## 解决方案 - -方案1: 升级 1.4.0 已经对这种不合规发的请求做了兼容处理(被迫)
-方案2: `uniapp` 内的请求设置正确的 `Content-Type` \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/swagger.md b/ruoyi-admin/src/main/resources/static/questions/swagger.md deleted file mode 100644 index 8b0a6e01..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/swagger.md +++ /dev/null @@ -1,3 +0,0 @@ -# 框架内没有任何swagger - -想使用接口文档功能 请查看框架接口文档说明 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/synchronous_update.md b/ruoyi-admin/src/main/resources/static/questions/synchronous_update.md deleted file mode 100644 index 70803f58..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/synchronous_update.md +++ /dev/null @@ -1,3 +0,0 @@ -# 如何同步项目更新 -- - - -参考文章: [关于如何同步更新开源项目](https://blog.csdn.net/qq_31360283/article/details/118345795) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/use_druid.md b/ruoyi-admin/src/main/resources/static/questions/use_druid.md deleted file mode 100644 index 77f3f605..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/use_druid.md +++ /dev/null @@ -1,20 +0,0 @@ -# 如何使用druid连接池 -- - - -## 为何移除druid - -性能低下 bug频发 内含fastjson问题众多 监控不支持集群(鸡肋) 不支持一些高版本数据库 社区活跃度冰点 - -### 性能对比图 -![输入图片说明](https://foruda.gitee.com/images/1667888745256002635/1bbd3481_1766278.png "屏幕截图") -### 包大小对比图 -![输入图片说明](https://foruda.gitee.com/images/1667888760611300040/87af8d82_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1667888766932068690/7b379298_1766278.png "屏幕截图") - -## 为何使用hikari(中文: 光) - -spring默认自带 代码量少结构简单 稳定可靠 性能突出(自行百度一堆测评) - -## 参考提交记录反向操作即可 - -https://gitee.com/dromara/RuoYi-Vue-Plus/commit/1f42bd3d22c104aaa2d780c20a555b5e467858bf
-https://gitee.com/dromara/RuoYi-Vue-Plus/commit/a63abbf268e4c0a60344f63b5cba828a1347e178 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/use_tomcat.md b/ruoyi-admin/src/main/resources/static/questions/use_tomcat.md deleted file mode 100644 index 113d239f..00000000 --- a/ruoyi-admin/src/main/resources/static/questions/use_tomcat.md +++ /dev/null @@ -1,9 +0,0 @@ -# 关于如何使用Tomcat -- - - -### 查看ruoyi-framework模块的pom.xml文件,根据注释更改依赖 - -![输入图片说明](https://foruda.gitee.com/images/1678981109106652929/0803004d_1766278.png "屏幕截图") - -### 查看ruoyi-admin模块中的application.yml文件,根据注释更改配置 - -![输入图片说明](https://foruda.gitee.com/images/1678981112652965294/dda8df86_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/_sidebar.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/_sidebar.md deleted file mode 100644 index 4580b86c..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/_sidebar.md +++ /dev/null @@ -1,70 +0,0 @@ - -- **特别赞助** -- [![输入图片说明](https://foruda.gitee.com/images/1704162419429172656/d0521e59_1766278.png "2024-01-02=>2028-01-02")](http://ccflow.org/?frm=ryPlus) -- [![输入图片说明](https://foruda.gitee.com/images/1705569347386939952/3f187980_1766278.jpeg "2024-01-18=>2025-01-18")](http://www.shuduokeji.com) -- [![输入图片说明](https://foruda.gitee.com/images/1711681233267310022/2ffbcff2_1766278.png "2024-03-29=>2025-03-29")](https://www.jnpfsoft.com/index.html?from=plus-doc) - - -* **简介** - * [项目简介](/ruoyi-cloud-plus/home.md) - * [更新日志](/ruoyi-cloud-plus/changlog.md) -* **快速开始** - * [项目初始化](/ruoyi-cloud-plus/quickstart/init.md) - * [1.X项目初始化](/ruoyi-cloud-plus/quickstart/1.Xinit.md) - * [工作流初始化](/ruoyi-cloud-plus/quickstart/worker_init.md) - * [idea环境配置](/ruoyi-cloud-plus/quickstart/idea_environment.md) - * [应用部署](/ruoyi-cloud-plus/quickstart/deploy.md) - * [扩展项目](/ruoyi-cloud-plus/quickstart/extend_project.md) - * [搭建SnailJob调度中心](/ruoyi-cloud-plus/quickstart/snail_job_init.md) - * [(废弃)搭建PowerJob调度中心](/ruoyi-cloud-plus/quickstart/power_job_init.md) -* **框架功能** - * [项目结构](/ruoyi-cloud-plus/framework/tree.md) - * [软件架构图](/ruoyi-cloud-plus/framework/architecture_diagram.md) - * 框架相关 - * [创建新服务](/ruoyi-cloud-plus/framework/association/new_module.md) - * [修改包名](/ruoyi-cloud-plus/framework/association/update_package_name.md) - * [接口文档](/ruoyi-cloud-plus/framework/association/doc.md) - * [修改应用路径](/ruoyi-cloud-plus/framework/association/update_url.md) - * [国际化](/ruoyi-cloud-plus/framework/association/i18n.md) - * [多团队开发](/ruoyi-cloud-plus/framework/association/collaboration.md) - * [内网鉴权](/ruoyi-cloud-plus/framework/association/inner_authentication.md) - * 基础功能 - * [系统用户相关](/ruoyi-cloud-plus/framework/basic/user.md) - * [权限控制](/ruoyi-cloud-plus/framework/basic/permissions_control.md) - * [导出功能](/ruoyi-cloud-plus/framework/basic/export.md) - * [导入功能](/ruoyi-cloud-plus/framework/basic/import.md) - * [参数校验](/ruoyi-cloud-plus/framework/basic/param_check.md) - * [代码生成](/ruoyi-cloud-plus/framework/basic/code_generate.md) - * [分页功能](/ruoyi-cloud-plus/framework/basic/page.md) - * [OSS功能](/ruoyi-cloud-plus/framework/basic/oss.md) - * [数据权限](/ruoyi-cloud-plus/framework/basic/permissions.md) - * [网关路由与放行](/ruoyi-cloud-plus/framework/basic/router_release.md) - * [多租户功能](/ruoyi-cloud-plus/framework/basic/tenant.md) - * [第三方授权功能](/ruoyi-cloud-plus/framework/basic/social.md) - * [客户端管理功能](/ruoyi-cloud-plus/framework/basic/client.md) - * 扩展功能 - * [多数据源](/ruoyi-cloud-plus/framework/extend/dynamic_datasource.md) - * [短信模块](/ruoyi-cloud-plus/framework/extend/sms.md) - * [邮件功能](/ruoyi-cloud-plus/framework/extend/mail.md) - * [防重幂等](/ruoyi-cloud-plus/framework/extend/idempotent.md) - * [数据脱敏](/ruoyi-cloud-plus/framework/extend/sensitive.md) - * [API加解密](/ruoyi-cloud-plus/framework/extend/api_encrypt.md) - * [数据加解密](/ruoyi-cloud-plus/framework/extend/encrypt.md) - * [翻译功能](/ruoyi-cloud-plus/framework/extend/translation.md) - * [WebSocket功能](/ruoyi-cloud-plus/framework/extend/websocket.md) - * 功能说明 - * [事务相关](/ruoyi-cloud-plus/framework/explain/transaction.md) - * [单元测试](/ruoyi-cloud-plus/framework/explain/test.md) - * [主键使用说明](/ruoyi-cloud-plus/framework/explain/key.md) - * [关于多表查询](/ruoyi-cloud-plus/framework/explain/about_join.md) -* **扩展功能** - * [ELK搭建](/ruoyi-cloud-plus/extend-function/elk.md) - * [ES搜索引擎](/ruoyi-cloud-plus/extend-function/es.md) - * [RabbitMQ搭建](/ruoyi-cloud-plus/extend-function/rabbitmq.md) - * [RocketMQ搭建](/ruoyi-cloud-plus/extend-function/rocketmq.md) - * [Kafka搭建](/ruoyi-cloud-plus/extend-function/kafka.md) - * [Nacos集群搭建](/ruoyi-cloud-plus/extend-function/nacos.md) - * [SkyWalking搭建与集成](/ruoyi-cloud-plus/extend-function/skywalking.md) - * [Prometheus+Grafana搭建](/ruoyi-cloud-plus/extend-function/prometheus_grafana.md) - * [Sharding-Proxy搭建分库分表](/ruoyi-cloud-plus/extend-function/shardingproxy.md) - * [对接MaxKey单点登录](/ruoyi-cloud-plus/extend-function/maxkey.md) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/changlog.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/changlog.md deleted file mode 100644 index 368844cb..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/changlog.md +++ /dev/null @@ -1,1385 +0,0 @@ -# 更新日志 -- - - - -## v2.2.1 - 2024-08-26 - -### 重大改动 - -* 增加 ruoyi-common-sse 模块 支持SSE推送 比ws更轻量更稳定的推送 -* 增加 springboot snailjob 等 actuator 账号密码认证 杜绝内外网信息泄漏问题 -* 增加 重构代码生成器 集成anyline开源框架 支持400+种数据库适配 - -### 依赖升级 - -* update springboot 3.2.6 => 3.2.9 -* update snailjob 1.0.1 => 1.1.2 -* update mapstruct-plus 1.4.3 => 1.4.4 -* update hutool 5.8.27 => 5.8.31 解决hutool不兼容jakarta问题 -* update anyline 8.7.2-20240808 -* update sms4j 3.2.1 => 3.3.2 -* update redisson 3.31.0 => 3.34.1 -* update mapstruct-plus 1.3.6 => 1.4.3 -* update lombok 1.18.32 => 1.18.34 -* update easyexcel 3.3.4 => 4.0.2 -* update springdoc 2.5.0 => 2.6.0 -* update flowable 7.0.0 => 7.0.1 - -### cloud内容更新 - -* update springcloud 2023.0.2 => 2023.0.3 -* update springcloud-alibaba 2023.0.1.0 => 2023.0.1.2 -* update redis 6.2.7 => 6.2.12 解决订阅key报错问题 -* update 优化 seata dockerfile 增加环境变量 -* update 优化 增加日志处理器顺序说明 -* update 优化 使用 seata-server 官方依赖简化seata集成方式 -* update 优化 屏蔽 sentinel 心跳日志 -* update 优化 dubbo元数据注册redis支持timeout(注意时间必须使用数字) -* update 优化 调整sentinel日志级别 屏蔽心跳日志 -* update 优化 sky-agent 默认开启即使连不上服务端也跟踪配置 (有些人就爱这么用) -* update 优化 kafka 自动创建 topic 部分人副本数不够报错问题 -* add 增加 nacos sentinel snailjob 健康检查 actuator 账号密码认证 -* fix 修复 dubbo redis元数据中心 获取监听器null问题 -* fix 修复 nacos sentinel seata 不适配新版undertow问题 先换回tomcat -* fix 修复 依赖漏洞 限制部分依赖版本 -* fix 修复 由于alibaba sentinel 初始化机制变更导致的无法连接问题 -* fix 修复 dubbo 日志输出异常判断错误 -* remove 删除 kafka-streams 所有人都不会用也不学怎么用 删除了事 - -### 功能更新 - -* update 优化 去除日志部署环境判断 通过日志级别控制 -* update 优化 忽略租户与忽略数据权限支持嵌套使用(感谢 amadeus5201) -* update 优化 租户相关controller 增加租户开关配置控制是否注册 -* update 优化 移除 alibaba ttl 与线程池搭配有问题(可传递但无法清除与更新) -* update 优化 个人中心编辑 忽略数据权限 -* update 优化 兼容部分用户不想给用户分配角色与部门的场景 -* update 优化 租户套餐重名校验 -* update 优化 部门下存在岗位不允许删除 -* update 优化 角色编辑状态未校验问题 -* update 优化 用户脱敏增加编辑权限标识符 -* update 优化 代码生成器 自动适配oss翻译 -* update 优化 临时升级 undertow 版本 解决虚拟线程溢出问题 -* update 优化 支持通过配置文件关闭工作流 -* update 优化 增加mybatis-plus填充器兜底策略 -* update 优化 TenantSpringCacheManager 处理逻辑 -* update 优化 角色权限判断 -* update 优化 增加删除标志位常量优化查询代码 -* update 优化 监控使用独立web依赖 -* update 优化 更多脱敏策略(感谢 hemengji) -* update 优化 设置nginx sse相关代理参数 -* update 优化 调整默认推送使用SSE -* update 优化 Monitor监控服务通知分类打印(感谢 AprilWind) -* update 优化 限流注解 又写key又不是表达式的情况 -* update 优化 WorkflowUtils查询用户信息发送消息未查询邮件和手机号(感谢 yanzy) -* update 优化 注释掉其他数据库 jdbc 依赖 由用户手动添加 -* update 优化 oracle snailjob 兼容低版本oracle索引名称长度限制 -* update 优化 数据权限支持通过菜单标识符获取数据所有权 -* update 优化 数据权限支持自定义连接符 -* update 优化 TestDemo 删除前校验数据权限 -* update 优化 更换docker镜像底层系统 避免无字体情况 - -### 问题修复 - -* fix 修复 三方登录构建去除无用代码 -* fix 修复 多线程对同一个session发送ws消息报错问题 -* fix 修复 依赖漏洞 限制部分依赖版本 -* fix 修复 excel 基于其他字段 合并错误问题 -* fix 修复 一级缓存key未区分租户问题 -* fix 修复 id字符串格式转换错误问题 -* fix 修复 登出无法正确删除对应的租户数据问题 -* fix 修复 登录错误锁定不区分租户问题 -* fix 修复 转换模型缺少分类字段 -* fix 修复 权限标识符处理未设置成功状态问题 -* fix 修复 无法导入 bpmn 类型文件问题 - -### 前端改动 - -* update element-plus 2.7.5 => 2.7.8 -* update vue 3.4.25 => 3.4.34 -* update vite 5.2.10 => 5.2.12 -* add 增加 使用 vueuse 编写 sse 推送功能 -* update 优化 使用匹配模式简化预编译配置 -* update 优化 时间搜索组件统一 -* update 优化 oss 配置按钮 使用ossConfig权限标识符与oss权限分离 -* update 优化 类型报错问题 -* update 优化 切换租户后刷新首页 -* update 优化 实现表格行选中切换 -* update 优化 使用 vueuse 重构 websocket 实现 -* update 优化 代码生成器编辑页禁用缓存 防止同步后页面不更新问题 -* update 优化 调整默认推送使用SSE -* fix 修复 租户套餐导出路径错误问题 -* fix 修复 登出后重新登录 sse推送报错问题 - - -## v2.2.0 - 2024-07-09 - -### 重大更新 - -* [重大更新] 使用 caffeine 重构 PlusSaTokenDao 层实现 减少将近90%的redis查询提高性能 -* [重大更新] 新增 PlusCacheWrapper 装饰器 为 SpringCache 增加本地缓存减少redis查询提高性能 -* [重大更新] 升级 awsS3 到2.X版本 支持异步与自动分片上传下载(感谢 AprilWind) -* [重大更新] 新增 flowable 工作流功能(感谢 May) -* [重大更新] 新增 snailjob 调度中心 移除 powerjob (投诉的人太多) (感谢 dhb52) -* [重大更新] 重构 将spring-cloud-stream改为普通的mq依赖用法(感谢 Xbhog) -* [重大更新] 新增 ruoyi-common-bus 消息总线组件 基于MQ跨服务投递事件消息 - -### 依赖升级 - -* update springboot 3.1.7 => 3.2.6 支持虚拟线程 -* update springboot-admin 3.1.8 => 3.2.3 -* update springdoc 2.2.0 => 2.5.0 -* update redisson 3.24.3 => 3.29.0 支持虚拟线程 -* update hutool 5.8.22 => 5.8.26 -* update dynamic-ds 4.2.0 => 4.3.0 -* update mybatis-plus 3.5.4 => 3.5.7 修复与boot代码冲突问题 -* update lock4j 2.2.5 => 2.2.7 消除启动警告 -* update sms4j 2.2.0 => 3.2.1 支持自定义配置key 可用于多厂商多租户等 -* update mapstruct-plus 1.3.5 => 1.3.6 -* update easyexcel 3.3.3 => 3.3.4 -* update lombok 1.18.30 => 1.18.32 -* update satoken 1.37.0 -> 1.38.0 -* update aws-oss 1.12.600 => 2.25.15 - -### 功能更新 - -* update 优化 StreamUtils 抽取 findFirst findAny 方法 -* update 优化 更新使用 Spring 官方推荐 JDK -* update 优化 webscoket 配置与异常拦截 -* update 优化 isTenantAdmin 空校验 -* update 优化 修改路由name命名规则(感谢 玲娜贝er) -* update 优化 大数据量下join卡顿问题 使用子查询提高性能 -* update 优化 用户ID查询角色列表(感谢 AprilWind) -* update 优化 获取用户账户(感谢 AprilWind) -* update 优化 租户列表接口 避免登录之后列表被域名过滤 -* update 优化 三方登录不同域名获取不到租户id问题 -* update 优化 获取aop代理的方式 减少与其他使用aop的功能冲突的概率 -* update 优化 临时解决 spring 启动报 warn 问题 -* update 优化 移除表单构建菜单(没有可用组件 用处不大以后再考虑) -* update 优化 修改用户信息接口(感谢 AprilWind) -* update 优化 切换动态租户 默认线程内切换(如需全局 手动传参) -* update 优化 适配最新前端代码生成模板 -* update 优化 代码生成 el-radio 标签过期属性 -* update 优化 文件下载(使用对流传递 降低内存使用量)(感谢 秋辞未寒) -* update 优化 去除gc日志参数(有需要自己加) -* update 优化 拆分异常处理器 -* update 优化 常规web异常状态码 -* update 优化 设置静态资源路径防止所有请求都可以访问静态资源 -* update 优化 代码生成表导入 排除工作流相关表 -* update 优化 redis 对Long值的存储类型不同问题 -* update 优化 去除加密请求类型限制 -* update 优化 mp多租户插件注入逻辑 -* update 优化 移除删表语句 用户自行处理 -* update 优化 RedisUtils 支持忽略租户 -* update 更新 ip地址 xdb文件 -* update 优化 新增修改菜单权限字符校验 -* update 优化 验证码背景色改为浅灰色 -* update 优化 更新 mybatis 多包扫描配置 -* update 优化 RateLimiter 注解使用体验(感谢 ly-chn) -* update 优化 GET 方法响应体支持加密 -* update 优化 excel 单元格合并可以基于注解选择需要依赖哪些字段(感谢 司猫子) -* update 优化 OssFactory 获取实例锁性能(感谢 fanc) -* update 优化 登录消息 支持集群发送 -* update 优化 数据权限 使用预扫描mapper注解提升代码性能 -* update 优化 数据加密 使用预扫描实体类提升代码性能(感谢 老马) -* update 优化 Async 针对虚拟线程配置 与其他注意事项注释 -* update 优化 框架整体sql提高查询性能 -* update 优化 将p6spy配置文件统一放置到 common-mybatis 插件包内 -* update 优化 使用翻译注解简化用户查询 调整用户查询逻辑 - - -### 新增功能 - -* add 新增 SMS异常处理器(感谢 AprilWind) -* add 新增 在线设备管理(个人中心)(感谢 AprilWind) -* add 新增 岗位编码与部门编码 并将岗位放到部门下(感谢 秋辞未寒) -* add 新增 分布式锁Lock4j异常拦截(感谢 AprilWind) -* add 新增 BaseMapperPlus提供一组可选是否抛出异常的selectVoOne方法(感谢 秋辞未寒) -* add 新增 用户、部门、角色、岗位 下拉选接口与代码实现优化 -* add 新增 JustAuth 整合 TopIam 单点登录(感谢 马铃薯头) -* add 新增 StringUtils.isVirtual 方法 -* add 新增 正则工具类 字符串提取 字符串校验 - -### 问题修复 - -* fix 修复 isLogin 方法抛异常无法正常返回值问题 -* fix 修复 spring路径规则 导致 actuator 被特殊方式访问问题 -* fix 修复token无效时关闭ws(感谢 AprilWind) -* fix 修复 oss未使用租户 拼接租户id null问题 -* fix 修复 用户昵称修改后未清除对应缓存问题 -* fix 修复 文件上传图片预览问题 -* fix 修复 三方账号可以被同一个用户多次绑定问题 -* fix 修复 兼容redis5.0出现的问题 -* fix 修复 字典键值可重复配置问题 -* fix 修复 部分浏览器无法获取加密响应头问题 -* fix 修复 用户未设置部门 登录报错问题 -* fix 修复 全局异常处理器 空指针null问题 -* fix 修复 excel 表达式字典 下拉框导出格式错误 -* fix 修复 InjectionMetaObjectHandler 已存在数据依旧会获取用户信息报异常问题 -* fix 修复 关闭租户功能 三方登录报错问题 -* fix 修复 部门树排序问题 -* fix 修复 CryptoFilter 代码逻辑问题 - -### 前端改动 - -* update 升级 element vite 版本 最低nodejs版本提升到18.18.0 -* update 优化 更改客户端状态接口 使用clientId传参 -* update 优化 ws开关改为常开(vite5修复了崩溃bug) -* update 优化 移除cjs -* update 优化 对Volar支持 -* update 优化 富文本组件,修复两个组件上传图片位置错乱问题 -* update 优化 request请求类判断请求头方式 -* update 优化 密码校验策略增加非法字符限制 -* update 优化 支持全局开启或关闭接口加密功能 -* update 优化 暗黑模式,增加vxe的暗黑模式 -* update 优化 首页打开topNav不展开菜单问题 -* update 优化 el-select 与 el-input 全局样式 -* update 优化 跟密码相关的默认前端关闭防重功能 -* add 新增 社交登录整合 TopIam -* add 新增 图片上传组件增加压缩功能支持,可自行开关 -* add 新增 vxe-table依赖支持 -* add 新增 全局用户选择组件 -* add 新增 工作流相关页面与组件 -* add 新增 使用bpmnjs流程预览 -* add 新增 在线登录设备管理(感谢 AprilWind) -* add 新增 用户选择角色时 可搜索功能(感谢 追梦稻草人Li) -* fix 修复 登录失效,重新登录丢失参数问题(感谢 爱宇阳) -* fix 修复 websocket 非index页面刷新无法重连问题 -* fix 修复 全局属性找不到的问题(感谢 ahaos) -* fix 修复 vue 类型识别问题 -* fix 修复 富文本编辑器 单页面多实例图片混乱问题 -* fix 修复 i18n无感刷新问题 -* fix 修复 文件预览大写后缀不展示的问题(感谢 北桥) -* fix 修复 面板因为min width原因收缩不全 -* fix 修复 移动端下 无法展开菜单问题 -* fix 修复 菜单搜索下方出现白色区域 -* fix 修复 el-tag标签类型不一致问题 -* fix 修复 角色必填*号 - -### 微服务修改 - -* update springcloud 2022.0.4 => 2023.0.2 -* update springcloud-alibaba 2022.0.0.0 => 2023.0.1.0 -* update dubbo 3.2.7 => 3.2.14 -* update easy-es 2.0.0-beta4 => 2.0.0 正式版 -* update nacos 2.2.1 => 2.3.2 默认开启nacos服务端授权认证 (感谢 OldDriver9527) -* update rocketmq 4.9.4 => 5.2.0 docker镜像升级 -* update kafka 3.2.0 => 3.6.2 docker镜像升级 -* update rabbitmq 3.10.6 => 3.13.3 docker镜像升级 -* update sentinel 1.8.6 => 1.8.8 -* update skywalking 9.3.0 => 9.7.0 -* update skywalking-agent 8.16.0 => 9.2.0 -* update 优化 dubbo 使用 redis 作为元数据中心管理 支持过期时间 避免过期数据堆积 解放nacos存储空间 -* update 优化 调整配置文件语法 -* update 优化 使用spring工具自定义dubbo ip获取方法(针对多网卡ip获取不正确问题) -* update 优化 common-dubbo 删除无用依赖 -* update 优化 去除重复的扫描器 @EnableDubbo 会自行扫描包 -* update 优化 加密组件 mp依赖改为可选 -* update 优化 mybatis依赖设置为可选依赖 避免出现不应该注入的情况 -* fix 修复 sentinel-dashboard的pom引入logaback冲突问题 -* fix 修复 nacos 不兼容 logback 1.4 新版本问题 -* fix 修复 开启数据库加密 auth服务报错问题 -* fix 修复 gateway sentinel 限流报错问题(临时方案) https://github.com/alibaba/Sentinel/issues/3298 - - -## v2.1.2 - 2023-12-22 - -### 依赖升级 - -* update springboot 3.1.5 => 3.1.7 -* update springboot 2.7.17 => 2.7.18(扩展服务升级到boot2最终版本) -* update mybatis-boot 3.0.2 => 3.0.3 优化依赖传递 -* update powerjob 4.3.3 => 4.3.6 -* update easyexcel 3.3.2 => 3.3.3 -* update transmittable-thread-local 2.14.2 => 2.14.4 -* update justauth 1.16.5 => 1.16.6 -* update redisson 3.24.1 => 3.24.3 修复订阅重启连接超时问题 -* update easy-es 1.1.1 => 2.0.0-beta4 - -### 功能更新 - -* update 优化 oss 远程调用 支持降级处理 -* update 优化 丰富RedisUtils对List Set类型的操作 -* update 优化 为 admin 模块 单独增加ratelimiter模块 -* update 优化 验证码接口 增加限流配置 -* update 优化 excel合并注解会根据第一合并列的结果来决定后续的列合并 (感谢 Simple) -* update 优化 SocialUtils 代码 -* update 优化 删除无用异常类 -* update 优化 补全三方登录校验国际化 -* update 优化 sms组件 预留自动配置类 -* update 更新 关于数据库的说明 -* update 优化 sms组件 预留自动配置类 -* update 优化 将 OSS配置 改为全局模式 降低使用难度 保留sql便于用户自行扩展(常规项目用不上配置分多租户) -* update 优化 细化oss配置管理权限控制 -* update 优化 开启 redisson 脚本缓存 减少网络传输 -* update 优化 删除 hikaricp 官方不推荐使用的配置 jdbc4 协议自带校验方法 -* update 优化 减少 PlusSaTokenDao 不必要的查询优化性能 -* update 优化 更新用户异常提示 使用登录账号 -* update 优化 使用登录用户判断是否登录 提高效率 -* update 优化 重构 LoginHelper 将本地存储代码操作封装 -* update 优化 getTenantId 判断是否开启多租户 -* update 优化 Dockerfile 使用shell模式 支持环境变量传入jvm参数 -* update 优化 WebSocketUtils 连接关闭改为警告 -* update 优化 excel多sheet页导出 (感谢 May) -* update 优化 删除无用接口实现 -* update 优化 jvm参数调整 全面启用zgc -* update 优化 使用动态租户重构业务对租户的逻辑 -* update 优化 TenantHelper 动态租户支持函数式方法 -* update 优化 支持多租户绑定相同的三方登录 -* update 优化 更新用户登录信息方法忽略数据权限 -* update 优化 补全三方绑定时间字段 删除无用excel注解 -* update 优化 将登录记录抽取到监听器统一处理 -* update 优化 登录消息推送异常拦截(未启动resource也不耽误用) -* update 优化 租户插件 ignoreTable 方法支持动态租户 - -### 新增功能 - -* add 新增 RedisUtils.setObjectIfExists 如果存在则设置方法 -* add 新增 丰富RedisUtils对List Set类型的操作 -* add 新增 翻译组件 用户昵称翻译实现 -* add 新增 响应加密功能 支持注解强制加密接口数据 (感谢 MichelleChung) -* add 新增 common-ratelimiter 限流模块 用于自定义业务限流 与 sentinel不冲突 - -### 问题修复 - -* fix 修复 stream-mq 测试服务未导入租户模块 导致鉴权不一致问题 -* fix 修复 使用zgc导致seata报错(未知原因 将alibaba组件全还原) -* fix 修复 sentinel 镜像添加了多余接口参数 -* fix 修复 注册接口获取开关未在租户范围内问题 -* fix 修复 seata-server logback版本冲突问题 -* fix 修复 selectDictTypeByType 查询方法错误问题 -* fix 修复 一些不正常类无法加载报错问题 -* fix 修复 powerjob sql脚本针对其他数据库转义符问题 (感谢 branches) -* fix 修复 MybatisSystemException 空指针问题 -* fix 修复 excel合并注解会根据第一合并列的结果来决定后续的列合并 -* fix 修复 session 多账号共用覆盖问题 改为 tokenSession 独立存储 -* fix 修复 token 失效后 登录获取用户null问题 -* fix 修复 powerjob部署方案 高版本nginx不生效问题 -* fix 修复 OssFactory 并发多创建实例问题 -* fix 修复 延迟队列在投递消息未到达时间的时候 服务死机导致重启收不到消息 - -### 前端改动 - -* update 优化 用户头像 img 变量无确定类型问题 -* update 优化 细化oss配置管理权限控制 -* update 优化 明确打包命令 -* update 优化 代码中存在的警告 -* update 优化 前端白名单页面放行逻辑 -* update 优化 页面关于权限标识符说明 -* fix 修复 append-to-body 编写错误 (感谢 Ai3_刘小龙) -* fix 关闭动态路由tab页签时不清理组件缓存 (感谢 NickLuo) -* fix 删除重复环境变量ElUploadInstance (感谢 棉花) -* fix 修复 在线用户 强推按钮点击取消控制台警告问题 -* fix 修复 字典使用 default 样式报警告问题 - -## v1.8.2 - 2023-11-27 - -### 依赖升级 - -* update springboot 2.7.16 => 2.7.18 升级到2.X最终版本(官方停更) -* update mybatis-plus 3.5.3.2 => 3.5.4 -* update satoken 1.36.0 => 1.37.0 -* update hutool 5.8.20 => 5.8.22 -* update aws-java-sdk-s3 1.12.400 => 1.12.540 -* update vue-quill 1.1.0 => 1.2.0 - -### 功能更新 - -* update 优化 页面关于权限标识符说明 -* update 优化 数据权限拦截器优先判断方法是否有效 提高性能减少无用sql解析 -* update 优化 部门数据权限使用默认兜底方案 -* update 优化 补全代码生成 columnList 接口参数注解缺失 -* update 优化 AddressUtils 兼容linux系统本地ip -* update 优化 操作日志 部门信息完善 -* update 优化 数据权限 减少二次校验查询 -* update 修改 获取用户token和后端不一致的问题 (感谢 bestrevens) -* update 优化 vue3 版本用户初始密码从字典查询 -* update 优化 富文本Editor组件检验图片格式 -* update 优化 操作日志列表新增IP地址查询 -* update 优化 全局数据存储用户编号 -* update 优化 菜单管理类型为按钮状态可选 - -### 问题修复 - -* fix 修复 OssFactory 并发多创建实例问题 -* fix 修复 demo页面字段编写错误 -* fix 修复 数据权限优化后 update delete 报null问题 -* fix 修复 五级路由缓存无效问题 -* fix 修复 oss服务无法连接 -* fix 修复 内链iframe没有传递参数问题 -* fix 修复 外链带端口出现的异常 -* fix 修复 普通角色编辑使用内置管理员code越权问题 -* fix 修复 seata XA模式缺失druid工具问题 -* fix 修复 代码生成 是否必填与数据库不匹配问题 -* fix 修复 富文本上传接口地址错误 -* fix 修复 HeaderSearch组件跳转query参数丢失问题 -* fix 修复树结构代码生成新增方法赋值错误 - -## v2.1.1 - 2023-11-14 - -### 依赖升级 - -* update springboot 3.1.3 => 3.1.5 -* update springboot 2.7.14 => 2.7.17(扩展服务) -* update springboot-admin 3.1.5 => 3.1.7 -* update satoken 1.35.0.RC => 1.37.0 -* update mybatis-plus 3.5.3.2 => 3.5.4 适配mp新版本改动 -* update dynamic-ds 4.1.3 => 4.2.0 -* update bouncycastle 1.72 => 1.76 -* update poi 5.2.3 => 5.2.4 -* update redisson 3.23.2 => 3.24.1 -* update hutool 5.8.20 => 5.8.22 -* update lombok 1.18.26 => 1.18.30(适配支持jdk21) -* update vue-quill 1.1.0 => 1.2.0 -* update seata 1.7.0 => 1.7.1 -* update dubbo 3.2.5 => 3.2.7 - -### 功能更新 - -* update 优化 移除不合理的方法 携带附件的邮件建议直接集成插件发送 -* update 优化 携带 clientid 跨域问题 -* update 优化 数据权限拦截器优先判断方法是否有效 提高性能减少无用sql解析 -* update 优化 适配 maxkey 新版本 -* update 优化 @Sensitive脱敏增加角色和权限校验 (感谢 盘古给你一斧) -* update 优化 部门数据权限使用默认兜底方案 -* update 优化 更改默认日志等级为info 避免日志过多(按需开启debug) -* update 优化 登录策略代码优化(感谢 David Wei) -* update 优化 补全代码生成 columnList 接口参数注解缺失 -* update 优化 nginx 配置支持 websocket -* update 优化 notice 新增通知公告发送ws推送 -* update 优化 websocket 模块减少日志输出 增加登录推送 -* update 优化 重构登录策略增加扩展性降低复杂度 -* update 优化 addressUtils 兼容linux系统本地ip -* update 优化 补全操作日志部门数据 -* update 优化 支持数据库操作在非web环境下切换租户 -* update 优化 排除powerjob无用的依赖 减少打包30M体积 -* update 优化 删除 satoken yml 时间配置 此功能已迁移至客户端管理 -* update 优化 redis 集群模式注释说明 -* update 优化 客户端禁用限制 -* update 优化 登录日志, 在线用户展示信息(增加 客户端, 设备类型)(感谢 MichelleChung) -* update 优化 限制框架中的fastjson版本 -* update 优化 数据权限 减少二次校验查询 -* update 优化 将部门id存入token避免过度查询redis -* update 优化 增加租户ID为Null错误日志 -* update 优化 操作日志列表新增IP地址查询 -* update 优化 通过参数键名获取键值接口的返回体(感谢 David Wei) -* update 优化 为 sys_grant_type 字典增加样式 -* update 优化 代码生成 页面输入框样式 -* update 优化 全业务分页查询增加排序规则避免因where条件导致乱序问题 -* update 优化 登录接口租户id被强制校验问题 -* update 优化 加密模块 支持父类统一使用加密注解(感谢 Tyler Ge) -* update 优化 将graalvm镜像更新为openjdk镜像 需要的人自行切换即可 -* update 优化 部分使用者乱设权限导致无法获取用户信息 增加权限提示 -* update 优化 表格列的显示与隐藏小组件(感谢 bestrevens) -* update 优化 增加表单构建不能使用说明 -* update 优化 富文本Editor组件检验图片格式 -* update 优化 操作日志列表新增IP地址查询 -* update 优化 菜单管理类型为按钮状态可选 -* update 优化 用户初始密码从参数配置查询 -* update 优化 通过参数键名获取键值接口的返回体(感谢 David Wei) -* update 优化 字典标签支持数组和多标签(感谢 抓蛙师) - -### 新增功能 - -* add 新增 websocket 群发功能 -* add 新增 前端接入websocket接收消息(感谢 三个三) -* add 增加 rpc消息推送接口与实现 -* add 新增 CacheController Redis 缓存监控接口(感谢 Michelle.Chung) - -### 问题修复 - -* fix 修复 因扩展服务不支持boot3导致无法引入common-web包 日志写出不生效问题 -* fix 修复 seata XA模式缺失druid工具问题 -* fix 修复 oss服务无法连接 导致业务异常问题 查询不应该影响业务 -* fix 修复 租户id为null 无法匹配字符串导致的嵌套key问题 -* fix 修复 部门管理orderNum排序失效问题 -* fix 修复 外链带端口出现的异常 -* fix 修复 普通角色编辑使用内置管理员code越权问题 -* fix 修复 代码生成 是否必填与数据库不匹配问题 -* fix 修复 用户注册接口校验用户名不区分租户问题 -* fix 修复 错误增加组导致的校验不生效问题 -* fix 修复 新增校验主键id问题 -* fix 修复 powerjob 使用 nginx 部署无法访问的问题 -* fix 修复 SysUserMapper 内标签使用错误(不影响使用) -* fix 修复 新增或编辑 SysOssConfig 数据后 推送到 redis 数据不完整 -* fix 修复 树表生成查询变量使用错误 -* fix 修复 个人信息修改密码接口隐藏新旧密码参数明文(感谢 bleachtred) -* fix 修复 删除字段后 * update sql 未更新问题 -* fix 修复 三方登录支付宝source与实际支付宝业务code不匹配问题 -* fix 修复 五级路由缓存无效问题 -* fix 修复 内链iframe没有传递参数问题 -* fix 修复 绑定第三方帐号参数“wechar”更正为“wechat” (感谢 scmiot) -* fix 修复 用户注册缺失 clientid 问题 -* fix 修复 HeaderSearch组件跳转query参数丢失问题 -* fix 修复 自定义字典样式不生效的问题 -* fix 修复 login 页面 loading 未关闭问题 - -## v1.8.1 - 2023-09-26 - -### 依赖升级 - -* update springboot 2.7.14 => 2.7.16 -* update springboot-admin 2.7.10 => 2.7.11 -* update satoken 1.35.0.RC => 1.36.0 -* update lombok 1.18.26 =. 1.18.30 -* update springboot 2.7.13 => 2.7.14 -* update mybatis-plus 3.5.3.1 => 3.5.3.2 -* update easyexcel 3.3.1 => 3.3.2 -* update hutool 5.8.18 => 5.8.20 -* update dubbo 3.1.8 => 3.1.11 - -### 功能更新 - -* update 优化 代码生成 vo实体类序列化 -* update 优化 excel 导出不必要的请求头 -* update 优化 字典标签支持传分隔符分隔的字符串和数组 -* update 优化 控制台debuger位置错误问题 -* update 优化 TopNav 菜单样式 -* update 优化 注册用户异常报错不正确问题 -* update 优化 全局异常处理器 业务异常不输出具体堆栈信息 减少无用日志存储 -* update 优化 用户管理 只查询未禁用的部门角色岗位数据 -* update 优化 岗位如果绑定了用户则不允许禁用 -* update 优化 部门与角色如果绑定了用户则不允许禁用 -* update 优化 加密实现 使用 EncryptUtils 统一处理 -* update 优化 适配 mysql 8.0.34 升级连接机制 -* update 优化 excel导出字典转下拉框 无需标记index自动处理 -* update 优化 excel 导出字典默认转为下拉框 -* update 删除一些跟swagger有关的字眼 避免误解 -* update 优化 角色权限支持仅本人权限查看 解决无法查看自己创建的角色问题 -* update 优化 xxljob 端口随着主应用端口飘逸 避免集群冲突 - -### 问题修复 - -* fix 修复 自定义字典样式不生效的问题 -* fix 修复 新建用户可能会存在的越权行为 -* fix 修复 字典缓存删除方法参数错误问题 -* fix 修复 修复树模板父级编码变量错误 -* fix 修复 demo 模块缺少 security 依赖问题 -* fix 修复 升级 mp 版本导致的问题 -* fix 修复 加密模块数据转换异常问题 -* fix 修复 动态设置 token 有效期不生效问题 -* fix 修复 token 过期登出无法清理在线用户问题 - - -## v2.1.0 - 2023-09-06 - -# 开发历程 - -* 2023年5月 开始 2.1.0 计划 历经1个月的设计与讨论 -* 2023年6月 开始着手开发 历经2个多月的开发 特别感谢团队的小伙伴与一些热心的粉丝 参与功能开发与测试 -* 2023年8月 开始公测 历经将近1个月的公测与修复工作(期间成功支持多位使用者生产使用) -* 2023年9月初 正式发布(经过多个小伙伴的生产实践 已基本可尝试生产使用) -> 关于1.X的说明 由于SpringBoot2.X与vue2.X均在11月底停止维护
-> 故而咱们vue版本1.X也无法再继续更新
-> 介于1.X的用户量特别庞大 功能也非常的稳定
-> 计划于11月底同Boot2.X一同停止更新但还会持续维护修复bug(修复的形式为直接提交到1.X分支停止发版)
- -# 视频介绍 - -为了更好的让大家了解 2.1.0 作者录制了相关的视频 供大家快速了解上手 - -* 2.1.0 新功能与变更介绍: https://www.bilibili.com/video/BV1fj411y71X/ - -# 更新日志 - -### 重大更新 - -* [重大更新] 优化 相关代码 完成代码生成多数据源统一存储(感谢 WangBQ) -* [不兼容更新] 移除 原短信功能 集成更强大的 sms4j 短信工具包(感谢 友杰) -* [不兼容更新] 对接 powerjob 实现分布式任务调度 删除原有 xxljob 原因为社区不更新功能太少只支持mysql(感谢 yhan219) -* [重大更新] 新增 三方授权绑定登录功能 基于 justauth 支持市面上大部分三方登录(感谢 三个三) -* [不兼容更新] 新增 客户端授权功能 不需要更改任何代码即可完成多端动态对接(感谢 Michelle.Chung) -* [重大更新] 新增 前后端接口请求加密传输 基于AES+RSA动态高强度加密(感谢 wdhcr) -* [重大更新] 新增 三方授权登录 对接 maxkey 单点登录 -* [不兼容更新] 优化 redis序列化配置 更改为通用格式(升级需清除redis所有数据) -* [重大更新] 新增 通过 sharding-proxy 实现分库分表(感谢 rice666 !pr94) - -### 依赖升级 - -* update springboot 3.0.7 => 3.1.3 -* update springboot-admin 3.1.3 => 3.1.5 -* update springcloud 2022.0.2 => 2022.0.4 -* update springcloud-alibaba 2022.0.0.0-RC2 => 2022.0.0.0 -* update springdoc 2.1.0 => 2.2.0 -* update spring-mybatis 3.0.1 => 3.0.2 -* update mybatis-plus 3.5.3.1 => 3.5.3.2 -* update easyexcel 3.2.1 => 3.3.2 -* update mapstruct-plus 1.2.3 => 1.3.5 解决修改实体类 idea不编译问题 -* update satoken 1.34.0 => 1.35.0.RC 优化过期配置 支持多端token自定义有效期 -* update dynamic-ds 3.6.1 => 4.1.3 支持 SpringBoot3 -* update sms4j 2.2.0 -* update hutool 5.8.18 => 5.8.20 -* update redisson 3.20.1 => 3.23.4 -* update lock4j 2.2.4 => 2.2.5 -* update aws-java-sdk-s3 1.12.400 => 1.12.540 -* update maven-surefire-plugin 3.0.0 => 3.1.2 -* update seata 1.6.1 => 1.7.0 -* update sharding-proxy 5.4.0 -* update dubbo 3.2.2 => 3.2.5 -* update skywalking-toolkit 8.14.0 => 8.16.0 -* update logstash 7.2 => 7.4 - -### 功能更新 - -* update 优化 与 vue 版本同步代码结构 -* update 优化 放行springboot默认error接口 -* update 优化 RepeatSubmitAspect 逻辑避免并发请求问题 -* update 调整 gateway 访问日志输出等级 -* update 优化 修改角色如果未绑定用户则无需清理 -* update 优化 用户昵称非空校验 -* update 优化 在全局异常拦截器中增加两类异常处理 -* update 优化 StreamUtils 方法过滤null值 -* update 优化 powerjob 端口随着主应用端口飘逸 避免集群冲突 -* update 优化 角色权限支持仅本人权限查看 解决无法查看自己创建的角色问题 -* update 修改代码生成模版,日期范围统一采用addDateRange方法 -* update 优化 树表生成前端缺少 children 字段 -* update 优化 ruoyi-resource 服务添加 websocket 模块 -* update 优化 放行验证码接口、第三方登录请求与回调 -* update 更新 GlobalLogFilter#filter 根据请求头判断加密参数(感谢 Michelle.Chung !pr100) -* update 优化 SaReactorFilter 过滤器判断 token 客户端 id 是否有效(感谢 Michelle.Chung !pr101) -* update 删除一些跟swagger有关的字眼 避免误解 -* update 优化 兼容 clientid 通过 param 传输 -* update 优化 excel导出字典转下拉框 无需标记index自动处理(感谢 一夏coco) -* update 优化 增加线程池销毁配置 -* update 优化 屏蔽 powerjob 无用的心跳日志 -* update 优化 适配 mysql 8.0.34 升级连接机制 -* update 优化 加密实现 使用 EncryptUtils 统一处理 -* update 优化 删除字典无用状态字段(基本用不上 禁用后还会导致回显问题) -* update 优化 部门与角色如果绑定了用户则不允许禁用 -* update 优化 岗位如果绑定了用户则不允许禁用 -* update 优化 用户管理 只查询未禁用的部门角色岗位数据 -* update 优化 登录用户增加昵称返回 -* update 优化 全局异常处理器 业务异常不输出具体堆栈信息 减少无用日志存储 -* update 优化 将部门管理 负责人选项改为下拉框选择 -* update 优化 登录用户缓存 去除冗余统一存储 -* update 优化 注册用户异常报错不正确问题 -* update 优化 放宽菜单权限 角色关联菜单无需管理员 - -### 新增功能 - -* add 增加 RedisUtils 批量删除 hash key 方法 -* add 新增 Oss 上传 File 文件方法(感谢 jenn) -* add 增加 excel 导出下拉框功能 -* add 新增 RedisUtils.setObjectIfAbsent 如果不存在则设置方法 - -### 修复问题 - -* fix 修复 用户重名登录报错问题 -* fix 修复 服务未添加 common-security 模块导致异常拦截器不生效问题 -* fix 修复 用户篡改管理员角色标识符越权问题 -* fix 修复 文件管理 创建人未翻译问题 -* fix 修复 monitor 监控无法展示数据问题 -* fix 修复 更换 satoken dubbo 插件导致包名不一致问题 -* fix 修复 字典缓存注解使用错误问题 -* fix 修复 接口文档未拼接服务路径问题 -* fix 修复 excel 枚举反向解析失败问题 -* fix 修复 查询部门下拉树未过滤数据权限问题 -* fix 修复 CacheName 缓存key存储错误问题 -* fix 修复 oss 列表 用户名回显错误 -* fix 修复 不同vo相同字段mybatis会自动赋值问题 -* fix 修复 删除 skywalking dubbo 2.X 插件避免与 3.X 出现兼容性问题 -* fix 修复 新增角色使用内置管理员标识符问题 -* fix 修复 token 过期登出无法清理在线用户问题 -* fix 修复 动态设置 token 有效期不生效问题 -* fix 修复 加密模块数据转换异常问题 -* fix 修复 dubbo 更改内部序列化方式 导致异常类无法反序列化问题 -* fix 修复 客户端编辑时授权类型变更未保存的问题 -* fix 修正 缺失 SysClientVoConvert 导致转换异常(感谢 Michelle.Chung) -* fix 修正 auth 模块缺失引用导致解密异常(感谢 Michelle.Chung) -* fix 修复 demo 与 stream-mq 模块缺少 security 依赖问题 -* fix 修复 导入用户数据 变量使用错误问题 -* fix 修复 验证码开关未动态刷新问题 -* fix 修复 自动填充数据 loginUser 为 null(感谢 charles !pr108) -* fix 修复 修复树模板父级编码变量错误 -* fix 修复 部署部分系统出现乱码问题 -* fix 修复 一级菜单无法显示问题 -* fix 修复 新建用户可能会存在的越权行为 -* fix 修复 代码生成页面参数缺少逗号问题 - -### 移除功能 - -* remove 移除原有短信功能(建议使用sms4j) -* remove 移除xxljob功能(建议使用powerjob) - - -## v1.8.0 - 2023-07-11 - -### 重大更新 - -* [重大更新] 新增 sms4j 短信融合框架整合(支持数十种短信厂商接入、发送限制、负载均衡等功能) -* [不兼容更新] 移除 原短信功能(建议使用新 sms4j 功能) -* [重要迁移] 迁移 vue3 前端到主仓库统一维护 - -### 依赖升级 - -* update springboot 2.7.11 => 2.7.13 -* update spring-cloud 2021.0.7 => 2021.0.8 -* update satoken 1.34.0 => 1.35.0.RC -* update easyexcel 3.2.1 => 3.3.1 -* update sms4j 2.2.0 -* update element 2.15.12 => 2.15.13 - -### 功能更新 - -* update 优化 StreamUtils 方法过滤null值 -* update 优化 页签在Firefox浏览器被遮挡 -* update 优化 在全局异常拦截器中增加两类异常处理 -* update 优化 下载zip方法增加遮罩层(感谢@梁剑锋) -* update 优化 用户昵称非空校验 -* update 优化 修改角色如果未绑定用户则无需清理 -* update 优化 RepeatSubmitAspect 逻辑避免并发请求问题 -* update 优化 satoken 过期配置 支持多端token自定义有效期 -* update 优化 加密注解注释错误 -* update 优化 切换 maven 仓库到华为云(aliyun 不可用) -* update 优化 excel 导出存在合并项时在初始化类时进行数据的处理避免多次调用(感谢@yueye) -* update 优化 重构 CellMergeStrategy 支持多级表头修复一些小问题 整理代码结构 -* update 补全 SysLogininforMapper.xml 缺失字段 -* update 优化 demo 模块 路径适配统一前端 -* update 调整 gateway 访问日志输出等级 - -### 新增功能 - -* add 新增 RedisUtils.setObjectIfAbsent 不存在则设置方法 -* add 新增 Excel 导出附带有下拉框(字典自动导出为下拉框) 可自定义多级下拉框(感谢@Emil.Zhang) -* add 新增 OssClient File 文件上传方法 -* add 增加 RedisUtils 批量删除 hash key 方法 - -### 问题修复 - -* fix 修复 sa-token.check-same-token 开关对网关鉴权无效问题 -* fix 修复 服务未添加 common-security 模块导致异常拦截器不生效问题 -* fix 修复 删除 skywalking dubbo 2.X 插件避免与 3.X 出现兼容性问题 -* fix 修复 excel 枚举反向解析失败问题 -* fix 修复 字典缓存注解使用错误问题 -* fix 修复 新增角色使用内置管理员标识符问题 -* fix 修复 缓存监控图表 支持跟随屏幕大小自适应调整(感谢@抓蛙师) -* fix 修复 防重组件 错删注解问题 -* fix 修复 CacheName 缓存key存储错误问题 -* fix 修复 字典缓存注解使用错误问题 -* fix 修复 用户篡改管理员角色标识符越权问题 -* fix 修复 登录校验错误次数未达到上限时 错误次数缓存未设置有效时间问题 -* fix 修复 OssClient 切换服务 实例不正确问题 -* fix 修复 element ui 因版本而未被工具识别问题(感谢@梁剑锋) -* fix 修复 admin监控 切换tab页需要重复登录问题 -* fix 修复 个人中心tab栏关闭页面内容压缩问题 - -## v2.0.0 - 2023-06-15 - -**重点说明: 由于 SpringCloudAlibaba 一直未发布正式版 导致系统底层组件可能存在些许问题 故而不建议生产使用 框架也将直接开启后续 2.1.0 的开发工作** - -### 重大更新 - -* [不兼容升级] java 版本从 jdk 8 升级到 jdk 17 且需要使用 graalvm 运行(暂时未解决原生jdk存在的问题) -* [不兼容升级] springboot 升级 3.0 版本 -* [不兼容升级] 重构 项目模块结构 采用插件化结构 易扩展易解耦 -* [不兼容升级] com.sun.mail 更改为 jakarta.mail 修改最新写法 -* [不兼容升级] javax.servlet 替换为 jakarta.servlet 更新所有代码 -* [简化性升级] 默认开启复杂结构 resultMap 自动映射 简化xml编码(多结构实体需带上主键id) -* [数据库改动] 更新 create_by update_by 字段类型 (保存用户id) -* [数据库改动] 新增 create_dept 字段 (保存创建部门id) -* [不兼容更新] system 模块 所有实体类均使用 bo|vo 规范化 -* [重大更新] 新增 多租户功能设计 整体框架代码结构与数据库更改 -* [重大更新] 新增 mapstruct-plus 替换 BeanUtil 与 BeanCopyUtils 工具 -* [不兼容更新] 重构 登录注解接口与cloud版本统一接口路径 -* [不兼容更新] 重构 BaseMapperPlus接口 去除 `@param Mapper` 泛型 -* [不兼容更新] 移除 vue2 前端工程 全面启用 vue3 -* [重大更新] 新增 vue3 + TS 版本前端(独立仓库后续与Cloud版本共用) -* [重大更新] 增加 websocket 模块 支持token鉴权 支持分布式集群消息同步 -* [重大更新] 框架文档全面翻新 https://plus-doc.dromara.org -* [不兼容更新] 代码生成 支持代码生成多数据源统一存储(主库存储子库的表 无需子库加gen表了) -* [不兼容更新] 重构 将系统内置配置放置到common包内独立加载 不允许用户随意修改 - -### 依赖升级 - -* update java 1.8 => 17 -* update springboot 2.7.7 => 3.0.7 -* update springcloud 2021.0.6 => 2022.0.2 -* update springcloud-alibaba 2022.0.0.0-RC2 -* update springboot-admin 2.7.10 => 3.0.4 -* update springdoc 1.6.14 => 2.1.0 -* udpate dubbo 3.1.8 => 3.2.2 -* update lock4j 2.2.3 => 2.2.4 -* update dynamic-ds 3.5.2 => 3.6.1 -* update easyexcel 3.1.5 => 3.2.1 -* update hutool 5.8.11 => 5.8.18 -* update redisson 3.19.2 => 3.20.1 -* update lombok 1.18.24 => 1.18.26 -* update spring-boot.mybatis 2.2.2 => 3.0.1 -* update mapstruct-plus 1.2.3 -* update maven-compiler-plugin 3.10.1 => 3.11.0 -* update maven-surefire-plugin 3.0.0-M7 => 3.0.0 -* update docker mysql 8.0.31 => 8.0.33 -* update docker nginx 1.22.1 => 1.32.4 -* update docker redis 6.2.7 => 6.2.12 -* update docker minio RELEASE.2023-04-13T03-08-07Z - -### 功能更新 - -* update 适配 AsyncConfig 替换过期继承类改为实现 AsyncConfigurer 接口 -* update 适配 redis 新版本配置文件写法 -* update 适配 获取redis 监控参数接口 替换过期语法 -* update 适配 sa-token 替换新依赖 sa-token-spring-boot3-starter -* update 适配 springboot-admin 改为最新 spring-security 写法 -* update 适配 springdoc 新版本配置方式 -* update 适配 ServletUtils 更换继承 JakartaServletUtil -* update 适配 新序列化注解 -* update 优化 利用 resultMap 自动映射配置 简化 xml (非嵌套) -* update 优化 调整 system entity 实体与 controller 包结构 -* update 优化 实体类中校验注解的提示信息 -* update 优化 使用 jdk17 语法优化代码 -* update 优化 所有 properties 文件改为注解启用 -* update 更新 docker 基础镜像 graalvm java17 -* update 优化 用户头像 改为存储 ossId 使用转换模块转为 url 展示 -* update 优化 重构 CellMergeStrategy 支持多级表头修复一些小问题 整理代码结构 -* update 优化 登录流程代码注释 -* update 优化 将框架内的swagger命名更改为springdoc命名避免误解 - -### 新增功能 - -* add 新增 flatten-maven-plugin 插件统一版本号管理 -* add 新增 ip2region 实现离线IP地址定位库 - -### 移除功能 - -* remove 移除 BeanCopyUtils 工具类 与 JDK17 不兼容 -* remove 移除 devtools 依赖 并不好用(建议直接用idea自带的热更) -* remove 移除 vue2 前端工程 统一使用 vue3 工程 - -### 修复功能 - -* fix 修复 根据 seata 官方提交记录 临时修复 seata 关于jdk17代理的bug -* fix 修复 登录校验错误次数未达到上限时 错误次数缓存未设置有效时间问题 -* fix 修复 common-core 包使用aop注解 但未添加aop实现类导致单独使用报错问题 - -## v1.7.0 - 2023-05-10 - -### 依赖升级 - -* update springboot 2.7.9 => 2.7.11 修复 DoS 漏洞 修复CVE漏洞 -* update springcloud 2021.0.6 => 2021.0.7 -* update springcloud-alibaba 2021.0.4.0 => 2021.0.5.0 -* update dubbo 3.1.7 => 3.1.10 -* update nacos 2.2.0 => 2.2.1 -* update xxljob 2.3.1 => 2.4.0 -* update minio 升级至最新版 避免低版本信息泄漏问题 -* update hutool 5.8.15 => 5.8.18 -* update redisson 3.20.0 => 3.20.1 -* update lombok 1.18.24 => 1.18.26 - -### 功能更新 - -* update 优化 更改 sys_oss_config 表注释 避免误解 -* update 优化 sys_logininfor 丰富多种信息 -* update 项目正式入驻 dromara 开源社区 更改项目地址 -* update 全新 logo 全新背景图(设计师打造) -* update 优化 代码生成模块的数据同步功能 -* update 修改多团队开发插件,支持多网卡 -* update 修改controller中校验直接返回R.fail -* update 优化 角色sort值一样的排序问题 -* update 更换默认用户头像 -* update 优化 WebFluxUtils.getOriginalRequestUrl 方法获取空路径报错问题 -* update 去除same-token有限期配置,使用默认配置(一天) -* update 优化固定头部页签滚动条被隐藏的问题 -* update delete vue-multiselect style -* update 按代码规范补全重写注解 -* update 优化 极端情况获取LoginUser可能为null问题 -* update 优化 更改系统所有服务日志配置文件命名为 logback-plus.xml 避免与其他框架默认配置冲突 -* update 优化 skywalking-agent 探针日志等级调整为 WARN 减少无用日志输出 -* update 优化 加解密模块 将null判断下推防止任何可能的null出现 -* update 优化 在线用户token获取方式 -* update 优化 用户更改角色 踢掉角色相关所有在线用户 - -### 新功能 - -* add 集成 ip2region 实现离线IP地址定位库 -* add 增加 邮箱验证码发送接口 -* add 增加 邮箱登陆接口 -* add 增加 EncryptUtils 加解密安全工具类 可以处理base64,aes,sm4,sm2,rsa,md5,sha256加解密 -* add 增加 EncryptUtils 类中增加国密sm3的不可逆加密算法 -* add 新增 忽略数据权限写法 防止异常不执行关闭问题 - -### 问题修复 - -* fix 修复 MybatisExceptionHandler 未自动装载问题 -* fix 修复 代码生成 点选按钮不生效问题 -* fix 修复 Nacos 服务 SpringBoot-admin 客户端功能失效问题 -* fix 修复 findInSet 在mysql下方法搜索非数字字段时 无引号报错问题 -* fix 修复 ruoyi-demo postgres 数据库用户名密码变量错误 -* fix 修复 oracle postgres 数据库日志表索引创建错误 -* fix 修复 无法注入 mailProperties 导致 resource 模块无法启动问题 -* fix 修复tab栏”关闭其他“异常的问题 -* fix 修复 加解密拦截器 对象属性为null问题 -* fix 修复 取消oss预览状态修改 图标变化不正常问题 -* fix 修复 nacos 新版本升级后 与 docker 基础镜像系统存在兼容性问题 - - -## v1.6.0 - 2023-03-14 - -### 重大更新 - -[重大更新] add 新增 通用翻译模块 `ruoyi-common-translation` 实现(部门名、字典、oss、用户名) -[重大更新] add 新增 数据加解密模块 `ruoyi-common-encrypt` - - -### 依赖升级 - -* update springboot 2.7.7 => 2.7.9 -* update springcloud 2021.0.5 => 2021.0.6 -* update easyexcel 3.1.5 => 3.2.1 -* update redisson 3.19.1 => 3.20.0 -* update springdoc 1.6.14 => 1.6.15 -* update hutool 5.8.12 => 5.8.15 (13与14有问题勿使用) -* update logstash-sdk 7.1.1 => 7.2 -* update aws-java-sdk-s3 1.12.373 => 1.12.400 -* update tencent-sms 3.1.660 => 3.1.687 -* update skywalking 8.9.1 => 9.3.0 -* update skywalking-agent 8.13.0 => 8.14.0 -* update dubbo 3.1.4 => 3.1.7 解决dubbo报一些无用警告问题 -* update element-ui 2.15.10 => 2.15.12 - -### 功能更新 - -* update 优化 修改 oss 配置页面开关说明 避免造成误解 -* update 优化 `gateway` 对接 `sentinel` 使用网关特定模式 -* update 优化 转移 `logback-common` 配置到 `common-web` 模块 `gateway` 单独处理 -* update 优化 调整连接池默认参数 -* update 优化 `zookeeper` 自带控制台占用 `8080` 端口 -* update 优化 `DictDataMapper` 注解标注过期 推荐使用 `@Translation` 注解 -* update 优化 获取菜单数据权限接口 删除无用角色属性与逻辑 -* update 优化 调整连接池最长生命周期 防止出现警告 -* update 优化 连接池增加 `keepaliveTime` 探活参数 -* update 优化 `DataPermissionHelper` 增加 `开启/关闭` 忽略数据权限功能 -* update 重构 `OssFactory` 加载方式 改为每次比对配置做实例更新 -* update 优化 更新角色后踢掉所有相关的登录用户 用户量过大会导致redis阻塞卡顿(应粉丝要求) -* update 优化 翻译组件 支持返回值泛型 支持多种类型数据翻译(例如: 根据主键翻译成对象) -* update 优化 `tagsView` 右选框,首页不应该存在关闭左侧选项 -* update 优化 `copyright 2023` -* update 优化 日志注解支持排除指定的请求参数 -* update 优化 业务校验优化代码 -* update 优化 日志管理使用索引提升查询性能 -* update 优化 框架时间检索使用时间默认值 `00:00:00 - 23:59:59` -* update 优化 oss 预览使用 `ImagePreview` 组件 -* update 优化 统一登录接口令牌key - - -### 新功能 - -* add 新增 数据加解密模块 测试案例 -* add 新增 `StringUtils` `splitTo` 与 `splitList` 方法 优化业务代码 - -### 问题修复 - -* fix 修复 vue3模板 删除功能书写错误 -* fix 修复 部分服务未开启日志存储 -* fix 修复 接口问题开关不生效问题 -* fix 修复 优化文件下载出现的异常 -* fix 修复 修改密码日志存储明文问题 -* fix 修复 代码生成 `postgreSQL` 查出多余的已删除字段 - -## v1.5.0 - 2023-01-13 - -### 重大更新 - -* [重大更新] 框架主体业务与代码生成器 完成 oracle postgres 多数据库类型支持(中间件不支持) -* [重大更新] 使用 spring 事件发布机制 重构登录日志与操作日志 支持多事件监听无入侵扩展 -* 例如: 可以增加一个监听者将日志上传至ES等存储 对原有逻辑无影响 - -### 依赖升级 - -* update springboot 2.7.6 => 2.7.7 -* update springboot-admin 2.7.7 => 2.7.10 -* update dubbo 3.1.3 => 3.1.4 -* update seata 1.5.2 => 1.6.1 适配升级 -* update nacos 2.1.2 => 2.2.0 适配升级 -* update mybatis-plus 3.5.2 => 3.5.3.1 -* update sa-token 1.33.0 => 1.34.0 -* update springdoc 1.6.13 => 1.6.14 -* update snakeyaml 1.32 => 1.33 -* update easyexcel 3.1.3 => 3.1.5 -* update redisson 3.18.0 => 3.19.1 -* update easy-es 1.1.0 => 1.1.1 -* update hutool 5.8.10 => 5.8.11 -* update aws-s3 1.12.349 => 1.12.373 -* update aliyun-sms 2.0.22 => 2.0.23 -* update tencent-sms 3.1.635 => 3.1.660 -* update echarts 4.9.0 => 5.4.0 - -### 功能更新 - -* update 优化 BaseMapperPlus 使用 MP V3.5.3 新工具类 Db 简化批处理操作实现 -* update 优化 demo服务 过滤健康检查 sql 打印 -* update 优化 代码生成与框架主体使用相同的主键生成器 全局统一避免问题 -* update 优化 系统登录 使用单表查询校验用户 避免多次join查询 -* update 优化 适配框架多数据库支持 完成 oracle postgres 数据库适配(放弃 sqlserver 适配 原因: 基础中间件均不支持) -* update 优化 删除主 sql 内无用数据 -* update 优化 删除 vue3 模板无用参数 -* update 优化 重构 ExcelUtil 全导出方法支持 OutputStream 流导出 不局限于 response -* update 优化 maven 地址切换回 aliyun 仓库 -* update 优化 springdoc 配置鉴权头写死问题 增加持久化鉴权头配置 -* update 优化 actuator 依赖整合到 common-web 模块 -* update 优化 验证码结果使用 spel 引擎自动计算 -* update 优化 数据权限处理器 变量命名错误 -* update 优化 去除 RedisUtils 无用继承 -* update 优化 弹窗内容过多展示不全问题 -* update 优化 删除 fuse 无效选项 maxPatternLength -* update 优化 minio 安装警告 使用新版本参数 -* update 优化 使用 spring 事件发布机制 重构登录日志与操作日志 -* update 优化 使用 spring 事件机制 重构 OssConfig 缓存更新 -* update 优化 单元格合并判断cellValue是否相等方法 -* update 优化 调整 gateway 拦截器执行顺序 优先处理 xss 过滤 然后进行缓存处理 - -### 新功能 - -* add 增加 GET 请求提交日期参数 默认格式化配置 -* add 增加 RedisUtils 检查缓存对象是否存在方法 -* add 增加 oracle postgres docker编排 -* add 新增 代码生成器适配 多数据库可切换生成代码 -* add 新增 oracle postgres 数据库框架sql脚本 -* add 增加 DataBaseHelper 数据库助手 用于适配多类型数据库 -* add 新增 BeanCopyUtils#mapToMap 方法 - -### 问题修复 - -* fix 修复 注册页面 验证码开关不生效问题 -* fix 修复 新版本 dubbo-filter-seata 插件内核与seata不一致问题(临时) -* fix 修复 根据 key 更新参数配置报 null 问题 -* fix 修复 用户注册 用户类型字段书写错误 -* fix 修复 代码生成图片/文件/单选时选择必填无法校验问题 -* fix 修复 修改参数键名时 未移除过期缓存配置 -* fix 修复 内网鉴权 Filter 优先级问题 导致 websocket 连接失败 -* fix 修复 gateway 流控规则生效但不显示问题 -* fix 修复 新版本 Redisson 存在与 boot 2.X 的兼容性问题 - -## v1.4.0 - 2022-12-01 - -### 重大更新 -* [重大更新] 新增 对接 skywalking 全功能(详细看下方新功能列表) -* [重大更新] 重构 ruoyi-nacos 使用官方依赖整合 解决一些问题 并升级 2.1.2 版本 -* [重大更新] 新增 oss 私有库功能(数据库结构改动 需执行升级sql) -* [重大更新] 优化 数据源连接池从 druid 切换到 hikari(原因看文档) -* [重大更新] 新增 对接 prometheus + grafana 全功能(详细看下方新功能列表) - -### 依赖升级 -* update springcloud 2021.0.4 => 2021.0.5 -* update springboot 2.7.4 => 2.7.6 -* update springboot-admin 2.7.5 => 2.7.7 -* update springdoc 1.6.11 => 1.6.13 -* update poi 5.2.2 => 5.2.3 -* update hutool 5.8.6 => 5.8.10 -* update aliyun-sms 2.0.18 => 2.0.22 -* update tencent-sms 3.1.591 => 3.1.611 -* update sa-token 1.30.0 => 1.33.0 -* update redisson 3.17.6 => 3.18.0 -* update easy-es 1.0.2 => 1.1.0 -* update easyexcel 3.1.1 => 3.1.3 -* update lock4j 2.2.2 => 2.2.3 -* update s3-adk 1.12.300 => 1.12.349 -* update sentinel 1.8.5 => 1.8.6 -* update nacos 2.1.1 => 2.1.2 -* update ELK 7.17.2 => 7.17.6 升级镜像版本 -* update nginx 1.21.6 => 1.22.1 修复漏洞 -* update mysql-docker 8.0.29 => 8.0.31 - -### 功能更新 -* update 优化 分页对象 PageQuery 支持多排序 适配 文件管理 页面支持多排序 -* update 优化 获取用户信息getInfo接口 使用缓存数据获取 -* update 优化 rpc文件上传 增加 ossId 数据返回 -* update 优化 nacos 集群模式搭建 关于 nacos.home 注释说明 -* update 优化 修改头像在小屏幕上页面布局错位的问题 -* update 优化 oss 云厂商增加 华为obs关键字 -* update 优化 重置时取消部门选中 -* update 优化 新增返回警告消息提示 -* update 优化 抽取 logback 通用配置 logback-common.xml 简化其他服务日志文件书写 -* update 更改 nacos 配置文件目录 从dev文件夹迁移到nacos文件夹与其他配置区分 -* update 优化 gateway 只缓存body -* update 优化 Dockerfile 创建目录命令简化操作 -* update 优化 gateway filter顺序 与 代码工具封装 -* update 优化 将空 catch 块形参重命名为 ignored -* update 优化 satoken 依赖传递 -* update 优化 重写字典查询 使用本地缓存优化网络开销 提升到上级实现减少rpc调用频率 使用流处理减少字符串操作 -* update 优化 减小腾讯短信引入jar包的体积 -* update 优化 简化一些方法的写法 -* update 优化 消除Vue3控制台出现的警告信息 -* update 优化 忽略不必要的属性数据返回 -* update 优化 重构 mysql-jdbc 依赖到 mybatis 包内 替换为最新坐标 - -### 新功能 -* add 新增 所有服务 docker 部署对接 skywalking -* add 新增 三大 mq 整合 skywalking -* add 新增 seata 整合 skywalking 手动编译 seata 插件包 -* add 新增 ruoyi-common-skylog 整合 skywalking 日志推送 -* add 增加 skywalking docker编排 -* add 增加 ruoyi-seata-server redis模式配置 -* add 新增 ruoyi-common-prometheus 模块 用于对接 prometheus 监控 -* add 新增 docker prometheus + grafana 容器编排 -* add 新增 ruoyi-monitor 监控服务 提供 prometheus http_sd 服务发现功能 -* add 新增 所有服务整合 ruoyi-common-prometheus 模块 -* add 新增 grafana 监控大屏配置文件(框架定制) -* add 新增 使用 mica-metrics 为 undertow 提供健康检查 -* add 新增 字典数据映射翻译注解 -* add 增加 RedisUtils 获取缓存Map的key列表 - -### 问题修复 -* fix 修复 开启账号同端互斥登录 被顶掉后登出报null异常问题 -* fix 修复 设置NameMapper导致队列功能异常问题 -* fix 修复 EnvironmentPostProcessor 不生效问题 -* fix 修复 文件上传组件格式验证问题 -* fix 修复 ruoyi-xxl-job-admin 服务健康检查配置缺失问题 -* fix 修复 Excel导出字典值转换方法由于内部调用缓存不生效bug -* fix 修复 SysOss 方法内部调用导致缓存不生效 bug -* fix 修复 主题颜色在Drawer组件不会加载问题 -* fix 修复 修改用户信息 校验用户名未排除当前用户问题 -* fix 修复 升级 nginx 修复漏洞 https://www.oschina.net/news/214309 -* fix 修复 用户编辑时角色和部门存在无法修改情况 -* fix 修复 RemoteDictServiceImpl 代理对象获取异常bug -* fix 修复 菜单激活无法填充颜色 去除某些svg图标的fill属性 -* fix 修复 使用透明底png图片时, 自动填充黑色背景 -* fix 修复 table中更多按钮切换主题色未生效修复问题 -* fix 修复 dubbo 使用 tri 协议 header 请求头变为小写导致无法获取参数问题 -* fix 修复 DubboRequestFilter 优先级过高导致的 skywalking tid 取不到问题 -* fix 修复 前端脚本乱码问题 -* fix 修复 WebFluxUtils 读取空 body 报 null 问题 -* fix 修复 Log注解GET请求记录不到参数问题 -* fix 修复 某些特性的环境生成代码变乱码TXT文件问题 -* fix 修复 开启TopNav没有子菜单隐藏侧边栏 -* fix 修复 回显数据字典数组异常问题 -* fix 修复 升级 satoken 导致白名单热更不生效问题 -* fix 修复 swagger 版本与 springdoc 版本不一致导致找不到class问题 -* fix 修复 grafana 监控模板绑定数据源ID 导致无法正常读取数据问题 - -## v1.3.0 - 2022-09-29 - -### 重大更新 - -* [重大更新] 新增 ruoyi-nacos 源码集成 nacos 服务端控制台 支持单机/集群模式 -* [重大更新] 重写 spring-cache 实现 更人性化的操作 支持注解指定ttl等一些参数 -* [重大更新] 新增 RuoYi-Cloud-Plus-UI 项目 Vue3 前端分支 -* [重大更新] 移除maven docker插件 过于老旧功能缺陷大 使用idea自带的docker插件替代 -* [重大更新] 优化 ruoyi-common-job 支持通过调度中心服务名注册 xxl-job-admin -* [重大更新] 新增 ruoyi-common-sentinel 模块 支持使用服务名注册 sentinel 控制台 - -### 依赖升级 - -* update spring-cloud 2021.0.3 => 2021.0.4 -* update springboot 2.7.2 => 2.7.4 -* update springboot-admin 2.7.3 => 2.7.5 -* update sentinel 1.8.4 => 1.8.5 集成新 dubbo3 插件 -* update springdoc 1.6.9 => 1.6.11 -* update easy-es 0.9.80 => 1.0.2 -* update dubbo 3.0.10 => 3.1.1 -* update redisson 3.17.5 => 3.17.6 -* update druid 1.2.11 => 1.2.12 -* update hutool 5.8.5 => 5.8.6 -* update dynamic-ds 3.5.1 => 3.5.2 -* update aws-java-sdk-s3 1.12.264 => 1.12.300 -* update aliyun-sms 2.0.16 => 2.0.18 -* update tencent-sms 3.1.555 => 3.1.591 -* update snakeyaml 1.30 => 1.32 - -### 功能更新 - -* update 优化 getLoginId 增加必要参数空校验 -* update 优化 将 elasticsearch 解压后放入 避免造成用户误解 -* update 优化 修改资料头像与部门被覆盖的问题 -* update 优化 字典管理操作类型新增其他 -* update 优化 使用 spring-cache 注解优化缓存 -* update 优化 easy-es.enable=false 关闭 actuator 健康检查 -* update 优化 优化多角色数据权限匹配规则 -* update dubbo 升级 3.1.0 删除自行处理的源码修复 采用官方修复后的代码 -* update 优化 页面内嵌iframe切换tab不刷新数据 -* update 优化 调整 oss表key 与 ossconfig的service 字段长度不匹配 -* update 优化 操作日志密码脱敏 -* update 优化 补全缺失的接口 更改更新日志链接 -* update 优化 插入 SysOperLog 时, 限制 operUrl 属性的长度 -* update 优化 satoken 鉴权拦截器 优化多次校验 - -### 新功能 - -* add 增加 项目中使用到的请求头放行跨域 -* add 新增 获取oss对象元数据方法 -* add 新增 字典管理操作类型 其他 - -### 问题修复 - -* fix 修复 个人中心卡死或鼠标点击和键盘输入无效 -* fix 修复 BaseMapperPlus 方法命令不一致问题 -* fix 修复 图片预览组件src属性为null值控制台报错问 -* fix 修复 短信功能是否启用判断不生效 -* fix 修复 web模块 不引入nacos依赖报错问题 -* fix 修复 sentinel 构建无法读取webapp目录问题 -* fix 修复 菜单管理遗漏的prop属性 -* fix 修复 minio配置https遇到的问题 -* fix 修复 点击删除后点击取消控制台报错问题 -* fix 修复 文件/图片上传组件 第一次上传报错导致后续上传无限loading问题 -* fix 修复 ruoyi-auth 服务与 elasticsearch 端口号冲突问题 -* fix 修复 ruoyi-resource 服务与 elasticsearch 端口号冲突问题 -* fix 修复 角色部门状态字典错误 与 菜单注释错误 -* fix 修复 hutool 存在多版本问题 -* fix 修复 openapi结构体 因springdoc缓存导致多次拼接接口路径问题 -* fix 修复 oss配置删除内部数据id匹配类型问题 -* fix 修复 没有权限的用户编辑部门缺少数据 -* fix 修复 用户导入存在则更新不生效 -* fix 修复 日志转换非json数据导致报错 -* fix 修复 p6spy输出sql语句时间格式化不正确问题 -* fix 修复 不同网段因reset请求头导致下载导出跨域问题 -* fix 修复 在线用户设置永不过期 超时时间-1推送redis无效问题 -* fix 修复 snakeyaml 1.31 依旧存在漏洞 升级 1.32 - -## v1.2.0 - 2022-08-09 - -### 重大更新 - -* [重大更新] 新增 ruoyi-common-elasticsearch 模块 集成 easy-es 傻瓜式操作搜索引擎 -* [重大更新] 新增 ruoyi-common-doc 整合 springdoc 基于 javadoc 实现无注解零入侵生成接口文档 -* [不兼容更新] 移除 swagger 所属 ruoyi-doc ruoyi-common-swagger 两个模块 建议使用 ruoyi-common-doc 模块 - -### 依赖升级 - -* update springboot 2.6.9 => 2.7.2 重构使用最新自动配置方式 -* update springboot-admin 2.6.7 => 2.7.3 -* update dubbo 3.0.9 => 3.0.10 -* update redisson 3.17.4 => 3.17.5 -* update hutool 5.8.3 => 5.8.5 -* update okhttp 4.9.1 => 4.10.0 -* update aws-java-sdk-s3 1.12.248 => 1.12.264 修复依赖安全漏洞 -* update aliyun.sms 2.0.9 => 2.0.16 -* update tencent.sms 3.1.537 => 3.1.555 -* update guava 30.0-jre => 31.1-jre - -### 功能更新 - -* update 修改 资源服务 不提供默认短信 sdk 依赖 -* update 优化表格上右侧工具条(搜索按钮显隐&右侧样式凸出) -* update 优化 前后端多环境部署保持一致 删除无用环境文件 -* update 优化 错误登录锁定与新增解锁功能 -* update 优化字典数据使用store存取 -* update 优化布局设置使用el-drawer抽屉显示 -* update 更新框架文档 专栏与视频 链接地址 -* update 优化 对象上传 主动设置文件公共读 解决天翼云OSS文件私有问题 -* update 优化 网关验证码过滤器 路径匹配改为严格匹配 -* update 优化 数据导致权限生成 SQL 重复问题 - -### 新功能 - -* add 增加 全局跨域过滤器 处理跨域请求 适配移动端访问 -* add 增加 搜索引擎 crud 演示案例 - -### 问题修复 - -* fix 防止date-picker组件报错,降级element-ui版本 -* fix 修复 RedisUtils 并发 set ttl 错误问题 -* fix 防止vue3主键字段名与row或ids一致导致报错的问题 -* fix 修复 幂等组件 逻辑问题导致线程变量未清除 -* fix 修复 图片回显查询 路径错误问题 -* fix 修复 脱敏没有实现类导致返回数据异常问题 -* fix 修复 xxljob 错误导入配置文件引发的问题 -* fix 修复 gateway模块 dockerfile 端口编写错误 -* fix 修复用户导出字典使用错误 -* fix 修复 demo 模块 远程调用失败问题 -* fix 修复 sentinel 控制台未适配 springboot 2.6 新路由策略导致无法登录问题 - -## v1.1.0 - 2022-07-18 - -### 重大更新 - -* [重大更新] 新增 ELK 分布式日志中心整合 -* [重大更新] 新增 ruoyi-stream-mq 演示模块 完成 RabbitMQ RocketMQ Kafka 整合 -* [重大更新] 优化 docker 部署方式 使用 host 模式简化部署流程 降低使用成本 -* [重大更新] 调整 dubbo 服务注册命名空间与 cloud 服务保持一致 通过注册组区分访问服务 -* [安全性] 优化 nginx 限制外网访问内网 actuator 相关路径 建议升级 - -### 依赖升级 - -* update springboot 2.6.8 => 2.6.9 -* update easyexcel 3.1.0 => 3.1.1 -* update hutool 5.8.2 => 5.8.3 -* update redisson 3.17.2 => 3.17.4 -* update aws-java-sdk-s3 1.12.215 => 1.12.248 -* update tencentcloud-sdk-java 3.1.500 => 3.1.537 -* update dubbo 3.0.8 => 3.0.9 -* update seata 1.5.1 => 1.5.2 - -### 功能更新 - -* update 增加 redisson key 前缀配置 -* update 优化 DateColumn 支持单模板多key场景 -* update 优化部署脚本 增加 elk kafka rabbitmq rocketmq 等配置 -* update 修改 oss 客户端自定义域名 统一使用https开关控制协议头 -* update 优化 使用 StreamUtils 简化业务流操纵 -* update 优化 ruoyi-demo 模块 去除用不上的 seata 依赖 -* update 优化 接口文档 接口地址与服务地址不匹配问题 -* update 优化字典数据回显样式下拉框显示值 -* update 默认不启用压缩文件缓存防止node_modules过大 -* update 优化登出方法 - -### 新功能 - -* add 增加 rocketmq docker编排 -* add 新增 rabbitmq docker编排 包含延迟插件 -* add 新增 kafka docker编排 -* add 增加 es ik 分词器插件集成 -* add 增加 StreamUtils 流工具 简化 stream 流操纵 - -### 问题修复 - -* fix 修复 获取 SensitiveService 空问题 增加空兼容 -* fix 修复 演示页面导出路径错误 -* fix 修复 minio 上传自定义域名回显路径错误问题 -* fix 修复 hutool 工具返回不可操纵类型 导致报错问题 -* fix 修复 远程调用短信功能返回实体 SysSms 序列化报错问题 -* fix 修复 复制过程错误 导致演示excel文件损坏问题 -* fix 修复 dubbo 注册组不生效问题 通过覆盖源码方式 -* fix 修复代码生成首字母大写问题 - - -## v1.0.0 - 2022-06-20 - -### 新增/优化 工程模块 - -* add 新增 ruoyi-common-alibaba-bom 工程管理 alibaba 相关依赖 -* add 新增 ruoyi-common-bom 工程管理 ruoyi-common 相关依赖 -* add 新增 ruoyi-api-bom 工程管理 ruoyi-api 依赖项 -* add 新增 ruoyi-api-resource 模块 规范用法 移除 ruoyi-file 模块 -* add 新增 ruoyi-common-web 模块 使用 undertow 替换 tomcat -* add 新增 ruoyi-common-dubbo 整合 dubbo 3.X 实现高性能 rpc 远程调用 替换 feign -* add 新增 ruoyi-common-dict 实现字典多服务调用 -* add 新增 ruoyi-common-loadbalancer 自定义负载均衡模块 用于多团队开发 -* add 新增 ruoyi-common-excel 模块 集成 Alibaba EasyExcel 替换 自带excel实现 -* add 新增 ruoyi-common-oss 模块 支持 AWS S3 协议 分布式文件存储 -* add 新增 ruoyi-common-mail 邮件模块 -* add 新增 ruoyi-common-sms 短信模块 整合 阿里云、腾讯云 短信功能 -* add 新增 ruoyi-common-idempotent 分布式幂等模块 -* add 新增 ruoyi-common-satoken 整合 sa-token 重写所有权限 -* add 新增 ruoyi-xxl-job-admin 整合 xxljob 替换 quartz 支持分布式任务调度 -* add 新增 ruoyi-job 模块 统一远程处理任务 规范用法 -* add 新增 ruoyi-doc 模块 集成 Knife4j 替换 swagger -* add 新增 ruoyi-seata-server 源码集成 Seata 1.5.X 服务端 -* add 新增 ruoyi-sentinel-dashboard 模块 源码集成 sentinel 控制台 -* update 抽取所有公用配置到 maven profile 管理 - -### 代码依赖改动 - -* update SpringCloud 2021.0.3 -* update 适配 SpringCloudAlibaba 2021.0.1.0 全新配置方式 -* update poi 4.1.2 => 5.2.2 性能大幅提升 -* update 重构 整合 jackson 替换 fastjson -* update 重构 整合 redisson 客户端 -* update 重构 整合 mybatis-plus -* update 重写 数据权限实现 基于 mybatis-plus -* add 增加 lombok 优化原生代码 -* add 整合 hutool 优化相关代码 -* add 新增 国际化 功能 -* add 新增 lock4j 分布式锁 -* add 增加监控中心 在线日志监控 优化日志文件格式 -* add 适配 docker 部署方式 - -### 后续/进行中计划 - -* 增加 Vue3 前端工程 -* 应用模块 适配 Oracle、PostgreSQL、SQLServer -* 增加 SpringCloud Stream 支持 -* 适配 Apache Kafka、Apache RocketMQ、RabbitMQ -* 适配 ElasticSearch 分布式搜索引擎 -* 适配 Alibaba Canal 分布式数据同步中心 -* 适配 Apache SkyWalking 分布式链路追踪监控中心 -* 适配 ELK 分布式日志中心 -* 适配 Prometheus、Grafana 分布式全方位数据大屏监控 diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/elk.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/elk.md deleted file mode 100644 index 58c2eda8..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/elk.md +++ /dev/null @@ -1,37 +0,0 @@ -# ELK搭建 -- - - -# 环境搭建 - -项目内置 `ELK` 的 `docker-compose` 编排 可查看 `/docker/docker-compose.yml` 文件下方扩展编排 - -**注意: `/docker/elk/elasticsearch/` 目录下所有文件夹 均需要写权限** - -`chmod 777 /docker/elk/elasticsearch/data`
-`chmod 777 /docker/elk/elasticsearch/logs`
-`chmod 777 /docker/elk/elasticsearch/plugins`
-**注意: es插件需要解压后放入 `plugins` 目录** - -# 运行命令 - -```shell -docker-compose up -d elasticsearch kibana logstash -``` - -# 参考文章 -[docker-compose 搭建 ELK 7.X 并整合 SpringBoot](https://lionli.blog.csdn.net/article/details/125743132) - -# 项目内配置 - -服务引入依赖项 - -```xml - - - com.ruoyi - ruoyi-common-logstash - -``` - -更改主 `pom` 文件 `logstash.address` 地址
- -![输入图片说明](https://foruda.gitee.com/images/1678981534923588112/ba6cb5b7_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/es.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/es.md deleted file mode 100644 index 65d9c4d4..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/es.md +++ /dev/null @@ -1,26 +0,0 @@ -# ES搜索引擎 -- - - -## 环境搭建(如果已经搭建了ELK则跳过) - -项目内置 `ELK` 的 `docker-compose` 编排 可查看 `/docker/docker-compose.yml` 文件下方扩展编排 - -**注意: `/docker/elk/elasticsearch/` 目录下所有文件夹 均需要写权限** - -`chmod 777 /docker/elk/elasticsearch/data`
-`chmod 777 /docker/elk/elasticsearch/logs`
-`chmod 777 /docker/elk/elasticsearch/plugins`
-**注意: es插件需要解压后放入 `plugins` 目录** - -## 运行命令 - -```shell -docker-compose up -d elasticsearch -``` - -## Easy-ES 文档 -[Easy-ES 文档](https://www.easy-es.cn/) - -## 用法 - -基本配置和用法可参考 `ruoyi-demo` 模块 更多高级用法请参考 Easy-ES 文档
-![输入图片说明](https://foruda.gitee.com/images/1660030085169129908/屏幕截图.png "屏幕截图.png") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/kafka.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/kafka.md deleted file mode 100644 index 78521431..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/kafka.md +++ /dev/null @@ -1,9 +0,0 @@ -# Kafka搭建 -- - - -## 环境搭建 -参考文章: [docker-compose 安装 Kafka 3.X 附带可视化界面](https://lionli.blog.csdn.net/article/details/125855550) - -## 用法参考 -参考 `ruoyi-stream-mq` 模块内的测试案例 - -![输入图片说明](https://foruda.gitee.com/images/1660031528265343174/屏幕截图.png "屏幕截图.png") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/maxkey.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/maxkey.md deleted file mode 100644 index 4b4b4305..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/maxkey.md +++ /dev/null @@ -1,20 +0,0 @@ -# 对接 MaxKey 单点登录 -- - - - -# 安装 MaxKey 应用服务 - -参考 MaxKey 官方文档安装 [MaxKey安装部署](http://www.maxkey.top/doc/docs/intro/) - -# 配置应用 OAuth2.0 认证注册 - -![输入图片说明](https://foruda.gitee.com/images/1693377802128677240/0927270a_1766278.png "屏幕截图") - -# 配置后端服务 - -找到 `Nacos` 内的 `ruoyi-auth.yml` 配置文件 - -修改 `maxkey` 对应的 `client-id` 与 `client-secret` - -![输入图片说明](https://foruda.gitee.com/images/1693378118762354596/2f02c8a3_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1693378168538263792/24476d2a_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/nacos.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/nacos.md deleted file mode 100644 index 18e6aefb..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/nacos.md +++ /dev/null @@ -1,13 +0,0 @@ -# Nacos集群搭建 -- - - -## 集群搭建两种方式 -### 文件寻址集群 -[【RuoYi-Cloud-Plus】学习笔记 02 - Nacos(二)寻址机制之文件寻址分析](https://blog.csdn.net/Michelle_Zhong/article/details/127423521) - -### 地址服务器寻址集群(推荐) -[【RuoYi-Cloud-Plus】学习笔记 03 - Nacos(三)使用 Nginx 实现地址服务器寻址及其原理分析](https://blog.csdn.net/Michelle_Zhong/article/details/127474238) - -## 集群路由代理设置 -[【RuoYi-Cloud-Plus】学习笔记 04 - Nacos(四)使用 Nginx 简单实现 Nacos 集群负载均衡](https://blog.csdn.net/Michelle_Zhong/article/details/127486350) - -设置好代理之后 跟单机用法一致 后端nacos地址写代理 `ip:端口` 即可 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/prometheus_grafana.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/prometheus_grafana.md deleted file mode 100644 index 2df4870b..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/prometheus_grafana.md +++ /dev/null @@ -1,45 +0,0 @@ -# Prometheus+Grafana搭建 -- - - -## 基础搭建 - -参考文章: https://lionli.blog.csdn.net/article/details/127959009 - -## 框架内扩展 - -框架已经包含了 docker-compose 编排 执行如下命令启动容器即可 - -```shell -docker-compose up -d prometheus grafana -``` - -## 应用配置 - -各个服务引入 `ruoyi-common-prometheus` 模块 - -![输入图片说明](https://foruda.gitee.com/images/1668998415863943539/413dc560_1766278.png "屏幕截图") - -修改 `prometheus.yml` 配置采集数据源 - -![输入图片说明](https://foruda.gitee.com/images/1668998433756761442/bf31c212_1766278.png "屏幕截图") - -修改 `Nacos` 地址 与 `SpringBoot-Admin` 监控地址 用于数据采集
-如都为本地应用则无需更改 - -![输入图片说明](https://foruda.gitee.com/images/1668998317973042740/2d3590ec_1766278.png "屏幕截图") - -## 导入框架特制模板 -**注意: 此处数据源名称必须与图片保持一致 不然会和模板对应不上导致无法读取数据**
-![输入图片说明](https://foruda.gitee.com/images/1669866309495145064/1de987ce_1766278.png "屏幕截图") - -> 找到框架内的特制模板json文件 在grafana点击上传json文件 导入模板
- -![输入图片说明](https://foruda.gitee.com/images/1668998149634542527/f0881c8e_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1668998179391197847/b1d3a630_1766278.png "屏幕截图") - -## 选择查看监控 - -点击右侧菜单浏览 选择想要查看的监控即可 - -![输入图片说明](https://foruda.gitee.com/images/1668998515814170229/817ac8b0_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1668998567335384306/acdf2833_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1668998616894681785/ac27538b_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/rabbitmq.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/rabbitmq.md deleted file mode 100644 index 75e0187c..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/rabbitmq.md +++ /dev/null @@ -1,10 +0,0 @@ -# RabbitMQ搭建 -- - - -## 环境搭建 - -参考文章: [docker-compose 安装 RabbitMQ 3.X 附带延迟队列插件](https://lionli.blog.csdn.net/article/details/125855177) - -## 用法参考 -参考 `ruoyi-stream-mq` 模块内的测试案例 - -![输入图片说明](https://foruda.gitee.com/images/1660031371503504748/屏幕截图.png "屏幕截图.png") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/rocketmq.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/rocketmq.md deleted file mode 100644 index 98d50bb7..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/rocketmq.md +++ /dev/null @@ -1,9 +0,0 @@ -# RocketMQ搭建 -- - - -## 环境搭建 -参考文章: [docker-compose 安装 RocketMQ 4.9.X (apache官方镜像) namesrv broker 与可视化控制台 console](https://lionli.blog.csdn.net/article/details/125798865) - -## 用法参考 -参考 `ruoyi-stream-mq` 模块内的测试案例 - -![输入图片说明](https://foruda.gitee.com/images/1660031496623275622/屏幕截图.png "屏幕截图.png") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/shardingproxy.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/shardingproxy.md deleted file mode 100644 index ebe461bc..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/shardingproxy.md +++ /dev/null @@ -1,75 +0,0 @@ -# Sharding-Proxy搭建分库分表 -- - - - -# 如何使用 - -查看 `ruoyi-demo` 服务 `TestShardingController` - -![输入图片说明](https://foruda.gitee.com/images/1688014028842337522/cd26026a_1766278.png "屏幕截图") - -## 首先在 MySQL 创建两个库 - -创建两个库 `data-center_0` `data-center_1` 分别执行如下SQL - -```sql -CREATE TABLE `t_order_0` ( - `order_id` bigint(20) UNSIGNED NOT NULL COMMENT '主键ID', - `user_id` bigint(20) UNSIGNED NOT NULL COMMENT '用户ID', - `total_money` int(10) UNSIGNED NOT NULL COMMENT '订单总金额', - PRIMARY KEY (`order_id`), - KEY `idx_user_id` (`user_id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单总表'; - -CREATE TABLE `t_order_1` ( - `order_id` bigint(20) UNSIGNED NOT NULL COMMENT '主键ID', - `user_id` bigint(20) UNSIGNED NOT NULL COMMENT '用户ID', - `total_money` int(10) UNSIGNED NOT NULL COMMENT '订单总金额', - PRIMARY KEY (`order_id`), - KEY `idx_user_id` (`user_id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单总表'; - -CREATE TABLE `t_order_item_0` ( - `order_item_id` bigint(20) UNSIGNED NOT NULL COMMENT '子订单ID', - `order_id` bigint(20) UNSIGNED NOT NULL COMMENT '主键ID', - `user_id` bigint(20) UNSIGNED NOT NULL COMMENT '用户ID', - `money` int(10) UNSIGNED NOT NULL COMMENT '子订单金额', - PRIMARY KEY (`order_item_id`), - KEY `idx_order_id` (`order_id`) USING BTREE, - KEY `idx_user_id` (`user_id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单子表'; - -CREATE TABLE `t_order_item_1` ( - `order_item_id` bigint(20) UNSIGNED NOT NULL COMMENT '子订单ID', - `order_id` bigint(20) UNSIGNED NOT NULL COMMENT '主键ID', - `user_id` bigint(20) UNSIGNED NOT NULL COMMENT '用户ID', - `money` int(10) UNSIGNED NOT NULL COMMENT '子订单金额', - PRIMARY KEY (`order_item_id`), - KEY `idx_order_id` (`order_id`) USING BTREE, - KEY `idx_user_id` (`user_id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单子表'; - -``` - -## 然后更改配置文件 - -更改 `config-sharding.yaml` 配置文件内的数据库连接地址与用户名密码 - -## 服务搭建 - -参考部署文档上传 docker 文件夹 内部包含 `shardingproxy` 配置文件 - -![输入图片说明](https://foruda.gitee.com/images/1688013921062151295/89652dda_1766278.png "屏幕截图") - -框架已经包含了 docker-compose 编排 执行如下命令启动容器即可 - -```shell -docker-compose up -d shardingproxy -``` - -## 最后运行 demo - -运行 demo 提供的 controller 代码查看数据库内数据即可 - -## 用法参考视频(略有不同 理性观看) - -用法参考视频: https://www.bilibili.com/video/BV1XN411A7Tv/ diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/skywalking.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/skywalking.md deleted file mode 100644 index 6ad0aecc..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/skywalking.md +++ /dev/null @@ -1,41 +0,0 @@ -# SkyWalking搭建与集成 -- - - -## 服务搭建 -参考文章: [SpringBoot 整合 SkyWalking 8.X (包含 Logback 日志采集)](https://lionli.blog.csdn.net/article/details/127656534) - -框架已经包含了 docker-compose 编排 执行如下命令启动容器即可 - -```shell -docker-compose up -d elasticsearch sky-oap sky-ui -``` - -### 本地开发使用 -参考上方文章 - -### docker部署使用 -上传探针到服务器 `/docker/skywalking/agent` 目录
-**不要使用网上下载的 请使用框架自带的 内含一些官网没有的插件**
-![输入图片说明](https://foruda.gitee.com/images/1667453098143152651/f1b4f492_1766278.png "屏幕截图") - -在对应服务的`dockerfile`内 打开 `skywalking` 相关参数注释
-![输入图片说明](https://foruda.gitee.com/images/1667452514896786032/f4322fb9_1766278.png "屏幕截图") - -服务编排增加探针路径映射
-![输入图片说明](https://foruda.gitee.com/images/1667453276389844864/7e139aa9_1766278.png "屏幕截图") - - -### 对接日志推送(不推荐 建议使用ELK收集日志) - -框架已经封装好了对应的依赖和配置 在服务内添加如下依赖 - -```xml - - - com.ruoyi - ruoyi-common-skylog - -``` - -在 `logback.xml` 日志配置文件内引入 `skylog` 配置文件 - -![输入图片说明](https://foruda.gitee.com/images/1667452697748002725/a18212cd_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/architecture_diagram.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/architecture_diagram.md deleted file mode 100644 index 05db07a3..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/architecture_diagram.md +++ /dev/null @@ -1,3 +0,0 @@ -# 软件架构图 -- - - -![输入图片说明](https://foruda.gitee.com/images/1722569321458793955/8672b1fc_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/collaboration.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/collaboration.md deleted file mode 100644 index 569aed75..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/collaboration.md +++ /dev/null @@ -1,27 +0,0 @@ -# 多团队开发 -- - - -## 功能介绍 - -> 多人员/团队开发往往会出现 调试程序 被负载均衡到别人那里 自己抓不到请求等问题
-> 正确团队开发模式 `测试机一台` 公共服务都放到测试机上
-> 本地开发人员 需启动 `ruoyi-gateway` 与 其他 调试的业务模块
-> 将所有服务都统一指向同一个 Nacos 服务
-> 前端连接本机 `ruoyi-gateway` 网关调试程序
- -框架提供了 `ruoyi-common-loadbalancer` 多团队 负载均衡模块 可以将网关的请求锁定到与网关相同的IP服务 - -需要在 `ruoyi-gateway` `ruoyi-auth` `ruoyi-modules` 引入 `ruoyi-common-loadbalancer` 模块 - -![输入图片说明](https://foruda.gitee.com/images/1678980590168990366/afa2fdf6_1766278.png "屏幕截图") - -启动前端访问本机 `ruoyi-gateway` 网关在请求转发 和 `dubbo` 进行 RPC 调用时
-会获取与本机IP地址相同的服务优先调用(如未找到 会随机返回) - -# 重点说明 - -请检查本机是否有虚机网卡IP 如有多网卡获取IP地址会不准确 - -可使用如下代码检查本机IP是否正常 -```java -InetAddress.getLocalHost().getHostAddress() -``` \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/doc.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/doc.md deleted file mode 100644 index 422aeb9e..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/doc.md +++ /dev/null @@ -1,88 +0,0 @@ -# 接口文档 -- - - -## 版本 >= `1.2.0` -## 说明 -由于 `springfox` 与 `knife4j` 均停止维护 bug众多
-故从 `1.2.0` 开始 迁移到 `springdoc` 框架
-基于 `javadoc` 无注解零入侵生成规范的 `openapi` 结构体
-由于框架自带文档UI功能单一扩展性差 故移除自带UI 建议使用外置文档工具 - -## 文档工具使用 -由于框架采用 `openapi` 行业规范 故市面上大部分的框架均支持 可自行选择
-例如: `apifox` `apipost` `postman` `torna` `knife4j` 等 根据对应工具的文档接入即可 - -## Swagger升级SpringDoc指南 - -常见功能如下 其他功能自行挖掘
-**注意: `javadoc` 只能替换基础功能 特殊功能还需要使用注解实现** - -| swagger | springdoc | javadoc | -|----------------------------------|---------------------------------|--------------------| -| @Api(name = "xxx") | @Tag(name = "xxx") | java类注释第一行 | -| @Api(description= "xxx") | @Tag(description= "xxx") | java类注释 | -| @ApiOperation | @Operation | java方法注释 | -| @ApiIgnore | @Hidden | 无 | -| @ApiParam | @Parameter | java方法@param参数注释 | -| @ApiImplicitParam | @Parameter | java方法@param参数注释 | -| @ApiImplicitParams | @Parameters | 多个@param参数注释 | -| @ApiModel | @Schema | java实体类注释 | -| @ApiModelProperty | @Schema | java属性注释 | -| @ApiModelProperty(hidden = true) | @Schema(accessMode = READ_ONLY) | 无 | -| @ApiResponse | @ApiResponse | java方法@return返回值注释 | - -# 建议使用 `Apifox`(常见问题有其他对接方式) - -官网连接: [https://www.apifox.cn/](https://www.apifox.cn/)
-视频教程: [springdoc与apifox配合使用](https://www.bilibili.com/video/BV1mr4y1j75M?p=8&vd_source=8f52c77be3233dbdd1c5e332d4d45bfb) - -![输入图片说明](https://foruda.gitee.com/images/1678976476639902970/f1617b40_1766278.png "屏幕截图") - -支持 文档编写 接口调试 Mock 接口压测 自动化测试 等一系列功能 - -### 接入框架 - -> 1.下载或使用web在线版 创建一个自己的项目
- -![输入图片说明](https://foruda.gitee.com/images/1678976502850663851/7bbd8728_1766278.png "屏幕截图") - -> 2.进入项目 选择项目设置 找到自动同步
- -![输入图片说明](https://foruda.gitee.com/images/1678976508918240326/6a4a61a8_1766278.png "屏幕截图") - -> 3.根据项目内所有文档组完成所有数据源创建(拉取后端`openapi`结构体)
-数据源URL格式 `http://网关ip:端口/服务路径/v3/api-docs`
-项目内所需:
-`http://localhost:8080/demo/v3/api-docs` 演示服务
-`http://localhost:8080/auth/v3/api-docs` 认证服务
-`http://localhost:8080/resource/v3/api-docs` 资源服务
-`http://localhost:8080/system/v3/api-docs` 系统服务
-`http://localhost:8080/code/v3/api-docs` 代码生成服务
- -![输入图片说明](https://foruda.gitee.com/images/1678980352012289965/24e0e4da_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1678980368645148754/62308680_1766278.png "屏幕截图") - -> 4.选择 接口管理 项目概览 点击立即导入 并等待导入完成
-后续会根据策略每3个小时自动导入一次
-每次重新进入apifox也会自动同步一次
-后端有改动也可以手动点击导入
- -![输入图片说明](https://foruda.gitee.com/images/1678980393851604773/a0c657d3_1766278.png "屏幕截图") - -> 5.(注意版本号)设置鉴权 选择接口管理 项目概览 找到Auth 按照如下配置
- -**版本号: >= 2.X** - -![输入图片说明](https://foruda.gitee.com/images/1690966897370710566/6a688aea_1766278.png "屏幕截图") - -**版本号: 1.X** - -![输入图片说明](https://foruda.gitee.com/images/1678980398409729963/db4502a0_1766278.png "屏幕截图") - -> key对应项目配置 默认为 `Authorization`
- -![输入图片说明](https://foruda.gitee.com/images/1678976544342001474/c2ff85d3_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1678976549237304743/bcdfadda_1766278.png "屏幕截图") - - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/i18n.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/i18n.md deleted file mode 100644 index 304d3e04..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/i18n.md +++ /dev/null @@ -1,31 +0,0 @@ -# 国际化方案 -- - - -* 前端国际化参考 [ruoyi前端国际化文档](http://doc.ruoyi.vip/ruoyi-vue/document/htsc.html#前端国际化流程)
-* 参考 `demo` 模块 `TestI18nController` 国际化演示案例 - 在 `Header` 请求头 增加上下文语言参数 `content-language` 参数需与国际化配置文件后缀对应 - 如 `zh_CN` `en_US` 等
- -![输入图片说明](https://foruda.gitee.com/images/1678976722892396585/60917594_1766278.png "屏幕截图") - -## 获取 `code` 对应国际化内容 - -![输入图片说明](https://foruda.gitee.com/images/1678976728533100954/0ab8e36a_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678976733019209506/a16574d6_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678976738409745057/a073b425_1766278.png "屏幕截图") - -## 使用 `Validator` 框架校验 `controller` 参数返回国际化 - -`controller` 校验接口参数 需要在类增加 `@Validated` 注解
-![输入图片说明](https://foruda.gitee.com/images/1678976741834729507/6c19b9cc_1766278.png "屏幕截图")
-参数对应校验注解 使用 `{code}` 形式标注使用国际化处理
-![输入图片说明](https://foruda.gitee.com/images/1678976746093285542/ad0989db_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678976750822808564/56bd60d7_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678976754755107198/b89bf173_1766278.png "屏幕截图") - -## 使用 `Validator` 框架校验 `Bean` 返回国际化 - -`Bean` 校验需要在接口校验 `Bean` 参数使用 `@Validated` 注解
-![输入图片说明](https://foruda.gitee.com/images/1678976761015767874/729da3bc_1766278.png "屏幕截图")
-`Bean` 内属性校验注解 使用 `{code}` 形式标注使用国际化处理
-![输入图片说明](https://foruda.gitee.com/images/1678976765122587920/0b1027af_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678976769965314387/0c416ede_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/inner_authentication.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/inner_authentication.md deleted file mode 100644 index c90d2c61..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/inner_authentication.md +++ /dev/null @@ -1,19 +0,0 @@ -# 内网鉴权 -- - - -## 功能介绍 - -此功能用于防止外部请求访问内部服务应用
-在请求经过 `gateway网关` 会生成一个 `id-token` 携带到后续服务进行校验
-若未经过 `gateway网关` 调用内网服务 会出现 `id-token无效` 异常
-有效防止非法请求直接访问内网服务
- -## 开启/关闭内网鉴权 - -更改 `application-common.yml` 配置文件的 `sa-token.check-id-token` 配置即可 - -![输入图片说明](https://foruda.gitee.com/images/1678980608778275681/9a2c1054_1766278.png "屏幕截图") - -## 放行内网鉴权 -进入 `ruoyi-common-security` 模块找到 `SecurityConfiguration` 类 增加排除路径即可 - -![输入图片说明](https://foruda.gitee.com/images/1678980612657326393/cea32a8c_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/new_module.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/new_module.md deleted file mode 100644 index 0d75525b..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/new_module.md +++ /dev/null @@ -1,39 +0,0 @@ -# 创建新服务 -- - - -### 最简单的方式 -> 找个配置好的 例如 `ruoyi-system` 直接copy一份 - -> 将 `pom` 名称改掉
- -![输入图片说明](https://foruda.gitee.com/images/1678980168782983123/c717e9ba_1766278.png "屏幕截图") - -> 服务启动类 名称改掉
- -![输入图片说明](https://foruda.gitee.com/images/1678980179829877203/f89d5c18_1766278.png "屏幕截图") - -> `application.yml` 配置服务应用名 改掉
- -![输入图片说明](https://foruda.gitee.com/images/1678980184047648028/e4c6c6cc_1766278.png "屏幕截图") - -> `nacos` 新建一份新的 对应新模块名称的 配置文件
-![输入图片说明](https://foruda.gitee.com/images/1678980188806372269/cfd9731a_1766278.png "屏幕截图") - -更改 `nacos` 上的 `ruoyi-gateway.yml` 增加新服务路由
-新服务访问路径 `网关ip:端口/服务路径/controller路径/接口路径`
-例子: `http://localhost:8080/system/user/list`
- -![输入图片说明](https://foruda.gitee.com/images/1666861595048863422/9e9755b3_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1666861629037264535/bdfd5484_1766278.png "屏幕截图") - -### 注意事项 -如果是两个不同包名的模块 需要修改如下配置 - -![输入图片说明](https://foruda.gitee.com/images/1719813861680271619/82435586_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1692006501957936219/059f8526_1766278.png "屏幕截图") - -如果新服务需要使用 `seata` 分布式事务
-需要在 `nacos` 上的 `seata-server.properties` 文件内增加服务组 - -![输入图片说明](https://foruda.gitee.com/images/1692006825427360840/5b9e410c_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/update_package_name.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/update_package_name.md deleted file mode 100644 index 2dcab848..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/update_package_name.md +++ /dev/null @@ -1,33 +0,0 @@ -# 关于修改包名 -- - - - -**注意: 老包名为 com.ruoyi** - -## 1.随便找个地方新建 org.dromara 包 -![输入图片说明](https://foruda.gitee.com/images/1708491220807198688/b95c0c34_1766278.png "屏幕截图") - -## 2.在包上右键选择 refactor -> rename 选择 All Directories -![输入图片说明](https://foruda.gitee.com/images/1683276891079076405/79808b22_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1708491697128844860/1e87ad39_1766278.png "屏幕截图") - -**因为dromara组织下有很多依赖导致idea无法识别完整包名** -
-![输入图片说明](https://foruda.gitee.com/images/1708490576909691001/692e5b37_1766278.png "屏幕截图") - -**需要先将dromara修改为 例如: ruoyi 然后重复上述步骤 这样就可以整包修改了** -
-![输入图片说明](https://foruda.gitee.com/images/1708490906933084793/ff104cd7_1766278.png "屏幕截图") - -## 3.使用IDEA全局替换 org.dromara 替换为 com.xxx - -![输入图片说明](https://foruda.gitee.com/images/1708491055347995519/dedda0d1_1766278.png "屏幕截图") - -**注意: 由于dromara组织下项目很多 非本框架的依赖模块 请勿修改 例如上图中的 org.dromara.sms4j** - -## 4.如有需要 将所有模块名逐一修改即可 - -## 5.修改完成后需查看所有common包下模块spi文件是否修改正确 - -**老版本idea或者未按照教程修改包名可能导致文件丢包问题** - -![输入图片说明](https://foruda.gitee.com/images/1708491365841192006/8bc337c2_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/update_url.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/update_url.md deleted file mode 100644 index d36012f5..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/update_url.md +++ /dev/null @@ -1,25 +0,0 @@ -# 修改应用路径 -- - - -# 修改访问后端接口路径 - -更改 前端环境配置文件 `VITE_APP_BASE_API` 代理路径 - -![输入图片说明](https://foruda.gitee.com/images/1661824572484410642/14265f05_1766278.png "屏幕截图")
- -![输入图片说明](https://foruda.gitee.com/images/1724317552931269967/f7515655_1766278.png "屏幕截图") - -`prod` 生产环境需修改 `nginx.conf` 后端代理路径(上述配置文件也要改) - -![输入图片说明](https://foruda.gitee.com/images/1678980501204821424/d3340308_1766278.png "屏幕截图") - -# 修改前端页面访问路径 -修改对应环境的 `.env.环境` 文件内的 `VITE_APP_CONTEXT_PATH` 应用访问路径即可 - -![输入图片说明](https://foruda.gitee.com/images/1661824572484410642/14265f05_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1724317049535973756/0a2cc43b_1766278.png "屏幕截图") - -生产环境 `nginx.conf` 与之对应修改即可
-**注意: 文件真实目录为 `/usr/share/nginx/html/admin/index.html` 此功能一般为多项目部署需要 故会增加一层目录 如不需要可以自行修改**
- -![输入图片说明](https://foruda.gitee.com/images/1678976662194341301/2720b7e9_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/client.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/client.md deleted file mode 100644 index 66ae32a9..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/client.md +++ /dev/null @@ -1,85 +0,0 @@ -# 客户端管理功能 -- - - -## 版本 >= 2.X - -## 客户端管理页面 - -![输入图片说明](https://foruda.gitee.com/images/1690961819029076660/c44374ac_4959041.png "屏幕截图") - -### 客户端管理字段说明 -| 字段名称 | 取值说明 | 注意事项 | -|----------------|----------------------------|--------------------------------| -| 客户端id | 由后端生成,用于前端登录校验以及接口数据加密 | 无法修改,不要删除默认数据,否则会报错 | -| 客户端key | 前端自定义 | 无法修改,不要删除默认数据,否则会报错 | -| 客户端秘钥 | 前端自定义 | 无法修改,不要删除默认数据,否则会报错 | -| 授权类型 | 密码认证、短信认证、邮件认证、小程序认证、第三方认证 | 根据授权类型判断当前客户端是否支持该登录方式 | -| 设备类型 | PC端、APP端 | | -| Token活跃超时时间 | 自定义 | 指定时间无操作则过期(单位:秒),默认30分钟(1800秒) | -| Token固定超时时间 | 自定义 | 指定时间必定过期(单位:秒),默认七天(604800秒) | - -### 前后端使用新的客户端id - -步骤如下: -1. 前端管理页面生成新的客户端id。 -2. 将新的客户端id复制到前端配置文件。 - -![输入图片说明](https://foruda.gitee.com/images/1690962894318847386/133d2f90_4959041.png "屏幕截图") - -## 新增自定义客户端 - -### 步骤一:新增客户端数据(例如增加小程序端) - -![输入图片说明](https://foruda.gitee.com/images/1690965463070099188/baeb4441_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1690965508836621042/df06248f_4959041.png "屏幕截图") - -### 步骤二:配置前端请求头信息 - -需要在全局请求头 header 中增加 cientid
-确保客户端所有请求都携带此id 可参考项目 `request.ts` - -![输入图片说明](https://foruda.gitee.com/images/1690965768235114596/980b88d2_4959041.png "屏幕截图") - -`VITE_APP_CLIENT_ID` 即配置文件中的客户端id。 - -**重点:不同客户端登录获取到的token不同与其他端不互通(例如: app登录获取到的token无法用于pc端接口查询)** - -## 新增自定义登录方式授权类型 - -**重点说明: 不要单独增加登录接口 系统全局统一只有一个登录接口 只需增加不同的鉴权方式即可** - -如何调试使用登录看这里 -> [关于登录调试步骤](/questions/login_step.md) - -### 步骤一:新增字典数据 - -![输入图片说明](https://foruda.gitee.com/images/1690968849418013624/3b28417e_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1690968865819397010/64529fad_4959041.png "屏幕截图") - -### 步骤二:新增/修改客户端数据 - -### 步骤三:后端新增认证策略 - -新增策略实现类实现 `IAuthStrategy` 接口。
- -![输入图片说明](https://foruda.gitee.com/images/1690972828588111954/7614a4c5_4959041.png "屏幕截图") - -参照已有策略实现类实现自定义参数校验登录方法逻辑。
- -![输入图片说明](https://foruda.gitee.com/images/1718951146945578143/789c80e4_1766278.png "屏幕截图") - -**注意修改 `@Service` 名称保证规范性** - -![输入图片说明](https://foruda.gitee.com/images/1718951179571300385/8db730b9_1766278.png "屏幕截图") - -`LoginBody` 校验参数(可自定义)
- -![输入图片说明](https://foruda.gitee.com/images/1718951237123374392/f7840db2_1766278.png "屏幕截图") - -例如 扩展小程序登录参数 只需要继承 `LoginBody
- -![输入图片说明](https://foruda.gitee.com/images/1718951283931895761/e6348be5_1766278.png "屏幕截图")` - -校验分组(可自定义)
- -![输入图片说明](https://foruda.gitee.com/images/1718951343601334215/8ef404b4_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/code_generate.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/code_generate.md deleted file mode 100644 index 742ef939..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/code_generate.md +++ /dev/null @@ -1,86 +0,0 @@ -# 代码生成 -- - - -## 功能介绍 - -### 数据源配置 - -![输入图片说明](https://foruda.gitee.com/images/1678976867341325193/a2be0608_1766278.png "屏幕截图") - -**项目适配多种类型数据库 可以在代码生成页面切换**
- -> 填写对应的数据源名称 点击搜索按钮 即可切换到对应的数据源
- -![输入图片说明](https://foruda.gitee.com/images/1678976876081856486/4ef4841c_1766278.png "屏幕截图") - -**>= 2.2.1版本 项目支持100+种数据库适配 在代码生成模块增加对应的数据库依赖即可**
- -![输入图片说明](https://foruda.gitee.com/images/1722396530340741054/3914eb72_1766278.png "屏幕截图") - - -### 导入数据表 - -> 点击导入按钮 会加载系统数据库所有的表
- -![输入图片说明](https://foruda.gitee.com/images/1678976880393939803/3ecf1dcc_1766278.png "屏幕截图") - -> 选择需要的表 点击确定即可
- -![输入图片说明](https://foruda.gitee.com/images/1678976885370716109/4834faa5_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678976891856866728/853420d9_1766278.png "屏幕截图") - -### 编辑表生成结构 - -> 点击表对应的编辑按钮
- -![输入图片说明](https://foruda.gitee.com/images/1678976899111822310/aeaa33f9_1766278.png "屏幕截图") - -> 更改要生成表的数据
- -![输入图片说明](https://foruda.gitee.com/images/1678976903345795925/4326f6ee_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678976908897387614/4cdf939b_1766278.png "屏幕截图") - -### 生成条件影响 - -![输入图片说明](https://foruda.gitee.com/images/1678976913809284051/24da09b0_1766278.png "屏幕截图") - - -* `插入` `编辑` 影响生成 BO 类 与 前端添加编辑页面 是否有该字段 -* `列表` 影响生成 VO 类 与 前端列表页面展示 是否有该字段 -* `查询` 影响 前端页面是否有该字段的搜索框 与 后端代码是否生成对应的查询条件 -* `查询方式` 影响生成查询条件的类型 -* `必填` 影响 BO 类 与 页面是否强制校验 -* `显示类型` 影响生成页面使用何种展示组件 -* `字典类型` 影响页面是否生成与字典的关联 - -### 树表配置 - -> 编辑表生成信息 生成模板为 `树表` 填写对应数据即可
- -![输入图片说明](https://foruda.gitee.com/images/1678976917918548901/f5886c5c_1766278.png "屏幕截图") - -### 主子表说明 - -框架不支持也不推荐使用主子表
-原因一般业务场景 基本都是一对N表 多表关联场景
-还有一些 主 => 子 <= 主 场景 需求很复杂 很少有单纯主子表场景出现
-另外主子表关联 很容易出现 笛卡尔积 或者数据错乱等问题 需要自行sql调优场景
-所以建议大家都按照 单表生成 自行编写业务逻辑 - -### 预览功能 - -> 配置好生成信息后 可以点击预览按钮
- -![输入图片说明](https://foruda.gitee.com/images/1678976924411765532/2e9747df_1766278.png "屏幕截图") - -> 系统会根据已经配置好的数据 生成对应的代码预览
-> 可以再此处观察代码的生成结构和数据是否正确等
- -![输入图片说明](https://foruda.gitee.com/images/1678976945982406065/ca7383bb_1766278.png "屏幕截图") - - -### 代码结构同步 - -> 实际开发中 难免会有表结构更改的需求
-> 这时可以使用 同步功能 点击同步按钮 即可与实时数据库表进行字段同步
- -![输入图片说明](https://foruda.gitee.com/images/1678976952919156537/3c47c078_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/export.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/export.md deleted file mode 100644 index fa901792..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/export.md +++ /dev/null @@ -1,250 +0,0 @@ -# 导出功能 - -- - - - -在本框架中引入了 `Easy Excel` 依赖(对 `Apache POI`进行了封装以及扩展),可以对数据进行导出操作(即写 Excel)。 - -[EasyExcel 文档地址](https://easyexcel.opensource.alibaba.com/) - -## 导出功能使用流程说明 - -### 步骤一:定义导出实体对象 - -以框架中 `SysUserExportVo` 为例: - -```Java - /** - * 用户ID - */ - @ExcelProperty(value = "用户序号") - private Long userId; - - // ....................... - - /** - * 用户性别 - */ - @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "sys_user_sex") - private String sex; - - /** - * 帐号状态(0正常 1停用) - */ - @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "sys_normal_disable") - private String status; -``` - -> 说明:
-> 1. 使用 `@ExcelProperty` 注解标注需要导出的属性。 -> 2. 注解 `@ExcelProperty` 中 `value` 属性代表表格头部标题字段,`converter` 代表使用的转换器,后面会详细说明。 -> 3. 注解 `@ExcelDictFormat` 为自定义注解,与自定义转换器结合使用,同样在后面进行详细说明。 - -### 步骤二:使用导出方法 - -以框架中 `SysUserController#export` 方法为例: - -```Java - /** - * 导出用户列表 - */ - @PostMapping("/export") - public void export(SysUserBo user, HttpServletResponse response) { - // 根据参数查询导出的用户列表数据 - List list = userService.selectUserList(user); - // 将列表转换为导出对象列表 - List listVo = MapstructUtils.convert(list, SysUserExportVo.class); - // 导出方法 - ExcelUtil.exportExcel(listVo, "用户数据", SysUserExportVo.class, response); - } -``` - -> 说明:
-> 使用 `ExcelUtil.exportExcel` 方法完成导出功能,上述 Demo 传入参数分别是:导出对象集合,Excel sheet 表名称,导出对象类型,response。 - -## 框架工具使用说明 - -### 1:字典转换器 - -字典转换器 `ExcelDictConvert` 与自定义注解 `@ExcelDictFormat` 结合使用,标注在需要转换的属性上。 - -使用方式一: - -```Java - /** - * 用户性别 - */ - @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "sys_user_sex") - private String sex; -``` - -使用方式二: - -```Java - /** - * 用户性别 - */ - @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) - @ExcelDictFormat(readConverterExp="0=男,1=女,2=未知", separator=",") - private String sex; -``` - -`@ExcelDictFormat` 注解属性说明: - -| 属性名称 | 属性类型 | 默认值 | 说明 | -|------------------|--------|-----|-----------------------------------| -| dictType | String | "" | 字典的type值 (如: sys_user_sex) | -| readConverterExp | String | "" | 读取内容转表达式 (如: 0=男,1=女,2=未知) | -| separator | String | "," | 与 readConverterExp 属性结合使用,表达式的分隔符 | - -### 2:枚举转换器 - -字典转换器 `ExcelEnumConvert` 与自定义注解 `@ExcelEnumFormat` 结合使用,标注在需要转换的属性上。 - -使用方式: - -```Java - /** - * 用户类型 - *

- * 使用ExcelEnumFormat注解需要进行下拉选的部分 - */ - @ExcelProperty(value = "用户类型", index = 1, converter = ExcelEnumConvert.class) - @ExcelEnumFormat(enumClass = UserStatus.class, textField = "info") - private String userStatus; -``` - -`@ExcelEnumFormat` 注解属性说明: - -| 属性名称 | 属性类型 | 默认值 | 说明 | -|-----------|------------|------|------------------------------| -| enumClass | Enum Class | - | 字典枚举类型 | -| codeField | String | code | 字典枚举类中对应的 code 属性名称,默认为 code | -| textField | String | text | 字典枚举类中对应的 text 属性名称,默认为 text | - -### 3:合并单元格 - -`@CellMerge` 注解用于合并相同的列数据,需要结合 `CellMergeStrategy` 策略使用,标注在需要转换的属性上。 - -使用方式: - -步骤一:在属性标注 `@CellMerge` 注解: -```Java - /** - * 部门id - */ - @CellMerge - @ExcelProperty(value = "部门id") - private Long deptId; -``` - -`@CellMerge` 注解属性说明: - -| 属性名称 | 属性类型 | 默认值 | 说明 | -|---------|----------|-----|------------------------------| -| index | int | -1 | 合并列的下标,建议使用默认值 | -| mergeBy | String[] | {} | 合并需要依赖的其他字段名称(基于这个字段内容做合并条件) | - - -步骤二:导出方法开启合并: -```Java - /** - * 导出测试单表列表 - */ - @PostMapping("/export") - public void export(@Validated TestDemoBo bo, HttpServletResponse response) { - List list = testDemoService.queryList(bo); - // 参数 true 表示开启合并单元格策略 - ExcelUtil.exportExcel(list, "测试单表", TestDemoVo.class, true, response); - } -``` -![输入图片说明](https://foruda.gitee.com/images/1700128921644543994/e8d4704f_1766278.png "屏幕截图") - -### 4:复杂 Excel 导出示例 -`TestExcelController` 提供了几种导出示例,如果需要可以参照相应方法进行导出。 - -#### 4.1:单列表多数据导出(模板导出) - -模板内容: - -![输入图片说明](https://foruda.gitee.com/images/1700124852002972562/d9f57a8c_4959041.png "屏幕截图") - -模板位置:`ruoyi-example/ruoyi-demo/src/main/resources/excel/` - -导出示例代码:参考 demo 模块 `TestExcelController` 模板写法请查看 `EasyExcel` 文档 - -导出结果: - -![输入图片说明](https://foruda.gitee.com/images/1700124885532359879/0d011d05_4959041.png "屏幕截图") - -#### 4.2:多列表多数据导出(模板导出) - -模板内容: - -![输入图片说明](https://foruda.gitee.com/images/1700125025931981176/105dbaaa_4959041.png "屏幕截图") - -模板位置:`ruoyi-example/ruoyi-demo/src/main/resources/excel/` - -导出示例代码:参考 demo 模块 `TestExcelController` 模板写法请查看 `EasyExcel` 文档 - -导出结果: - -![输入图片说明](https://foruda.gitee.com/images/1700125054011300002/71869c1d_4959041.png "屏幕截图") - -#### 4.3:导出下拉框 - -`ExcelDictFormat` 注解指定的字典项默认都会转换成下拉框 - -自定义导出省市区下拉框示例代码:参考 demo 模块 `TestExcelController` - -导出结果: - -![输入图片说明](https://foruda.gitee.com/images/1700125265411678973/7f767719_4959041.png "屏幕截图") - -## Easy Excel 常用注解 - -`Easy Excel` 提供了丰富的注解可以对导出对象进行定制化操作,这里的注解说明针对的是原生注解,自定义注解会结合转换器一起进行说明。 - -| 类型 | 注解名称 | 使用举例 | 说明 | -|-------|-------------------------|------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------| -| 格式化注解 | @DateTimeFormat | @DateTimeFormat(value=格式化值) | 对字符串进行日期格式化 (参照 `java.text.SimpleDateFormat` 书写即可) | -| 格式化注解 | @NumberFormat | @NumberFormat(value=格式化值, roundingMode=舍入模式) | 对字符串进行数值格式化 (参照 `java.text.DecimalFormat` 书写即可, `roundingMode` 默认 `RoundingMode.HALF_UP`) | -| 样式注解 | @ColumnWidth | @ColumnWidth(value=值) | 设置列宽 | -| 样式注解 | @ContentFontStyle | @ContentFontStyle(color=颜色) | 可以设置字体类型,颜色,粗细,是否斜体,下划线等,具体可查看注解 `@ContentFontStyle` | -| 样式注解 | @ContentLoopMerge | @ContentLoopMerge(eachRow=行值, columnExtend=列值) | 设置循环合并的区域 | -| 样式注解 | @ContentRowHeight | @ContentRowHeight(value=值) | 设置内容行高 | -| 样式注解 | @ContentStyle | - | 设置单元格样式,具体可查看注解 `@ContentStyle` | -| 样式注解 | @HeadFontStyle | @HeadFontStyle(color=颜色) | 设置表头字体格式,类似 `@ContentFontStyle`,具体可查看注解 `@HeadFontStyle` | -| 样式注解 | @HeadRowHeight | @HeadRowHeight(value=值) | 设置表头行高 | -| 样式注解 | @HeadStyle | - | 设置表头样式,具体可查看注解 `@HeadStyle` | -| 样式注解 | @OnceAbsoluteMerge | @OnceAbsoluteMerge(firstRowIndex=开始行下标, lastRowIndex=结束行下标, firstColumnIndex=开始列下标, lastColumnIndex=结束列下标) | 根据设置值合并单元格 | -| 属性注解 | @ExcelIgnore | @ExcelIgnore | 导出忽略该字段 | -| 属性注解 | @ExcelIgnoreUnannotated | @ExcelIgnoreUnannotated | 默认不管加不加 `@ExcelProperty` 的注解的所有字段都会参与读写,加了 `@ExcelIgnoreUnannotated` 注解以后,不加 `@ExcelProperty` 注解的字段就不会参与 | -| 属性注解 | @ExcelProperty | @ExcelProperty(value=值, order=排序值, index=下标, converter=转换器) | 默认按照对象属性顺序导出,如果设置了 `order` 以及 `index`,优先级 `index` > `order` > 默认;converter 可以自定义 | - -## 扩展说明 - -### 自定义转换器实现 - -由于业务需要,原生注解不一定能够符合需要,因而衍生出了自定义转换器。能够实现定制化的内容转换需要。 -以下以框架中的字典转换器 `ExcelDictConvert` 为例进行说明。 - -字典转换器 `ExcelDictConvert`,字典转换器使用了自定义注解 `@ExcelDictFormat` 配合使用。 - -_**注:自定义转换器并非一定需要自定义注解,也可以针对已有的注解进行自定义转换实现。**_ - -#### 实现方式 - -自定义转换器需要实现 `com.alibaba.excel.converters.Converter` 接口,实现接口中的方法。 - -![输入图片说明](https://foruda.gitee.com/images/1700104014304819918/33eb0c42_4959041.png "屏幕截图") - -转换方法 `ExcelDictConvert#convertToExcelData` : - -![输入图片说明](https://foruda.gitee.com/images/1700104426131801297/72931ef0_4959041.png "屏幕截图") - -## 更多功能 - -更多导出功能使用可以参照 `Easy Excel` [官方文档](https://easyexcel.opensource.alibaba.com/docs/current/api/write)。 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/import.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/import.md deleted file mode 100644 index f1bbca7d..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/import.md +++ /dev/null @@ -1,202 +0,0 @@ -# 导入功能 -- - - - -在本框架中引入了 `Easy Excel` 依赖(对 `Apache POI`进行了封装以及扩展),可以对数据进行导入操作(即读 Excel)。 - -## 导入功能使用流程说明 - -### 步骤一:定义导入实体对象 - -以框架中 `SysUserImportVo` 为例: - -```java - /** - * 用户ID - */ - @ExcelProperty(value = "用户序号") - private Long userId; - - // ....................... - - /** - * 用户性别 - */ - @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "sys_user_sex") - private String sex; - - /** - * 帐号状态(0正常 1停用) - */ - @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "sys_normal_disable") - private String status; -``` - -> 说明:
-> 1. 使用 `@ExcelProperty` 注解标注需要导入的属性。 -> 2. 注解 `@ExcelProperty` 中 `value` 属性代表表格头部标题字段,`converter` 代表使用的转换器,后面会详细说明。 -> 3. 注解 `@ExcelDictFormat` 为自定义注解,与自定义转换器结合使用,同样在后面进行详细说明。 -> 4. 对象禁止使用链式注解 `@Accessors(chain = true)`,会找不到set方法。 - -### 步骤二:使用导入方法 - -以框架中 `SysUserController#importData` 方法为例: - -```Java - /** - * 导入数据 - * - * @param file 导入文件 - * @param updateSupport 是否更新已存在数据 - */ - @Log(title = "用户管理", businessType = BusinessType.IMPORT) - @SaCheckPermission("system:user:import") - @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public R importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception { - // 导入方法 - ExcelResult result = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class, new SysUserImportListener(updateSupport)); - return R.ok(result.getAnalysis()); - } -``` -> 说明:
-> 使用 `ExcelUtil.importExcel` 方法完成导出功能,上述 Demo 传入参数分别是:导入文件流,导入对象类型,导入监听器 `SysUserImportListener`。 - -## 框架工具使用说明 - -### 1:字典转换器 - -字典转换器 `ExcelDictConvert` 与自定义注解 `@ExcelDictFormat` 结合使用,标注在需要转换的属性上。 - -使用方式一: - -```Java - /** - * 用户性别 - */ - @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "sys_user_sex") - private String sex; -``` - -使用方式二: - -```Java - /** - * 用户性别 - */ - @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) - @ExcelDictFormat(readConverterExp="0=男,1=女,2=未知", separator=",") - private String sex; -``` - -`@ExcelDictFormat` 注解属性说明: - -| 属性名称 | 属性类型 | 默认值 | 说明 | -|------------------|--------|-----|-----------------------------------| -| dictType | String | "" | 字典的type值 (如: sys_user_sex) | -| readConverterExp | String | "" | 读取内容转表达式 (如: 0=男,1=女,2=未知) | -| separator | String | "," | 与 readConverterExp 属性结合使用,表达式的分隔符 | - -### 2:枚举转换器 - -字典转换器 `ExcelEnumConvert` 与自定义注解 `@ExcelEnumFormat` 结合使用,标注在需要转换的属性上。 - -使用方式: - -```Java - /** - * 用户类型 - *

- * 使用ExcelEnumFormat注解需要进行下拉选的部分 - */ - @ExcelProperty(value = "用户类型", index = 1, converter = ExcelEnumConvert.class) - @ExcelEnumFormat(enumClass = UserStatus.class, textField = "info") - private String userStatus; -``` - -`@ExcelEnumFormat` 注解属性说明: - -| 属性名称 | 属性类型 | 默认值 | 说明 | -|-----------|------------|------|------------------------------| -| enumClass | Enum Class | - | 字典枚举类型 | -| codeField | String | code | 字典枚举类中对应的 code 属性名称,默认为 code | -| textField | String | text | 字典枚举类中对应的 text 属性名称,默认为 text | - - -### 3:导入监听器 - -#### 3.1:ExcelListener 监听器接口 - -`ExcelListener` 扩展了 `ReadListener` 接口,增加了获取结果方法。 - -![输入图片说明](https://foruda.gitee.com/images/1700181723794469524/99bf83c9_4959041.png "屏幕截图") - -#### 3.2:DefaultExcelListener 默认监听器 - -`DefaultExcelListener` 默认监听器在读 Excel 时调用,主要对数据进行校验、解析、异常处理、返回结果等。导入操作时如果没有特别指定则使用该监听器。 - -#### 3.3:SysUserImportListener 用户导入监听器 - -`SysUserImportListener` 用户导入监听器是在用户导入时调用的监听器。 - -该监听器重写了 `invoke` 反射接口,对导入的用户数据进行了校验;重写了 `getExcelResult` 获取结果接口,返回结果数据。 - -#### 3.4:ExportDemoListener 带下拉框的导入监听器 - -`ExportDemoListener` 是对带有下拉框的 Excel 进行处理的导入监听器。 - -## Easy Excel 常用注解 - -`Easy Excel` 提供了丰富的注解可以对导出对象进行定制化操作,这里的注解说明针对的是原生注解。 - -| 类型 | 注解名称 | 使用举例 | 说明 | -|-------|-------------------------|------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------| -| 格式化注解 | @DateTimeFormat | @DateTimeFormat(value=格式化值) | 对字符串进行日期格式化 (参照 `java.text.SimpleDateFormat` 书写即可) | -| 格式化注解 | @NumberFormat | @NumberFormat(value=格式化值, roundingMode=舍入模式) | 对字符串进行数值格式化 (参照 `java.text.DecimalFormat` 书写即可, `roundingMode` 默认 `RoundingMode.HALF_UP`) | -| 属性注解 | @ExcelIgnore | @ExcelIgnore | 导出忽略该字段 | -| 属性注解 | @ExcelIgnoreUnannotated | @ExcelIgnoreUnannotated | 默认不管加不加 `@ExcelProperty` 的注解的所有字段都会参与读写,加了 `@ExcelIgnoreUnannotated` 注解以后,不加 `@ExcelProperty` 注解的字段就不会参与 | -| 属性注解 | @ExcelProperty | @ExcelProperty(value=值, order=排序值, index=下标, converter=转换器) | 默认按照对象属性顺序导出,如果设置了 `order` 以及 `index`,优先级 `index` > `order` > 默认;converter 可以自定义 | - -## 扩展使用 - -### 扩展一:自定义转换器实现 - -由于业务需要,原生注解不一定能够符合需要,因而衍生出了自定义转换器。能够实现定制化的内容转换需要。 -以下以框架中的字典转换器 `ExcelDictConvert` 为例进行说明。 - -字典转换器 `ExcelDictConvert`,字典转换器使用了自定义注解 `@ExcelDictFormat` 配合使用。 - -_**注:自定义转换器并非一定需要自定义注解,也可以针对已有的注解进行自定义转换实现。**_ - -#### 实现方式 - -自定义转换器需要实现 `com.alibaba.excel.converters.Converter` 接口,实现接口中的方法。 - -![输入图片说明](https://foruda.gitee.com/images/1700104014304819918/33eb0c42_4959041.png "屏幕截图") - -转换方法 `ExcelDictConvert#convertToJavaData` : - -![输入图片说明](https://foruda.gitee.com/images/1700182975516396213/d3c020f9_4959041.png "屏幕截图") - -### 扩展二:自定义监听器实现 - -自定义监听器主要用于在读取解析 Excel 数据时进行自定义操作。 -以下以框架中的用户导入监听器 `SysUserImportListener` 为例进行说明。 - -#### 实现方式 -1. 继承分析事件监听器 `AnalysisEventListener` 以及实现 Excel 监听器 `ExcelListener`。 - -![输入图片说明](https://foruda.gitee.com/images/1700184652693497753/09333dac_4959041.png "屏幕截图") - -2. 显示使用构造函数,否则将导致空指针。 - -![输入图片说明](https://foruda.gitee.com/images/1700184759075616584/cf05b0ed_4959041.png "屏幕截图") - -3. 实现 `invoke` 方法,对数据进行解析操作,可以在此方法对数据进行合法性判断。 - -4. 实现 `getExcelResult` 方法,对结果进行操作,例如返回成功、失败的统计数据。 - -## 更多功能 - -更多导入功能使用可以参照 `Easy Excel` [官方文档](https://easyexcel.opensource.alibaba.com/docs/current/quickstart/read)。 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/oss.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/oss.md deleted file mode 100644 index 4cb42769..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/oss.md +++ /dev/null @@ -1,124 +0,0 @@ -# 关于OSS模块使用 -- - - -## 重点注意事项 - -`桶/存储区域` 系统会根据配置自行创建分配权限
-~~如手动配置需要设置 `公有读` 权限 否则文件无法访问~~(`aliyun` 还需开通跨域配置)
-1.4.0 版本支持配置`公有/私有`权限(`aliyun` 还需开通跨域配置)
-访问站点 后严禁携带其他 `url` 例如: `/`, `/ruoyi` 等
-**阿里云与腾讯云SDK访问站点中不能包含桶名 系统会自动处理**
-**minio 站点不允许使用 localhost 请使用 127.0.0.1**
-**访问站点与自定义域名 都不要包含 `http` `https` 前缀 设置`https`请使用选项处理** - -## 代码使用 - -> 参考 `SysOssService.upload` 用法
-> 使用 `OssFactory.instance()` 获取当前启用的 `OssClient` 实例
-> 进行功能调用 获取返回值后 存储到对应的业务表 - -![输入图片说明](https://foruda.gitee.com/images/1678978345529639839/d350ec0b_1766278.png "屏幕截图") - - -## 功能配置 - -### 配置OSS - -> 进入 `系统管理 -> 文件管理 -> 配置管理` 填写对应的OSS服务相关配置
- -![输入图片说明](https://foruda.gitee.com/images/1678978349820700551/1f91a237_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678978354387669856/3a91a3a9_1766278.png "屏幕截图")
**重点说明** - -> 云厂商只需修改 `访问站点`对应的域 切勿乱改(云厂商强烈建议绑定自定义域名使用 七牛云必须绑定[官方规定])
- -![输入图片说明](https://foruda.gitee.com/images/1678978362358100362/5c2c4d20_1766278.png "屏幕截图") - -> 七牛云 访问站点
- - -![输入图片说明](https://foruda.gitee.com/images/1678978366254745764/e93a65ff_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678978369853348732/79e8950e_1766278.png "屏幕截图") - -> 阿里云 访问站点 - -![输入图片说明](https://foruda.gitee.com/images/1678978373981462025/56a70398_1766278.png "屏幕截图") - -> 腾讯云 访问站点 - -![输入图片说明](https://foruda.gitee.com/images/1678978378697093134/785517f3_1766278.png "屏幕截图") - -### MinIO 使用 https访问站点 - -**注意:S3 API 签名计算算法不支持托管 MinIO Server API 的代理方案** - -[ minio https 配置方式](https://blog.csdn.net/Michelle_Zhong/article/details/126484358) - -### 切换OSS - -> 再配置列表点击 `状态` 按钮开启即可(注意: 只能开启一个OSS默认配置)
-> 手动使用 `OssFactory.instance("configKey")`
- -![输入图片说明](https://foruda.gitee.com/images/1678978383700118702/7f3fa0c5_1766278.png "屏幕截图") - -### 扩展分类 - -> 如有文件分类 建议创建多个 oss配置 进行切换存储
- -例如: 创建一个 图片存储的 oss配置
-指定唯一的 `configKey` 与 `前缀目录` 或 直接使用独立的`桶`
-独立桶的特点 可以自定义访问权限
-例如: 创建一个私有文件存储桶 不对外开放
- -![输入图片说明](https://foruda.gitee.com/images/1678978389139754119/140be1df_1766278.png "屏幕截图") - -> 指定需要使用的配置
-> 使用 `OssFactory.instance("image")` 获取的 `OssClient` 会加载上图的配置 从而达到上传不同的目录或桶 - - -![输入图片说明](https://foruda.gitee.com/images/1678978397550123641/1b536881_1766278.png "屏幕截图") - - -### 上传图片或文件 - -> 进入 `系统管理 -> 文件管理` 点击 `上传文件` 或 `上传图片` 根据选项选择即可 会对应上传到配置开启的OSS内
- -![输入图片说明](https://foruda.gitee.com/images/1678978401028132972/445d058e_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678978404388284503/5459da29_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678978408761764835/c81651fc_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678978412748494539/7bae621f_1766278.png "屏幕截图") - -### 列表展示 - -> 默认展示图片(可预览) 文件会展示路径
- -![输入图片说明](https://foruda.gitee.com/images/1678978416327601385/af1ecb3b_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678978422249633007/19d68eaa_1766278.png "屏幕截图") - -> 可以点击 `预览禁用启用` 按钮对是否展示进行更改 - -![输入图片说明](https://foruda.gitee.com/images/1678978426017014926/4f7fa3f3_1766278.png "屏幕截图") - -> 点击禁用后 图片会变成路径展示 - -![输入图片说明](https://foruda.gitee.com/images/1678978429692592556/0231d778_1766278.png "屏幕截图") - -> 也可再 `参数设置` 更改预览状态 将 `OSS预览列表资源` 改为 `false` 即可关闭预览 - -![输入图片说明](https://foruda.gitee.com/images/1678978433769403801/7d480e76_1766278.png "屏幕截图") - -### 删除功能 - -> 点击列表上方或后方 `删除` 按钮 会根据OSS服务商类型 调用对应的删除(注意: 需确保对应的服务商配置正确)
-> 可勾选多服务商类型的文件进行删除 系统会自动判断 - -![输入图片说明](https://foruda.gitee.com/images/1678978438265941745/f32edc72_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1678978441938542080/43ed7c3d_1766278.png "屏幕截图") - -### 下载功能 - -> 点击列表后方对应资源的 `下载` 按钮 根据需求填写文件名 点击确认即可完成下载 - -![输入图片说明](https://foruda.gitee.com/images/1678978448927336261/409af888_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1678978452761792483/ed0a4a72_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/page.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/page.md deleted file mode 100644 index 2aafe47b..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/page.md +++ /dev/null @@ -1,29 +0,0 @@ -# 分页功能 -- - - - -## 重点说明 - -> 项目使用 `mybatis-plus` 分页插件 实现分页功能 大致用法与 MP 一致 [MP分页文档](https://baomidou.com/pages/97710a/)
-> 项目已配置分页合理化 页数溢出 例如: 一共5页 查了第6页 默认返回第一页
- -![输入图片说明](https://foruda.gitee.com/images/1678977804058241635/b5cb362d_1766278.png "屏幕截图") - -## 代码用法 - -> `Controller` 使用 `PageQuery` 接收分页参数 具体参数参考 `PageQuery` - -![输入图片说明](https://foruda.gitee.com/images/1678977844048821356/1f994221_1766278.png "屏幕截图") - -> 构建 `Mybatis-Plus` 分页对象
-> 使用 `PageQuery#build()` 方法 可快速(基于当前对象数据)构建 `MP` 分页对象 - -![输入图片说明](https://foruda.gitee.com/images/1678977862816976499/b82c1638_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678977876194578744/eaa7b854_1766278.png "屏幕截图")
- -具体用法与 `MP` 一致 - -> 自定义 `SQL` 方法分页
-> 只需在 `Mapper` 方法第一个参数和返回值 重点: 第一个参数 标注分页对象 - -![输入图片说明](https://foruda.gitee.com/images/1678977898181729571/6e102731_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678977906788451483/70979292_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/param_check.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/param_check.md deleted file mode 100644 index 95ee19d8..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/param_check.md +++ /dev/null @@ -1,158 +0,0 @@ -# 参数校验 -- - - - -参数校验在日常开发中十分常见,在本框架中引入了 `spring-boot-starter-validation` 依赖,底层基于 `hibernate-validator`,可以对参数进行校验。 - -## 参数校验使用 - -### 方法一:使用 `@Validated` 注解 - -#### 步骤一:标注 `@Validated` - -`@Validated` 可以标注在类上,或者是参数前。 - -```Java -/** 标注在类上 **/ -@Validated -@RestController -@RequestMapping("/auth") -public class AuthController { - - @PostMapping("/login") - public R login(@RequestBody LoginBody body) { - // ... - } - -} -``` - -```Java -/** 标注在参数前 **/ -@PostMapping -public R add(@Validated @RequestBody SysUserBo user) { - // ... -} -``` - -#### 步骤二:标注校验注解 - -在参数中加入校验注解。 - -```Java -public class SysUserBo { - - @NotBlank(message = "用户账号不能为空") - @Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符") - private String userName; - - @NotBlank(message = "用户昵称不能为空") - @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符") - private String nickName; - - @Email(message = "邮箱格式不正确") - @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") - private String email; - -} -``` - -常见校验注解见文末附表。 - -_注:message 支持 EL 表达式,{max} 直接读取前面的参数值。_ - -### 方法二:使用校验工具类 `ValidatorUtils` - -`org.dromara.common.core.utils.ValidatorUtils` - -![输入图片说明](https://foruda.gitee.com/images/1700050047426137432/206bd032_4959041.png "屏幕截图") - -使用方式 1:校验所有带有校验注解的属性 - -```Java -// 校验所有带有校验注解的属性 -ValidatorUtils.validate(object); -``` - -使用方式 2:按照分组校验属性(可以传多个分组) - -```Java -// 按照分组校验属性(可以传多个分组) -ValidatorUtils.validate(object, group); -``` - -## 扩展使用 - -### 扩展一:自定义校验注解 - -除了已有的校验注解以外,可以结合业务进行自定义。 - -以框架中的 `@Xss` 注解为例进行说明。 - -```Java -@Xss(message = "用户账号不能包含脚本字符") -@NotBlank(message = "用户账号不能为空") -@Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符") -private String userName; -``` - -#### 1:新增 `@Xss` 注解 - -`org.dromara.common.core.xss.Xss` - -![输入图片说明](https://foruda.gitee.com/images/1700048074014527096/b4e230c2_4959041.png "屏幕截图") - -#### 2:自定义校验器 - -自定义校验器实现 `jakarta.validation.ConstraintValidator` 接口。 - -`org.dromara.common.core.xss.XssValidator` - -![输入图片说明](https://foruda.gitee.com/images/1700048474563719650/f9172bdc_4959041.png "屏幕截图") - -### 扩展二:自定义分组校验 - -同一个对象在不同的请求中需要校验的参数不同,则可以使用分组校验。 - -#### 1:自定义分组 - -![输入图片说明](https://foruda.gitee.com/images/1700049439236073123/9e0d2e16_4959041.png "屏幕截图") - -#### 2:`@Validated` 注解指定分组 - -![输入图片说明](https://foruda.gitee.com/images/1700049302803077030/c2a985aa_4959041.png "屏幕截图") - -#### 3:校验注解中指定分组 - -![输入图片说明](https://foruda.gitee.com/images/1700049205699437759/96babbd6_4959041.png "屏幕截图") - -## 附录:常用校验注解 - -| 注解 | 使用(只列举特殊参数值) | 参数类型 | 说明 | -|------------------|--------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------| -| @AssertFalse | @AssertFalse | boolean / Boolean | 元素值必须为 false | -| @AssertTrue | @AssertTrue | boolean / Boolean | 元素值必须为 true | -| @DecimalMax | @DecimalMax(value=值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须小于或等于指定的最大值 | -| @DecimalMin | @DecimalMin(value=值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须大于或等于指定的最小值 | -| @Digits | @Digits(integer=整数位值, fraction=小数位值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 元素必须符合整数位以及小数位范围值 | -| @Email | @Email(regexp=正则表达式, flags=标志) | CharSequence | 元素是否符合正则表达式(正则表达式非必传) | -| @Future | @Future | - java.util.Date
- java.util.Calendar
- java.time.Instant
- java.time.LocalDate
- java.time.LocalDateTime
- java.time.LocalTime
- java.time.MonthDay
- java.time.OffsetDateTime
- java.time.OffsetTime
- java.time.Year
- java.time.YearMonth
- java.time.ZonedDateTime
- java.time.chrono.HijrahDate
- java.time.chrono.JapaneseDate
- java.time.chrono.MinguoDate
- java.time.chrono.ThaiBuddhistDate | 元素必须是未来的时刻、日期或时间 | -| @FutureOrPresent | @FutureOrPresent | 同 @Future | 元素必须是当前或未来的时刻、日期或时间 | -| @Length | @Length(min=最小值, max=最大值) | - CharSequence | 验证字符串是否在包含的 min 和 max 之间 | -| @Max | @Max(value=值) | - BigDecimal
- BigInteger
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须小于或等于指定的最大值 | -| @Min | @Min(value=值) | - BigDecimal
- BigInteger
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须大于或等于指定的最小值 | -| @Negative | @Negative | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须是一个严格的负数(即 0 被视为无效值) | -| @NegativeOrZero | @NegativeOrZero | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须为负数或 0 | -| @NotBlank | @NotBlank | CharSequence | 元素不能为 null,并且必须至少包含一个非空白字符 | -| @NotEmpty | @NotEmpty | - CharSequence
- Collection
- Map
- Array | 元素不能为 null 或空集合 | -| @NotNull | @NotNull | 不限类型 | 元素不能为 null | -| @Null | @Null | 不限类型 | 元素必须为 null | -| @Past | @Past | 同 @Future | 元素必须是过去的瞬间、日期或时间 | -| @PastOrPresent | @PastOrPresent | 同 @Future | 元素必须是过去或现在的瞬间、日期或时间 | -| @Pattern | @Pattern(regexp=正则表达式, flags=标志) | CharSequence | 元素必须与指定的正则表达式匹配(正则表达式遵循 Java 正则表达式约定) | -| @Positive | @Positive | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须是一个严格的正数(即 0 被视为无效值) | -| @PositiveOrZero | @PositiveOrZero | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须为正数或 0 | -| @Range | @Range(min=最小值, max=最大值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 验证元素是否在包含的 min 和 max 之间 | -| @Size | @Size(min=最小值, max=最大值) | - CharSequence
- Collection
- Map
- Array | 验证元素是否在包含的 min 和 max 之间 | -| @Valid | @Valid | 对象 | 级联验证 | - -更多注解可参考包: `org.hibernate.validator` \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/permissions.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/permissions.md deleted file mode 100644 index 62ce2946..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/permissions.md +++ /dev/null @@ -1,144 +0,0 @@ -# 关于数据权限 -- - - -* 参考 demo 模块用法(需导入 test.sql 文件) - -### 新版数据权限功能: -1.支持自动注入 sql 数据过滤
-2.查询、更新、删除 限制
-3.支持自定义数据字段过滤
-4.模板支持 spel 语法实现动态 Bean 处理
-5.支持与菜单权限标识符联合使用(2.2.X新功能) - -### 数据权限相关代码 - -| 类 | 说明 | 功能 | -|-------------------------------|-----------------|----------------------------------------| -| DataScopeType | 数据权限模板定义 | 用于定义数据权限模板 | -| DataPermission | 数据权限组注解 | 用于标注开启数据权限 (默认过滤部门权限) | -| DataColumn | 具体的数据权限字段标注 | 用于替换数据权限模板内的 key 变量 | -| PlusDataPermissionInterceptor | 数据权限 sql 拦截器 | 用于拦截所有 sql 检查是否标注了 `DataPermission` 注解 | -| PlusDataPermissionHandler | 数据权限处理器 | 用于处理被拦截到的 sql 为其添加数据权限过滤条件 | -| DataPermissionHelper | 数据权限助手 | 操作数据权限上下文变量 | -| SysDataScopeService | 自定义 Bean 处理数据权限 | 用于自定义扩展 | - -## 忽略数据权限 - -1.如果需要指定单独 SQL 不开启过滤,可在对应的 Mapper 接口添加如下忽略注解: -``` -@InterceptorIgnore(dataPermission = "true") -``` - -2.如果需要在业务层忽略数据权限,可调用以下方法: -``` -# 无返回值 -DataPermissionHelper.ignore(() -> { 业务代码 }); -# 有返回值 -Class result = DataPermissionHelper.ignore(() -> { return 业务代码 }); -``` - -### 使用方式 `参考demo模块` -数据权限体系 `用户 -> 多角色 => 角色 -> 单数据权限` -> 例子: 用户A 拥有两个角色
-> 角色A 部门经理 可查看 本部门及以下部门的数据
-> 角色B 兼职开发 可查看 仅自己的数据 - -> 创建角色 test1 为 本部门及以下 - -![输入图片说明](https://foruda.gitee.com/images/1678978669666831574/b51ed0a3_1766278.png "屏幕截图") - -> 创建角色 test2 为 仅本人 - -![输入图片说明](https://foruda.gitee.com/images/1678978674159035056/69cf32ad_1766278.png "屏幕截图") - -> 将其分配给用户 test - -![输入图片说明](https://foruda.gitee.com/images/1678978680492570269/a47b6afc_1766278.png "屏幕截图") - -### 编写列表查询(注意: 数据权限注解只能在 Mapper 层使用) - -> 标注数据权限注解 `dept_id` 为过滤部门字段 `user_id` 为过滤创建用户 - -![输入图片说明](https://foruda.gitee.com/images/1678978687179608427/d6b83c30_1766278.png "屏幕截图") - -### 重点注意: 如下情况不生效 - -> 有自定义实现方法 最终执行的mapper不是这个方法 所以无法生效 -> -> 解决方案: 一直往下点 找到最终的执行mapper重写即可 - -![输入图片说明](https://foruda.gitee.com/images/1678978692558777291/78b0a3dd_1766278.png "屏幕截图") - -### 编写数据权限模板 - -![输入图片说明](https://foruda.gitee.com/images/1678978697141183499/cfc1cb6a_1766278.png "屏幕截图") - -1.`code` 为关联角色的数据权限 `code`
-2.`sqlTemplate` 为 sql 模板
-`#{#deptName}` 为模板变量 对应权限注解的 `key`
-`#{@sdss}` 为模板 Bean 调用 调用其 Bean 的处理方法
-3.`elseSql` 为兜底 sql 处理当前角色与标注的注解 无对应的情况
-例如 数据权限为仅本人 且 方法并未标注具体过滤注解 则 填充 `1 = 0` 使条件不满足 不允许查看
-更详细用法可以参考 `DataScopeType` 注释 - -### 测试代码 - -> 使用 `管理员` 用户优先测试 - -![输入图片说明](https://foruda.gitee.com/images/1678978703250082481/e93a68a5_1766278.png "屏幕截图") - -> 使用 `test` 用户测试 - -![输入图片说明](https://foruda.gitee.com/images/1678978710644676604/d7f80487_1766278.png "屏幕截图") - -> 使用 `test` 删除一条不属于自己的数据 -> sql执行为不满足条件 不允许删除 - -![输入图片说明](https://foruda.gitee.com/images/1678978715711122947/441d61f7_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1678978720298532619/a35b1147_1766278.png "屏幕截图") - - -> 使用 `test` 修改与删除同理
-> 具体实现为 更新和删除方法 标注数据权限注解 - -![输入图片说明](https://foruda.gitee.com/images/1678978725329242504/a70491a1_1766278.png "屏幕截图") - -### 自定义SQL模板 - -> 1.首先在角色管理 数据权限下拉框 添加自定义模板
-> 为什么不放置到系统字典问题: 因数据权限与模板绑定 不应随意改动 最好事先定义好 - -![输入图片说明](https://foruda.gitee.com/images/1678978730563169865/3459ee17_1766278.png "屏幕截图") - -> 2.代码 `DataScopeType` 自定义一个SQL模板 - -![输入图片说明](https://foruda.gitee.com/images/1678978735588305505/3f030c67_1766278.png "屏幕截图") - -> 3.标注权限注解 - -![输入图片说明](https://foruda.gitee.com/images/1678978742259837391/eabe5caa_1766278.png "屏幕截图") - -> 4.设置数据权限变量 - -![输入图片说明](https://foruda.gitee.com/images/1678978746778429543/e211201f_1766278.png "屏幕截图") - -> 5.测试 - -![输入图片说明](https://foruda.gitee.com/images/1678978751875467640/7d210cf4_1766278.png "屏幕截图") - -### mybatis-plus 原生方法 增加数据权限过滤 - -> 首先查看需要重写的方法源码 重点`方法源码` `方法源码` `方法源码`
-> 例如重写 `selectPage` 方法
- -![输入图片说明](https://foruda.gitee.com/images/1678978757955000897/8315695c_1766278.png "屏幕截图") - -> 复制源码到自己的 `Mapper` 并增加数据权限注解 注意左边出现重写图标 即为重写成功
- -![输入图片说明](https://foruda.gitee.com/images/1678978763224011694/bbea25a1_1766278.png "屏幕截图") - -### 支持类标注 - -> 获取规则 `方法 > 类` 注意: 类标注后 所有方法(包括父类方法) 都会进行数据权限过滤 - -![输入图片说明](https://foruda.gitee.com/images/1678978767336534896/fb13ee99_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/permissions_control.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/permissions_control.md deleted file mode 100644 index 6931ca7a..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/permissions_control.md +++ /dev/null @@ -1,178 +0,0 @@ -# 权限控制 -- - - - -本文采用 `Sa-Token` 框架实现权限控制。[官方文档传送门](https://sa-token.cc/doc.html#/) - -## 权限校验 -权限校验指的是校验用户是否拥有访问某个 API 的能力。 - -通常情况下,一个 API 对应一个权限码,如果用户具备当前 API 的权限码,即代表有能力访问该 API。 - -### 1:权限标识 -在本系统中,每一个菜单功能都有对应的权限标识,可以在菜单管理中进行设置。 - -> 注: -> 1. 前后端的权限标识要保持一致。 -> 2. 权限标识可以使用通配符`*`。 - -![输入图片说明](https://foruda.gitee.com/images/1701086497939145368/133fb327_4959041.png "屏幕截图") - - -### 2:校验方法 -#### 2.1:使用 `@SaCheckPermission` 注解进行校验 -`@SaCheckPermission` 注解是由 `Sa-Token` 框架提供的角色校验注解,可以标注在方法上或类上。 - -- 单个权限校验: - -```Java -@SaCheckPermission("system:user:list") -``` - -- 多个权限校验(或模式,满足任意一个权限即可): - -```Java -@SaCheckPermission( - value = { - "system:user:list", - "system:user:query" - }, - mode = SaMode.OR -) -``` - -- 多个权限校验(与模式,必须满足所有权限): - -```Java -@SaCheckPermission( - value = { - "system:user:list", - "system:user:query" - }, - mode = SaMode.AND -) -``` - -#### 2.2:使用 `StpUtil` 工具类校验 -`StpUtil` 工具类是由 `Sa-Token` 框架提供的权限工具类,提供了常用的校验方法。 - -- 判断当前用户是否拥有某个权限(返回 `boolean`): - -```Java -StpUtil.hasPermission("system:user:list"); -``` - -- 单个权限校验: - -```Java -StpUtil.checkPermission("system:user:list"); -``` -如果验证未通过,则抛出异常: `NotPermissionException` - -- 多个权限校验(或模式,满足任意一个权限即可): - -```Java -StpUtil.checkPermissionOr("system:user:list", "system:user:query"); -``` -如果验证未通过,则抛出异常: `NotPermissionException` - -- 多个权限校验(与模式,必须满足所有权限): - -```Java -StpUtil.checkPermissionAnd("system:user:list", "system:user:query"); -``` -如果验证未通过,则抛出异常: `NotPermissionException` - -## 角色校验 -角色校验指的是校验用户是否拥有某个指定角色。 - -### 1:权限标识 -在本系统中,每个角色都拥有唯一的权限字符。 - -除了超级管理员角色外,其他角色的权限字符可以通过角色管理进行设置。 - -![输入图片说明](https://foruda.gitee.com/images/1701085080527279823/3255961d_4959041.png "屏幕截图") - -### 2:校验方法 -#### 2.1:使用 `@SaCheckRole` 注解校验 -`@SaCheckRole` 注解是由 `Sa-Token` 框架提供的角色校验注解,可以标注在方法上或类上。 - -- 单个角色校验 - -```Java -@SaCheckRole("superadmin") -``` - -- 多个角色校验(或模式,满足任意一个角色即可): - -```Java -@SaCheckRole( - value = { - "superadmin", - "admin" - }, - mode = SaMode.OR -) -``` - -- 多个角色校验(与模式,必须满足所有角色): - -```Java -@SaCheckRole( - value = { - "superadmin", - "admin" - }, - mode = SaMode.AND -) -``` - -#### 2.2:使用 `StpUtil` 工具类校验 -`StpUtil` 工具类是由 `Sa-Token` 框架提供的权限工具类,提供了常用的校验方法。 - -- 判断当前用户是否拥有某个角色(返回 `boolean`): - -```Java -StpUtil.hasRole("superadmin") -``` - -- 单个权限校验: - -```Java -StpUtil.checkRole("system:user:list"); -``` -如果验证未通过,则抛出异常: `NotRoleException` - -- 多个权限校验(或模式,满足任意一个角色即可): - -```Java -StpUtil.checkRoleOr("system:user:list", "system:user:query"); -``` -如果验证未通过,则抛出异常: `NotRoleException` - -- 多个权限校验(与模式,必须满足所有角色): - -```Java -StpUtil.checkRoleAnd("system:user:list", "system:user:query"); -``` -如果验证未通过,则抛出异常: `NotRoleException` - -## 角色权限双重 `OR` 校验 -除了分开校验以外,权限和角色也可以进行组合,表示备选校验。 - -简单举个例子: - -假设某个 API 的权限码为 `system:user:list`,角色 `admin` 可以调用,则可以这样写: - -```Java -@SaCheckPermission(value = "system:user:list", orRole = "admin") -``` - -以上权限只需要满足任意一项即可。更多写法可以参考 `Sa-Token` [官方文档](https://sa-token.cc/doc.html#/use/at-check?id=_4%e3%80%81%e8%a7%92%e8%89%b2%e6%9d%83%e9%99%90%e5%8f%8c%e9%87%8d-or%e6%a0%a1%e9%aa%8c)。 - -## 当前用户的所有权限 -本系统中实现了 `StpInterface` 接口,可以对用户的权限以及角色进行管理,并且可以根据不同的用户类型进行设置。 - -具体参考类:`org.dromara.common.satoken.core.service.SaPermissionImpl` - -## 忽略权限校验 -请参考文档:[网关路由与放行](/ruoyi-cloud-plus/framework/basic/router_release?id=网关路由与放行) diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/router_release.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/router_release.md deleted file mode 100644 index 9b08f069..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/router_release.md +++ /dev/null @@ -1,26 +0,0 @@ -# 网关路由与放行 -- - - - -## 新增路由 -`ruoyi-gateway.yml` 配置文件 增加 `routers` 配置
-**注意: 路径格式为 `/服务路径/controller路径/接口方法路径` `*代表任意一级 **代表任意所有级`**
-下图代表 `resource/**` 将所有 `resource开头的路径` 都路由到 `ruoyi-resource` 服务
-例如: `/resource/sms/code` `resource路由到ruoyi-resource服务` `sms路由到对应的contrller` `code 路由到对应的接口`
-![输入图片说明](https://foruda.gitee.com/images/1669623462957266512/c282932b_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1669623527799049459/201a52db_1766278.png "屏幕截图") - -## 放行使用方式 -nacos 中 `ruoyi-gateway.yml` 白名单放行
-**注意: 放行路径格式为 `/服务路径/controller路径/接口方法路径` `*代表任意一级 **代表任意所有级`**
-示例: `/resource/sms/code` 代表 `ruoyi-resource服务 sms的controller code接口`
-![输入图片说明](https://foruda.gitee.com/images/1660622672461635175/屏幕截图.png "屏幕截图.png") - -## 注意事项 - -接口放行后不需要token即可访问
-但是没有token也就无法获取用户信息与鉴权 - -### 解决方案 -删除接口上的鉴权注解
-删除接口内获取用户信息功能
-删除数据库实体类 自动注入 `createBy` `updateBy` 因为会获取用户数据 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/social.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/social.md deleted file mode 100644 index 2e3cd739..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/social.md +++ /dev/null @@ -1,68 +0,0 @@ -# 第三方授权功能 -- - - -## 版本 >= 2.X - -## 前置说明 -1. 该功能基于 `JustAuth` 实现,支持多家平台实现第三方授权登录。 -2. 以 `Gitee` 授权登录为例进行本功能的使用说明。 -3. 其他第三方授权配置信息获取方式可参考 `JustAuth` [官方文档](https://www.justauth.cn/guide/)。
- - ![输入图片说明](https://foruda.gitee.com/images/1690937097426867003/91d80587_4959041.png "屏幕截图") - -## 第三方授权配置 - -### 申请三方应用(以gitee为例) - -![输入图片说明](https://foruda.gitee.com/images/1700641775779304627/1cf1b56f_1766278.png "屏幕截图") - -### 更改后端配置 `application-dev.yml` - -![输入图片说明](https://foruda.gitee.com/images/1690936741844431943/580f8998_4959041.png "屏幕截图") - -**注:内网地址无法回调,请使用外网可以访问的地址。** - -![输入图片说明](https://foruda.gitee.com/images/1690940457570856867/ce22df18_4959041.png "屏幕截图") - -### 更改前端配置 `login.vue` - -![输入图片说明](https://foruda.gitee.com/images/1690937306197173754/5c1ece29_4959041.png "屏幕截图") - -## 授权登录(未绑定第三方平台) - -### 步骤一:个人中心授权第三方应用 - -![输入图片说明](https://foruda.gitee.com/images/1690938449386201097/ea375106_4959041.png "屏幕截图") - -### 步骤二:同意授权 - -![输入图片说明](https://foruda.gitee.com/images/1690938522418523183/81b327bf_4959041.png "屏幕截图") - -顶部出现授权成功,并跳转到系统首页。
- -![输入图片说明](https://foruda.gitee.com/images/1690938559178527841/563168e4_4959041.png "屏幕截图")
- -![输入图片说明](https://foruda.gitee.com/images/1690938636375977741/8ceb77cf_4959041.png "屏幕截图") - -查看第三方应用可看到授权成功的个人信息。
- -![输入图片说明](https://foruda.gitee.com/images/1690938725512311321/5532a2a9_4959041.png "屏幕截图") - -## 授权登录(已绑定第三方平台) - -### 步骤一:点击登录页面图标 - -![输入图片说明](https://foruda.gitee.com/images/1690938908352243992/fd044381_4959041.png "屏幕截图") - -### 步骤二:同意授权 - -![输入图片说明](https://foruda.gitee.com/images/1690938522418523183/81b327bf_4959041.png "屏幕截图") - -## 解除授权绑定 - -### 步骤一:个人中心点击解绑第三方应用 - -![输入图片说明](https://foruda.gitee.com/images/1690939087877969002/4ef324e7_4959041.png "屏幕截图") - -### 步骤二:点击确定完成解绑 - -![输入图片说明](https://foruda.gitee.com/images/1690939108017661775/7236088d_4959041.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/tenant.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/tenant.md deleted file mode 100644 index b57c3f63..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/tenant.md +++ /dev/null @@ -1,121 +0,0 @@ -# 多租户功能 -- - - -## 版本 >= 2.X - -## 前置说明(重要) -1. 本框架多租户功能的实现是基于 [MyBatis-Plus 多租户插件](https://baomidou.com/pages/aef2f2/#tenantlineinnerinterceptor) 的,只支持最简单的隔离。 -2. 本系统默认开启多租户功能。 -3. 多租户业务表建表需要加上租户id `tenant_id`,可参考其他系统表。 -4. 非多租户表可在配置文件进行配置排除。 -5. 只有超级管理员支持切换租户。 - -## 多租户使用流程(先说结论再展开!) -0. 开启多租户配置(系统默认已经开启) -1. 登录界面(可以选择不同租户) -> 注:如果为租户设置了绑定域名,则只能选择当前域名相关的租户列表。 -2. 设置多租户套餐 -3. 新增/修改租户(需要选择套餐) -4. 切换租户(仅超级管理员可操作) - -## 多租户配置 -`application-common.yml`
- -> 开关 `enable` 节点不用废话。
-> 如果不需要过滤租户的表可在 `excludes` 节点下添加。 - -**注意: 如果已经基于租户模式启动了程序 关闭租户必须删除mysql与redis内的相关数据重新导入sql** - -![输入图片说明](https://foruda.gitee.com/images/1680168468127690787/2cd3279e_4959041.png "屏幕截图") - -## 忽略租户 - -1.如果需要指定单独 SQL 不开启过滤,可在对应的 Mapper 接口添加如下忽略注解: -``` -@InterceptorIgnore(tenantLine = "true", dataPermission = "false") -``` -**此处注意事项 使用此注解如果需要开启数据权限 dataPermission = "false" 必须添加 mp的注解默认是忽略数据权限的 会导致数据权限失效** - -2.如果需要在业务层忽略多租户,可调用以下方法(推荐使用): -``` -# 无返回值 -TenantHelper.ignore(() -> { 业务代码 }); -# 有返回值 -Class result = TenantHelper.ignore(() -> { return 业务代码 }); -``` - -## 动态切换租户 - -**仅适用于特殊需求业务(例如: 创建租户时, 对该租户操作一些数据, 或者需要去其他租户查一些数据等) 禁止乱用后果自负** - -``` -# 无返回值 -TenantHelper.dynamic(租户id, () -> { 业务代码 }); -# 有返回值 -Class result = TenantHelper.dynamic(租户id, () -> { return 业务代码 }); -``` - -## 登录界面 - -![输入图片说明](https://foruda.gitee.com/images/1680173982933030545/bca146d7_4959041.png "屏幕截图") - -> 注:如果为租户设置了绑定域名,则只能选择当前域名相关的租户列表。 - -## 租户套餐管理 -### 租户套餐新增 -![输入图片说明](https://foruda.gitee.com/images/1680174317475230288/352957a1_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1680174602877523112/fc194f17_4959041.png "屏幕截图") - -> 注: -> 1、先新增套餐再新增租户,因为租户新增之后无法修改所选套餐。 -> 2、租户所关联的套餐如果后续有修改可以进行同步。 - - -## 租户管理 -### 默认租户 -> 注:默认租户无法修改 - -![输入图片说明](https://foruda.gitee.com/images/1680174738913576400/b6aca11a_4959041.png "屏幕截图") - -### 新增租户 -#### 填写表单 -![输入图片说明](https://foruda.gitee.com/images/1680174945220618443/f7181b51_4959041.png "屏幕截图") - -#### 选择新增的租户套餐 -![输入图片说明](https://foruda.gitee.com/images/1680174991869792688/0dbaadd6_4959041.png "屏幕截图") - -#### 新增完成 -![输入图片说明](https://foruda.gitee.com/images/1680175033853525725/42e64b4d_4959041.png "屏幕截图") - -#### 登录租户 -![输入图片说明](https://foruda.gitee.com/images/1680176145378931134/e05f347e_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1680176208161104366/44a935f1_4959041.png "屏幕截图") - -### 修改租户 -#### 配置域名 -![输入图片说明](https://foruda.gitee.com/images/1680175251192690133/141fa6a6_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1680175431036971650/db522d39_4959041.png "屏幕截图") - -#### 没有配置域名 -![输入图片说明](https://foruda.gitee.com/images/1680175541165540240/95e211f7_4959041.png "屏幕截图") - -#### 强调一下:这不是bug! -> 注:域名的配置就是为了绑定特定租户! - -### 同步套餐 -应用场景:租户套餐进行了修改,配置的菜单需要同步到特定租户。 -(不是所有租户都有更新套餐的权利, 这是跟钱挂钩的) - -> 点一下按钮的事,图略。 - -## 切换租户(仅超级管理员) -> 注:管理员切换租户不是切换用户,切换的只是数据,管理员拥有所有权限。 - -![输入图片说明](https://foruda.gitee.com/images/1680176324802967804/5c5d6fc3_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1680176431031189788/0c3f924c_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1680176496555243569/624ec677_4959041.png "屏幕截图") - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/user.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/user.md deleted file mode 100644 index 99050fa7..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/user.md +++ /dev/null @@ -1,85 +0,0 @@ -# 系统用户相关 -- - - - -> 框架采用sa-token控制权限 并对sa-token的api做了一定的业务封装
- -## 用户登录 - -> 参考自带多种登录实现 不限制用户数据来源 只需要构建 LoginUser 即可完成登录
-> 例如: `同表不同类型` `不同表` `同表+扩展表`
- -![输入图片说明](https://foruda.gitee.com/images/1699590555824776931/63d493fc_1766278.png "屏幕截图") - -## 获取用户信息 - -> 完成登录后会生成登录token返回给前端 前端需要再请求头携带token 后端方可获取到对应的用户信息 - -请求头传递格式: `Authorization: Bearer token` - -后端获取用户信息: -```java -LoginUser user = LoginHelper.getLoginUser(); -``` - -## 获取用户信息(基于token) -```java -LoginUser user = LoginHelper.getLoginUser(token); -``` - -## 获取登录用户id -```java -Long userId = LoginHelper.getUserId(); -``` - -## 获取登录用户账户名 -```java -String username = LoginHelper.getUsername(); -``` - -## 获取登录用户所属租户id -```java -String tenantId = LoginHelper.getTenantId(); -``` - -## 获取登录用户所属部门id -```java -Long deptId = LoginHelper.getDeptId(); -``` - -## 获取登录用户类型 -```java -UserType userType = LoginHelper.getUserType(); -``` - -## 获取登录用户其他扩展属性 -```java -Object obj = LoginHelper.getExtra(key); -``` - -## 设置登录用户其他扩展属性 - -参考登录设置 `clientId` 属性 - -![输入图片说明](https://foruda.gitee.com/images/1699591164562734430/42730add_1766278.png "屏幕截图") - -## 判断用户是否为超级管理员 - -```java -// 判断当前登录用户 -boolean b = LoginHelper.isSuperAdmin(); -// 判断用户基于id -boolean b = LoginHelper.isSuperAdmin(userId); -``` - -## 判断用户是否为租户管理员 - -```java -// 判断当前登录用户 -boolean b = LoginHelper.isTenantAdmin(); -// 判断用户基于角色组 -boolean b = LoginHelper.isSuperAdmin(rolePermission); -``` - -## 其他更多操作 -[Sa-Token 官方文档 - 登录认证](https://sa-token.cc/doc.html#/use/login-auth) - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/about_join.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/about_join.md deleted file mode 100644 index 77cde6ef..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/about_join.md +++ /dev/null @@ -1,12 +0,0 @@ -# 关于多表查询 -- - - -## 建议单表查询 - -文章连接: [大连接查询分解好处](https://java.isture.com/db/mysql/mysql-x-optimize-decompose-connection.html) - -![输入图片说明](https://foruda.gitee.com/images/1678979482724037085/1e74f3e1_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1666336728402711844/52788205_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1666336945935088277/f60e3288_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1666336954686520161/c6c83adc_1766278.png "屏幕截图")
-**(上图出自 <高性能MySql>)** \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/key.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/key.md deleted file mode 100644 index c960140d..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/key.md +++ /dev/null @@ -1,19 +0,0 @@ -# 主键使用说明 -- - - -## 关于如何使用分布式id或雪花id - -参考 `MybatisPlusConfig` 如需自定义 修改 `Bean` 实现即可 - -![输入图片说明](https://foruda.gitee.com/images/1678979401707903546/e25f6c06_1766278.png "屏幕截图") - -框架默认集成 雪花ID 只需全局更改 主键类型即可 - -![输入图片说明](https://foruda.gitee.com/images/1678979411517764918/1470df04_1766278.png "屏幕截图") - -如单表使用 可单独配置注解 - -![输入图片说明](https://foruda.gitee.com/images/1678979416033986923/2a4c3736_1766278.png "屏幕截图") - -### 重点说明 -* 由于雪花id位数过长 `Long` 类型在前端会失真 -* 框架已配置序列化方案 超越 `JS` 最大值自动转字符串 参考 `BigNumberSerializer` 类 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/test.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/test.md deleted file mode 100644 index 4c521ad1..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/test.md +++ /dev/null @@ -1,6 +0,0 @@ -# 单元测试 -- - - -## 参考文章 -[SpringBoot 2.X 整合 JUnit5 及全方位使用手册](https://lionli.blog.csdn.net/article/details/127576604) -## 参考代码(1.4.0新增) -![输入图片说明](https://foruda.gitee.com/images/1666973151030696086/6d44f4c2_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/transaction.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/transaction.md deleted file mode 100644 index 2b4966dc..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/transaction.md +++ /dev/null @@ -1,45 +0,0 @@ -# 事务相关 -- - - -若依文档对事务注解的描述 [关于事务](https://doc.ruoyi.vip/ruoyi/document/htsc.html#%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86) 以下对多数据源事务做补充: - - -## 多服务多数据源事务(框架已默认对接 直接使用seata注解即可) - -框架支持对接 `seata` 保证分布式多数据源事务
-详情参考多数据源框架文档连接: https://www.kancloud.cn/tracy5546/dynamic-datasource/2268607 - -## 本地多数据源事务 -请使用 `@DSTransactional` 注解 会代理 `@DS` 注解切换后的数据源事务做回滚处理
-只要 `@DSTransactional` 注解下任一环节发生异常,则全局多数据源事务回滚。
-如果BC上也有 `@DSTransactional` 会有影响吗?答:没有影响的。 - -```java -//如AService调用BService和CService的方法,A,B,C分别对应不同数据源。 - -public class AService { - - @DS("a")//如果a是默认数据源则不需要DS注解。 - @DSTransactional - public void dosomething(){ - BService.dosomething(); - CService.dosomething(); - } -} - -public class BService { - - @DS("b") - public void dosomething(){ - //dosomething - } -} - -public class CService { - - @DS("c") - public void dosomething(){ - //dosomething - } -} -``` - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/api_encrypt.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/api_encrypt.md deleted file mode 100644 index be4ce445..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/api_encrypt.md +++ /dev/null @@ -1,39 +0,0 @@ -# 数据加解密 -- - - - -## 1:API 加密注解 `@ApiEncrypt` -1. 对于标注了 `@ApiEncrypt` 注解的接口,请求参数都必须进行加密。 -2. 注解的参数 `response` 为响应加密标识,默认 `false` 不加密,为 `true` 表示响应加密。 -3. 加密解密逻辑由过滤器实现,详情可参考 `org.dromara.common.encrypt.filter.CryptoFilter`。 - -## 2:API 加密配置 -`application-common.yml` - -![输入图片说明](https://foruda.gitee.com/images/1701133628809355269/8979704a_4959041.png "屏幕截图") - -`.env.development` / `.env.production` - -![输入图片说明](https://foruda.gitee.com/images/1709533252413969800/1d0dff25_1766278.png "屏幕截图") - -> 注: -> 1. 注意修改 Nacos 配置。 -> 2. 公私钥与前端配置文件互为配对,如果需要更换请一同更换。 -> 3. 后端公钥对应前端私钥;后端私钥对应前端公钥。 - -## 3:前端开启加密 -如果需要开启 API 加密,则需要修改 `request` 的 `headers` 内容: -```Javascript -headers: { - isEncrypt: true -} -``` - -![输入图片说明](https://foruda.gitee.com/images/1701137141916998346/5e839bbe_4959041.png "屏幕截图") - -## 4.关于请求响应参数加解密说明 - -如何加解密请求响应参数看这里 -> [关于请求响应参数解密](/questions/api_encrypt.md) - -## 密钥生成说明 - -![输入图片说明](https://foruda.gitee.com/images/1675577852271308699/9b30258e_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/dynamic_datasource.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/dynamic_datasource.md deleted file mode 100644 index 21114cd4..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/dynamic_datasource.md +++ /dev/null @@ -1,45 +0,0 @@ -# 多数据源 -- - - - -### 框架默认 mysql 其他数据库使用说明 - -找到 `ruoyi-common-mybatis` 模块在 pom 文件内增加对应的jdbc依赖 - -![输入图片说明](https://foruda.gitee.com/images/1721098535176969987/d42870ca_1766278.png "屏幕截图") - - -### 关于多数据源事务 具体参考 `事务相关` 文档说明 - -### 多数据源框架功能介绍 -多数据源框架官方文档: [dynamic-datasource文档](https://www.kancloud.cn/tracy5546/dynamic-datasource/2264611) - -* 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。 -* 支持数据库敏感配置信息 加密 ENC()。 -* 支持每个数据库独立初始化表结构schema和数据库database。 -* 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。 -* 支持 自定义注解 ,需继承DS(3.2.0+)。 -* 提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。 -* 提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。 -* 提供 自定义数据源来源 方案(如全从数据库加载)。 -* 提供项目启动后 动态增加移除数据源 方案。 -* 提供Mybatis环境下的 纯读写分离 方案。 -* 提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。 -* 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。 -* 提供 基于seata的分布式事务方案。 -* 提供 本地多数据源事务方案。 附:不能和原生spring事务混用。 - -### 用法说明 - -> 加载顺序 `方法 => 类 => 默认`
- -![输入图片说明](https://foruda.gitee.com/images/1678979069737596299/abe8ae7f_1766278.png "屏幕截图") - -### 配置方式 - -![输入图片说明](https://foruda.gitee.com/images/1678979074000345758/b9238f0b_1766278.png "屏幕截图") - -### 数据库异构 - -例如: `mysql + oracle` 参考对应多数据源框架文档 [dynamic-ds文档](https://www.kancloud.cn/tracy5546/dynamic-datasource) - -![输入图片说明](https://foruda.gitee.com/images/1678979078387192317/2de94a78_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/encrypt.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/encrypt.md deleted file mode 100644 index 729a3039..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/encrypt.md +++ /dev/null @@ -1,38 +0,0 @@ -# 数据加解密 -- - - -## 框架版本 >= 1.6.0 - -## 引入依赖 - -```xml - - com.ruoyi - ruoyi-common-encrypt - -``` - -## 功能说明 - -数据库 数据存储加密 查询解密功能
-支持加密算法: `BASE64` `AES` `RSA` `SM2` `SM4` - -## 注解 `@EncryptField` - -![输入图片说明](https://foruda.gitee.com/images/1675577493013639395/cd920f15_1766278.png "屏幕截图") - -## 用法说明 - -**详细用法可参考案例 TestEncryptController 测试数据库加解密功能** - -全局默认加密配置(如果注解不配置则使用全局配置) - -![输入图片说明](https://foruda.gitee.com/images/1675577674063566357/dee94786_1766278.png "屏幕截图") - -注解可自定义算法与配置 - -![输入图片说明](https://foruda.gitee.com/images/1675577725117970708/7ee7a833_1766278.png "屏幕截图") - -## 密钥生成说明 - -![输入图片说明](https://foruda.gitee.com/images/1675577852271308699/9b30258e_1766278.png "屏幕截图") - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/idempotent.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/idempotent.md deleted file mode 100644 index 5f706710..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/idempotent.md +++ /dev/null @@ -1,29 +0,0 @@ -# 防重幂等 -- - - -## 功能介绍 - -防重功能为防止两条相同的数据重复提交导致脏数据或业务错乱
-**注意: 重复提交属于小概率事件 请不要拿并发压测与之相提并论**
-框架防重功能参考 `美团GTIS防重系统` 使用 请求参数与用户Token或URL 生成全局业务ID
-有效防止 `同一个用户` 在 `限制时间` 内对 `同一个业务` 提交 `相同的数据` - -框架防重处理 `支持业务失败或异常` 快速释放限制
-业务处理成功后 会在设置时间内 限制同一条数据的提交
-**注意: 只对同一个用户的同一个接口提交相同的数据有效** - - - - -### 美团GTIS系统流程图 - -[美团 分布式系统互斥性与幂等性问题的分析与解决](https://tech.meituan.com/2016/09/29/distributed-system-mutually-exclusive-idempotence-cerberus-gtis.html) - -![输入图片说明](https://foruda.gitee.com/images/1678979231862359032/34f030c5_1766278.png "屏幕截图") - -### 使用方法 - -在Controller标注 `@RepeatSubmit` 注解即可 - -![输入图片说明](https://foruda.gitee.com/images/1678979236772683145/9fa27e5b_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1678979240831458322/8e1fac4b_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/mail.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/mail.md deleted file mode 100644 index ce089802..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/mail.md +++ /dev/null @@ -1,15 +0,0 @@ -# 邮件功能 -- - - -## 配置功能 - -修改配置文件 - -![输入图片说明](https://foruda.gitee.com/images/1663555260932007318/fabb2bfa_1766278.png "屏幕截图") - -* `enabled` 为邮件功能开关 - -## 功能使用 - -参考 `demo` 模块 `MailController` 邮件演示案例 - -![输入图片说明](https://foruda.gitee.com/images/1663555374113593089/885b4db2_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sensitive.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sensitive.md deleted file mode 100644 index 3e2d92ba..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sensitive.md +++ /dev/null @@ -1,33 +0,0 @@ -# 数据脱敏 -- - - -## 功能说明 - -系统使用 `Jackson` 序列化策略 对标注了 `Sensitive` 注解的属性进行脱敏处理 - -## 使用教程 - -> 使用注解标注需要脱敏的字段 选择对应的策略 - -![输入图片说明](https://foruda.gitee.com/images/1699523591703893602/ffd6dba2_1766278.png "屏幕截图") - -* strategy 脱敏策略 -* roleKey 角色code(判断用户是否拥有角色权限) -* perms 权限code(判断用户是否拥有标识符权限) - -![输入图片说明](https://foruda.gitee.com/images/1678979315796014155/614adf91_1766278.png "屏幕截图") - -> 可再 `SensitiveStrategy` 内自定义策略 - -![输入图片说明](https://foruda.gitee.com/images/1678979319996224858/3b3e3c8b_1766278.png "屏幕截图") - -## 脱敏逻辑修改 - -> 系统使用通用接口处理是否需要脱敏 多个系统可以自定义不同的脱敏逻辑实现 - -![输入图片说明](https://foruda.gitee.com/images/1678979325448998856/b262e425_1766278.png "屏幕截图") - -> 系统默认处理逻辑为 根据角色与标识符或非管理员脱敏 可自行修改默认实现 - -![输入图片说明](https://foruda.gitee.com/images/1699523752627488891/f82f2f50_1766278.png "屏幕截图") - - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sms.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sms.md deleted file mode 100644 index 81fb345a..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sms.md +++ /dev/null @@ -1,51 +0,0 @@ -# 短信模块 -- - - - -# 配置功能 - -### 版本: >= v2.1.0 - -已完成 sms4j 项目整合 文档地址: https://sms4j.com/doc3 - -配置方式 具体厂商配置扩展 可以查看sms4j文档 - -![输入图片说明](https://foruda.gitee.com/images/1705573035997239848/2ca8512d_1766278.png "屏幕截图") - -使用方式 参考文档各种写法 下方为 demo 模块提供示例 - -![输入图片说明](https://foruda.gitee.com/images/1705573001447394180/2bd726d0_1766278.png "屏幕截图") - -### 版本: v1.2.0 提供短信模块 - -短信模块采用SPI加载
-使用哪家的短信 引入哪家的依赖 即可动态加载
-目前支持: `阿里云` `腾讯云` 欢迎扩展PR其他 - -> 参考 `ruoyi-demo` pom文件写法 - -![输入图片说明](https://foruda.gitee.com/images/1678979157797419426/cc9b7444_1766278.png "屏幕截图") - -> 修改配置文件 - -![输入图片说明](https://foruda.gitee.com/images/1678979163029635375/e5fd6e20_1766278.png "屏幕截图") - -* `enabled` 为短信功能开关 -* `endpoint` 为域名 各厂家域名固定 按照文档配置即可 -* `accessKeyId` 密钥id -* `accessKeySecret` 密钥密匙 -* `signName` 签名 -* `sdkAppId` 应用id 腾讯专用 - -## 功能使用 - -参考 `demo` 模块 `SmsController` 短信演示案例
-功能采用 `模板模式` 动态加载对应厂家的工具模板
-引入 `SmsTemplate` 即可使用 - -![输入图片说明](https://foruda.gitee.com/images/1678979168699323982/e9301e84_1766278.png "屏幕截图") - -## 重点须知 - -由于各厂家参数解析不一致 请遵守以下规则 - -![输入图片说明](https://foruda.gitee.com/images/1678979172581090456/ac1f10e8_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sse.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sse.md deleted file mode 100644 index ec51df7c..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sse.md +++ /dev/null @@ -1,24 +0,0 @@ -# SSE功能 -- - - - -## 框架版本 >= 2.2.1 - -## 配置说明 - -配置在 `ruoyi-resource` 目录下 远程调用可直接使用 `RemoteMessageService` 接口 - -![输入图片说明](https://foruda.gitee.com/images/1721986989993234455/4214cbbd_1766278.png "屏幕截图") - -* enabled 是否开启此功能 -* path 应用路径 - -## 使用方法 - -前端连接方式: `http://后端ip:端口/resource/sse?clientid=import.meta.env.VITE_APP_CLIENT_ID&Authorization=Bearer eyJ0eXAiO......` - -其中 `Authorization` 为请求token需要登录后获取 连接成功之后 与框架内其他获取登录用户方式一致 - -`SseMessageUtils.sendMessage` 推送单机消息(特殊需求使用)
-`SseMessageUtils.subscribeMessage` 订阅分布式消息(框架初始化已订阅)
-`SseMessageUtils.publishMessage` 发布分布式消息(推荐使用 所有集群内寻找到接收人)
-`SseMessageUtils.publishAll` 群发消息给所有连接人
\ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/translation.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/translation.md deleted file mode 100644 index d0834ab8..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/translation.md +++ /dev/null @@ -1,44 +0,0 @@ -# 翻译功能 -- - - -## 框架版本 >= 1.6.0 - -## 引入依赖包 - -```xml - - com.ruoyi - ruoyi-common-translation - -``` - -## 注解 - -![输入图片说明](https://foruda.gitee.com/images/1675575648043199227/d04b3e21_1766278.png "屏幕截图") - -`@Translation` 翻译注解 用于实体类字段上
-`@TranslationType` 翻译类别注解 用于实现类上标注与 `@Translation` 注解相同的 `type` 类型 实现翻译功能 - - -## 用法说明 - -默认提供功能 `用户id转账号(用户名)` `部门id转名称` `字典type转label` `ossId转url` - -![输入图片说明](https://foruda.gitee.com/images/1675575977860232549/143b74f8_1766278.png "屏幕截图") - -用户名翻译(映射翻译) 根据另一个映射字段 翻译保存到此字段 - -![输入图片说明](https://foruda.gitee.com/images/1675576044011477847/13eb9f57_1766278.png "屏幕截图") - -ossUrl翻译(直接翻译) 直接根据此字段值翻译后替换此字段值 - -![输入图片说明](https://foruda.gitee.com/images/1675576265894720924/70792f66_1766278.png "屏幕截图") - -字典翻译(其他扩展条件翻译) 根据`other`条件 自行定义如何使用 例如字典翻译`other`条件就是字典的唯一值 - -![输入图片说明](https://foruda.gitee.com/images/1675576391012282823/f95c5d78_1766278.png "屏幕截图") - -## 自定义扩展 - -实现接口 `TranslationInterface` 标注注解 `@TranslationType` 可参考框架默认实现 - -![输入图片说明](https://foruda.gitee.com/images/1676735454308997001/cfcf3590_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/websocket.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/websocket.md deleted file mode 100644 index 55145bad..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/websocket.md +++ /dev/null @@ -1,39 +0,0 @@ -# WebSocket功能 -- - - - -## 框架版本 >= 2.1.0 - -## 配置说明 - -配置在 `ruoyi-resource` 目录下 - -![输入图片说明](https://foruda.gitee.com/images/1688356273985385949/5e4d1de8_1766278.png "屏幕截图") - -* enabled 是否开启此功能 -* path 应用路径 -* allowedOrigins 设置访问源地址 - -**重点: 如关闭ws功能需连同前端ws开关一同关闭 不然前端启动会报错** - -![输入图片说明](https://foruda.gitee.com/images/1700644877512019497/052d2f46_1766278.png "屏幕截图") - -## 使用方法 - -前端连接方式: `ws://后端ip:端口/resource/websocket?clientid=import.meta.env.VITE_APP_CLIENT_ID&Authorization=Bearer eyJ0eXAiO......` - -**由于js不支持请求头传输故而采用参数传输 如支持请求头传输建议使用请求头传输** - -传输方式: -```js -headers: { - Authorization: "Bearer " + getToken(), - clientid: import.meta.env.VITE_APP_CLIENT_ID -} -``` - -其中 `Authorization` 为请求token需要登录后获取 连接成功之后 与框架内其他获取登录用户方式一致 - -`WebSocketUtils.sendMessage` 推送单机消息(特殊需求使用)
-`WebSocketUtils.subscribeMessage` 订阅分布式消息(框架初始化已订阅)
-`WebSocketUtils.publishMessage` 发布分布式消息(推荐使用 所有集群内寻找到接收人)
-`WebSocketUtils.publishAll` 群发消息给所有连接人
\ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/tree.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/tree.md deleted file mode 100644 index f649197c..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/tree.md +++ /dev/null @@ -1,91 +0,0 @@ -# 项目结构 -- - - -## 目录结构 -v2.2.1 -~~~ -RuoYi-Cloud-Plus -├─ ruoyi-api // api模块 -│ └─ ruoyi-api-bom // api模块依赖管理 -│ └─ ruoyi-api-resource // 资源api模块 -│ └─ ruoyi-api-system // 系统api模块 -│ └─ ruoyi-api-workflow // 工作流api模块 -├─ ruoyi-auth // 认证服务 [9210] -├─ ruoyi-common // 通用模块 -│ └─ ruoyi-common-alibaba-bom // alibaba 依赖管理 -│ └─ ruoyi-common-bom // common 依赖管理 -│ └─ ruoyi-common-bus // 消息总线模块 -│ └─ ruoyi-common-core // 核心功能模块 -│ └─ ruoyi-common-dict // 字典集成模块 -│ └─ ruoyi-common-doc // 文档集成模块 -│ └─ ruoyi-common-dubbo // dubbo集成模块 -│ └─ ruoyi-common-elasticsearch // ES集成模块 -│ └─ ruoyi-common-encrypt // 数据加解密模块 -│ └─ ruoyi-common-excel // excel集成模块 -│ └─ ruoyi-common-idempotent // 幂等功能模块 -│ └─ ruoyi-common-job // job定时任务集成模块 -│ └─ ruoyi-common-json // json集成模块 -│ └─ ruoyi-common-loadbalancer // 团队负载均衡集成模块 -│ └─ ruoyi-common-log // 日志集成模块 -│ └─ ruoyi-common-logstash // elk日志集成模块 -│ └─ ruoyi-common-mail // 邮件集成模块 -│ └─ ruoyi-common-mybatis // mybatis数据库相关集成模块 -│ └─ ruoyi-common-oss // oss相关集成模块 -│ └─ ruoyi-common-prometheus // prometheus监控 -│ └─ ruoyi-common-redis // redis集成模块 -│ └─ ruoyi-common-satoken // satoken集成模块 -│ └─ ruoyi-common-seata // seata分布式事务集成模块 -│ └─ ruoyi-common-security // 框架权限鉴权集成模块 -│ └─ ruoyi-common-sensitive // 脱敏功能模块 -│ └─ ruoyi-common-sentinel // sentinel集成模块 -│ └─ ruoyi-common-skylog // skywalking日志收集模块 -│ └─ ruoyi-common-sms // 短信集成模块 -│ └─ ruoyi-common-social // 社交三方功能模块 -│ └─ ruoyi-common-sse // sse流推送模块 -│ └─ ruoyi-common-tenant // 租户功能模块 -│ └─ ruoyi-common-translation // 通用翻译功能 -│ └─ ruoyi-common-web // web服务集成模块 -│ └─ ruoyi-common-websocket // websocket服务集成模块 -├─ ruoyi-example // 例子模块 -│ └─ ruoyi-demo // 演示模块 [9401] -│ └─ ruoyi-test-mq // mq演示模块 [9402] -├─ ruoyi-gateway // 网关模块 [8080] -├─ ruoyi-modules // 功能模块 -│ └─ ruoyi-gen // 代码生成模块 [9202] -│ └─ ruoyi-job // 任务调度模块 [9203,9901] -│ └─ ruoyi-resource // 资源模块 [9204] -│ └─ ruoyi-system // 系统模块 [9201] -│ └─ ruoyi-workflow // 工作流模块 [9205] -├─ ruoyi-visual // 可视化模块 -│ └─ ruoyi-monitor // 服务监控模块 [9100] -│ └─ ruoyi-nacos // nacos服务模块 [8848,9848,9849] -│ └─ ruoyi-seata-server // seata服务模块 [7091,8091] -│ └─ ruoyi-sentinel-dashboard // sentinel控制台模块 [8718] -│ └─ ruoyi-snailjob-server // 任务调度控制台模块 [8800,17888] -├─ plus-ui // 前端框架 [80] -├─ config/nacos // nacos配置文件(需复制到nacos配置中心使用) -│ └─ sentinel-ruoyi-gateway.json // sentinel对接gateway限流配置文件 -│ └─ seata-server.properties // seata服务配置文件 -│ └─ application-common.yml // 所有应用主共享配置文件 -│ └─ datasource.yml // 所有应用共享数据源配置文件 -│ └─ ruoyi-auth.yml // auth 模块配置文件 -│ └─ ruoyi-gateway.yml // gateway 模块配置文件 -│ └─ ruoyi-gen.yml // gen 模块配置文件 -│ └─ ruoyi-job.yml // job 模块配置文件 -│ └─ ruoyi-monitor.yml // monitor 模块配置文件 -│ └─ ruoyi-resource.yml // resource 模块配置文件 -│ └─ ruoyi-sentinel-dashboard.yml // sentinel 控制台 模块配置文件 -│ └─ ruoyi-snailjob-server.yml // snailjob 控制台 模块配置文件 -│ └─ ruoyi-system.yml // systen 模块配置文件 -│ └─ ruoyi-workflow.yml // workflow 模块配置文件 -├─ config/grafana // grafana配置文件(需复制到grafana使用) -│ └─ Nacos.json // Nacos监控页面 -│ └─ SLS JVM监控大盘.json // JVM监控页面 -│ └─ Spring Boot 2.1 Statistics.json // SpringBoot监控页面 -├─ sql // sql脚本 -├─ docker // docker 配置脚本 -├─ .run // 执行脚本文件 -├─ .editorconfig // 编辑器编码格式配置 -├─ LICENSE // 开源协议 -├─ pom.xml // 公共依赖 -├─ README.md // 框架说明文件 -~~~ \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/home.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/home.md deleted file mode 100644 index 290a4f9c..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/home.md +++ /dev/null @@ -1,137 +0,0 @@ - -
- -- - - -# 平台简介 -
- -[![码云Gitee](https://gitee.com/dromara/RuoYi-Cloud-Plus/badge/star.svg?theme=blue)](https://gitee.com/dromara/RuoYi-Cloud-Plus) -[![GitHub](https://img.shields.io/github/stars/dromara/RuoYi-Cloud-Plus.svg?style=social&label=Stars)](https://github.com/dromara/RuoYi-Cloud-Plus) -[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Cloud-Plus/blob/master/LICENSE) -[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Cloud-Plus) -
-[![RuoYi-Cloud-Plus](https://img.shields.io/badge/RuoYi_Cloud_Plus-2.2.1-success.svg)](https://gitee.com/dromara/RuoYi-Cloud-Plus) -[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.1-blue.svg)]() -[![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]() -[![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]() - -> RuoYi-Cloud-Plus `微服务通用权限管理系统` 重写 RuoYi-Cloud 全方位升级(不兼容原框架) - -> 项目代码、文档 均开源免费可商用 遵循开源协议在项目中保留开源协议文件即可
-活到老写到老 为兴趣而开源 为学习而开源 为让大家真正可以学到技术而开源 - -> 系统演示: [传送门](https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages?sort_id=4836388&doc_id=1469725) 分布式集群版本(功能一致) - -# 本框架与RuoYi的功能差异 - -| 功能 | 本框架 | RuoYi | -|-------------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------| -| 前端项目 | 采用 Vue3 + TS + ElementPlus 重写 | 基于Vue2/Vue3 + JS | -| 后端项目结构 | 采用插件化 + 扩展包形式 结构解耦 易于扩展 | 模块相互注入耦合严重难以扩展 | -| 后端代码风格 | 严格遵守Alibaba规范与项目统一配置的代码格式化 | 代码书写与常规结构不同阅读障碍大 | -| 分布式注册中心 | 采用 Alibaba Nacos 源码集成便于调试扩展与二次开发 框架还为其增加了各种监控 | 采用 Alibaba Nacos 自行搭建纯官方版本不可靠 | -| 分布式配置中心 | 采用 Alibaba Nacos 源码集成便于调试扩展与二次开发 框架还为其增加了各种监控 | 采用 Alibaba Nacos 自行搭建纯官方版本不可靠 | -| 服务网关 | 采用 SpringCloud Gateway 框架扩展了多种功能
例如:内网鉴权、请求体缓存、跨域配置、请求响应日志等 | 采用 SpringCloud Gateway 功能单一 | -| 负载均衡 | 采用 SpringCloud Loadbalancer 扩展支持了开发团队路由 便于多团队开发调试 | 采用 SpringCloud Loadbalancer 功能单一 | -| RPC远程调用 | 采用 全新 Apache Dubbo 3.X 历史悠远不用多说 | 采用 feign 功能有限编写方式 网络波动大 不稳定 | -| 分布式限流熔断 | 采用 Alibaba Sentinel 源码集成便于调试扩展与二次开发 框架还为其增加了各种监控 | 采用 Alibaba Sentinel 自行搭建纯官方版本不可靠 | -| 分布式事务 | 采用 Alibaba Seata 源码集成对接了Nacos与各种监控 简化了搭建部署流程 | 采用 Alibaba Seata 自行搭建纯官方版本 搭建繁琐与Nacos不挂钩 代码内使用方式怪异等 | -| Web容器 | 采用 Undertow 基于 XNIO 的高性能容器 | 采用 Tomcat | -| 权限认证 | 采用 Sa-Token、Jwt 静态使用功能齐全 低耦合 高扩展 | Spring Security 配置繁琐扩展性极差 | -| 权限注解 | 采用 Sa-Token 支持注解 登录校验、角色校验、权限校验、二级认证校验、HttpBasic校验、忽略校验
角色与权限校验支持多种条件 如 `AND` `OR` 或 `权限 OR 角色` 等复杂表达式 | 只支持是否存在匹配 | -| 关系数据库支持 | 原生支持 MySQL、Oracle、PostgreSQL、SQLServer
可同时使用异构切换(支持其他 mybatis-plus 支持的所有数据库 只需要增加jdbc依赖即可使用 达梦金仓等均有成功案例) | 支持 Mysql、Oracle 不支持同时使用、不支持异构切换 | -| 缓存数据库 | 支持 Redis 5-7 支持大部分新功能特性 如 分布式限流、分布式队列 | Redis 简单 get set 支持 | -| Redis客户端 | 采用 Redisson Redis官方推荐 基于Netty的客户端工具
支持Redis 90%以上的命令 底层优化规避很多不正确的用法 例如: keys被转换为scan
支持单机、哨兵、单主集群、多主集群等模式 | Lettuce + RedisTemplate 支持模式少 工具使用繁琐
连接池采用 common-pool Bug多经常性出问题 | -| 缓存注解 | 采用 Spring-Cache 注解 对其扩展了实现支持了更多功能
例如 过期时间 最大空闲时间 组最大长度等 只需一个注解即可完成数据自动缓存 | 需手动编写Redis代码逻辑 | -| ORM框架 | 采用 Mybatis-Plus 基于对象几乎不用写SQL全java操作 功能强大插件众多
例如多租户插件 分页插件 乐观锁插件等等 | 采用 Mybatis 基于XML需要手写SQL | -| SQL监控 | 采用 p6spy 可输出完整SQL与执行时间监控 | log输出 需手动拼接sql与参数无法快速查看调试问题 | -| 数据分页 | 采用 Mybatis-Plus 分页插件
框架对其进行了扩展 对象化分页对象 支持多种方式传参 支持前端多排序 复杂排序 | 采用 PageHelper 仅支持单查询分页 参数只能从param传 只能单排序 功能扩展性差 体验不好 | -| 数据权限 | 采用 Mybatis-Plus 插件 自行分析拼接SQL 无感式过滤
只需为Mapper设置好注解条件 支持多种自定义 不限于部门角色 | 采用 注解+aop 实现 基于部门角色 生成的sql兼容性差 不支持其他业务扩展
生成sql后需手动拼接到具体业务sql上 对于多个Mapper查询不起作用 | -| 数据脱敏 | 采用 注解 + jackson 序列化期间脱敏 支持不同模块不同的脱敏条件
支持多种策略 如身份证、手机号、地址、邮箱、银行卡等 可自行扩展 | 无 | -| 数据加解密 | 采用 注解 + mybatis 拦截器 对存取数据期间自动加解密
支持多种策略 如BASE64、AES、RSA、SM2、SM4等 | 无 | -| 数据翻译 | 采用 注解 + jackson 序列化期间动态修改数据 数据进行翻译
支持多种模式: `映射翻译` `直接翻译` `其他扩展条件翻译` 接口化两步即可完成自定义扩展 内置多种翻译实现 | 无 | -| 多数据源框架 | 采用 dynamic-datasource 支持市面大部分数据库
通过yml配置即可动态管理异构不同种类的数据库 也可通过前端页面添加数据源
支持spel表达式从请求头参数等条件切换数据源 | 基于 druid 手动编写代码配置数据源 配置繁琐 支持性差 | -| 多数据源事务 | 采用 dynamic-datasource 支持多数据源不同种类的数据库事务回滚 | 不支持 | -| 数据库连接池 | 采用 HikariCP Spring官方内置连接池 配置简单 以性能与稳定性闻名天下 | 采用 druid bug众多 社区维护差 活跃度低 配置众多繁琐性能一般 | -| 数据库主键 | 采用 雪花ID 基于时间戳的 有序增长 唯一ID 再也不用为分库分表 数据合并主键冲突重复而发愁 | 采用 数据库自增ID 支持数据量有限 不支持多数据源主键唯一 | -| WebSocket协议 | 基于 Spring 封装的 WebSocket 协议 扩展了Token鉴权与分布式会话同步 不再只是基于单机的废物 | 无 | -| SSE推送 | 采用 Spring SSE 实现 扩展了Token鉴权与分布式会话同步 | 无 | -| 序列化 | 采用 Jackson Spring官方内置序列化 靠谱!!! | 采用 fastjson bugjson 远近闻名 | -| 分布式幂等 | 参考美团GTIS防重系统简化实现(细节可看文档) | 手动编写注解基于aop实现 | -| 分布式任务调度 | 采用 SnailJob 天生支持分布式 统一的管理中心 支持多种数据库 支持分片重试DAG任务流等 | 采用 Quartz 基于数据库锁性能差 集群需要做很多配置与改造 | -| 分布式日志中心 | 采用 ELK 业界成熟解决方案 实时收集所有服务的运行日志 快速发现定位问题 | 无 | -| 分布式搜索引擎 | 采用 ElasticSearch、Easy-Es 以 Mybatis-Plus 方式操作 ElasticSearch | 无 | -| 分布式消息队列 | 采用 支持 Kafka、RocketMQ、RabbitMQ 各种 延迟消息 事务消息 流消息 | 无 | -| 分布式消息总线 | 采用 SpringCloud Bus 实现事件总线 跨服务通知 支持 Kafka、RocketMQ、RabbitMQ | 无 | -| 分库分表功能 | 采用 Apache Sharding-Proxy 代理服务无入侵支持分库分表 只需编写分库分表规则即可 | 无 | -| 文件存储 | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储
支持权限管理 安全可靠 文件可加密存储 | 采用 本机文件存储 文件裸漏 易丢失泄漏 不支持集群有单点效应 | -| 云存储 | 采用 AWS S3 协议客户端 支持 七牛、阿里、腾讯 等一切支持S3协议的厂家 | 不支持 | -| 短信 | 支持 阿里、腾讯 只需在yml配置好厂家密钥即可使用 接口化支持扩展其他厂家 | 不支持 | -| 邮件 | 采用 mail-api 通用协议支持大部分邮件厂商 | 不支持 | -| 接口文档 | 采用 SpringDoc、javadoc 无注解零入侵基于java注释
只需把注释写好 无需再写一大堆的文档注解了 | 采用 Springfox 已停止维护 需要编写大量的注解来支持文档生成 | -| 校验框架 | 采用 Validation 支持注解与工具类校验 注解支持国际化 | 仅支持注解 且注解不支持国际化 | -| Excel框架 | 采用 Alibaba EasyExcel 基于插件化
框架对其增加了很多功能 例如 自动合并相同内容 自动排列布局 字典翻译等 | 基于 POI 手写实现 功能有限 复杂 扩展性差 | -| 工作流支持 | 支持各种复杂审批 转办 委派 加减签 会签 或签 票签 等功能 | 无 | -| 工具类框架 | 采用 Hutool、Lombok 上百种工具覆盖90%的使用需求 基于注解自动生成 get set 等简化框架大量代码 | 手写工具稳定性差易出问题 工具数量有限 代码臃肿需自己手写 get set 等 | -| 服务监控框架 | 采用 SpringBoot-Admin 基于SpringBoot官方 actuator 探针机制
实时监控服务状态 框架还为其扩展了在线日志查看监控 | 无 | -| 全方位监控报警 | 采用 Prometheus、Grafana 多样化采集 多模板大屏展示 实时报警监控 提供详细的搭建文档 | 无 | -| 链路追踪 | 采用 Apache SkyWalking 还在为请求不知道去哪了 到哪出了问题而烦恼吗
用了它即可实时查看请求经过的每一处每一个节点 | 无 | -| 代码生成器 | 只需设计好表结构 一键生成所有crud代码与页面
降低80%的开发量 把精力都投入到业务设计上
框架为其适配MP、SpringDoc规范化代码 同时支持动态多数据源代码生成 | 代码生成原生结构 只支持单数据源生成 | -| 部署方式 | 支持 Docker 编排 一键搭建所有环境 让开发人员从此不再为搭建环境而烦恼 | 原生jar部署 其他环境需手动下载安装 自行搭建 | -| 项目路径修改 | 提供详细的修改方案文档 并为其做了一些改动 非常简单即可修改成自己想要的 | 需要做很多改造 文档说明有限 | -| 国际化 | 基于请求头动态返回不同语种的文本内容 开发难度低 有对应的工具类 支持大部分注解内容国际化 | 只提供基础功能 其他需自行编写扩展 | -| 代码单例测试 | 提供单例测试 使用方式编写方法与maven多环境单测插件 | 只提供基础功能 其他需自行编写扩展 | -| Demo案例 | 提供框架功能的实际使用案例 单独一个模块提供了很多很全 | 无 | - -## 本框架与RuoYi的业务差异 - -| 业务 | 功能说明 | 本框架 | RuoYi | -|--------|-----------------------------------------|-----|------------------| -| 租户管理 | 系统内租户的管理 如:租户套餐、过期时间、用户数量、企业信息等 | 支持 | 无 | -| 租户套餐管理 | 系统内租户所能使用的套餐管理 如:套餐内所包含的菜单等 | 支持 | 无 | -| 用户管理 | 用户的管理配置 如:新增用户、分配用户所属部门、角色、岗位等 | 支持 | 支持 | -| 部门管理 | 配置系统组织机构(公司、部门、小组) 树结构展现支持数据权限 | 支持 | 支持 | -| 岗位管理 | 配置系统用户所属担任职务 | 支持 | 支持 | -| 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等 | 支持 | 支持 | -| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 | 支持 | 支持 | -| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 | 支持 | 支持 | -| 参数管理 | 对系统动态配置常用参数 | 支持 | 支持 | -| 通知公告 | 系统通知公告信息发布维护 | 支持 | 支持 | -| 操作日志 | 系统正常操作日志记录和查询 系统异常信息日志记录和查询 | 支持 | 支持 | -| 登录日志 | 系统登录日志记录查询包含登录异常 | 支持 | 支持 | -| 文件管理 | 系统文件展示、上传、下载、删除等管理 | 支持 | 无 | -| 文件配置管理 | 系统文件上传、下载所需要的配置信息动态添加、修改、删除等管理 | 支持 | 无 | -| 在线用户管理 | 已登录系统的在线用户信息监控与强制踢出操作 | 支持 | 支持 | -| 定时任务 | 运行报表、任务管理(添加、修改、删除)、日志管理、执行器管理等 | 支持 | 仅支持任务与日志管理 | -| 代码生成 | 多数据源前后端代码的生成(java、html、xml、sql)支持CRUD下载 | 支持 | 仅支持单数据源 | -| 系统接口 | 根据业务代码自动生成相关的api接口文档 | 支持 | 支持 | -| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等 | 支持 | 仅支持单机CPU、内存、磁盘监控 | -| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | 支持 | 支持 | -| 在线构建器 | 拖动表单元素生成相应的HTML代码。 | 支持 | 支持 | -| 使用案例 | 系统的一些功能案例 | 支持 | 不支持 | - -## 演示图例 - -| | | -|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| -| ![输入图片说明](https://foruda.gitee.com/images/1680077524361362822/270bb429_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077619939771291/989bf9b6_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680077681751513929/1c27c5bd_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077721559267315/74d63e23_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680077765638904515/1b75d4a6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078026375951297/eded7a4b_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078237104531207/0eb1b6a7_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078254306078709/5931e22f_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078287971528493/0b9af60a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078308138770249/8d3b6696_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078352553634393/db5ef880_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078378238393374/601e4357_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078414983206024/2aae27c1_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078446738419874/ecce7d59_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078475971341775/149e8634_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078491666717143/3fadece7_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078558863188826/fb8ced2a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078574561685461/ae68a0b2_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078594932772013/9d8bfec6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078626493093532/fcfe4ff6_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078643608812515/0295bd4f_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078685196286463/d7612c81_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078703877318597/56fce0bc_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078716586545643/b6dbd68f_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078734103217688/eb1e6aa6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078759131415480/73c525d8_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078779416197879/75e3ed02_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078802329118061/77e10915_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078893627848351/34a1c342_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078928175016986/f126ec4a_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078941718318363/b68a0f72_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078963175518631/3bb769a1_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078982294090567/b31c343d_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079000642440444/77ca82a9_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680079020995074177/03b7d52e_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079039367822173/76811806_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680079274333484664/4dfdc7c0_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079290467458224/d6715fcf_1766278.png "屏幕截图") | - - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/1.Xinit.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/1.Xinit.md deleted file mode 100644 index 19492b1e..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/1.Xinit.md +++ /dev/null @@ -1,87 +0,0 @@ -# 1.X项目初始化 -- - - -### 项目分支说明 -`master` 主分支 稳定发布分支
-`dev` 开发分支 代码随时更新 不推荐使用 经测试后会发布到主分支
-`2.X` 新2.X大版本分支
-`future/*` 新功能预览分支 - -### 项目必备环境 -> 推荐使用 `docker` 安装 项目内置 `docker` 编排文件 - -* oracle jdk 8 11 (暂时不支持 17 不支持大于 jdk8_202 因为202是最后一个免费版本) -* mysql 5.7 8.0 (5.6未适配可能会有问题) -* oracle 11g 12c -* postgres 13 14 -* redis 5.X 6.X 7.X 由于框架大量使用了redis特性 版本必须 >= 5.X ([win redis 下载地址](https://github.com/zkteco-home/redis-windows)) -* minio 本地文件存储 或 阿里云 腾讯云 七牛云等一切支持S3协议的云存储 -* maven 3.6.3 3.8.X -* nodejs >= 12 -* npm 6.X 8.X (7.X确认有问题) -* nacos >= 2.X(框架1.3.0内置nacos) -* sentinel 框架内置 -* seata 框架内置 - -### 需勾选 maven 对应环境 -![输入图片说明](https://foruda.gitee.com/images/1678976284045210056/a2f28d33_1766278.png "屏幕截图") - -### 默认 `JDK8` 如有变动 需更改以下配置 - -![输入图片说明](https://foruda.gitee.com/images/1686813181851830778/2dd7954c_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1686813189749486666/c526486c_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1686813196981178511/cd218705_1766278.png "屏幕截图") - -### sql导入 -将sql导入到与sql文件名对应的数据库(不要放到一个库下)
- -![输入图片说明](https://foruda.gitee.com/images/1678981513725772842/8097a816_1766278.png "屏幕截图") - -### 使用内置 `ruoyi-naocs` 服务 从这开始 - -> 更改 ruoyi-nacos 数据库地址 - -![输入图片说明](https://foruda.gitee.com/images/1664422006264405180/cac5afc6_1766278.png "屏幕截图") - -**其余流程同下方步骤一致** - -### 自建 Nacos 从这开始 - -**Nacos 数据库指向 ry-config 数据库(此处重点: 此数据库为定制数据 未使用此库会无法读取配置)** - -> 将项目 `config/nacos` 下所有配置 复制到 `nacos` 内(建议手动复制内容 防止编码不一致问题) - -![输入图片说明](https://foruda.gitee.com/images/1678979826345958752/913142c9_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1678979856705927770/75cc1e8c_1766278.png "屏幕截图") - -> 更改 `主pom文件` 对应环境的 `nacos` 地址 - -![输入图片说明](https://foruda.gitee.com/images/1678979881888833924/7e6a191f_1766278.png "屏幕截图") - -### 更改 `Nacos` 自定义配置 - -**忠告: 微服务配置相当复杂 请勿在不懂原理的情况下乱改** - -> `application-common.yml` 更改 - -![输入图片说明](https://foruda.gitee.com/images/1678979889410167794/100db4ab_1766278.png "屏幕截图") - -> `datasource.yml` 更改 - -![输入图片说明](https://foruda.gitee.com/images/1678979894464784408/0d020c07_1766278.png "屏幕截图") - -> `seata-server.properties` 更改 - -![输入图片说明](https://foruda.gitee.com/images/1678979902433843257/12da2839_1766278.png "屏幕截图") - -### 使用内置 `ruoyi-seata-server` 服务 从这开始 - -执行 `ry-seata.sql` 文件 初始化服务端数据库
-修改 `nacos` 内的 `seata-server.properties` 的数据库地址
-启动 `ruoyi-seata-server` 服务即可 - -### 服务启动顺序说明 - -1. 必须启动基础建设: mysql redis nacos
-2. 可选启动基础建设: minio(影响文件上传) seata(影响分布式事务 默认开启) sentinel(影响熔断限流) monitor(影响监控) xxljob(影响定时任务)
-3. 必须启动应用服务: gateway auth system
-4. 可选启动应用服务: resource(影响资源使用 文件上传 邮件 短信等) gen(代码生成) job(影响定时任务) demo(影响demo使用) diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/deploy.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/deploy.md deleted file mode 100644 index bdc653bc..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/deploy.md +++ /dev/null @@ -1,118 +0,0 @@ -# 应用部署 -- - - -## 版本 >= 1.3.0 - -### 请优先阅读 [idea环境配置](/ruoyi-cloud-plus/quickstart/idea_environment.md) - -## 手动部署 - -在服务器安装 `mysql` `redis` `nginx` `minio` 等其他组件 - -将项目内 `docker/` 文件夹下的文件内容 放到对应的组件内
-例如: 将项目内 `docker/nginx/nginx.conf` 配置文件 复制到 `nginx` 配置内
-将项目内 `docker/redis/redis.conf` 配置文件 复制到 `redis` 配置内
- -并修改相关参数如 `前端页面存放位置` `后端Ip地址` 等使其生效 - -jar包部署后端服务 打包命令如下 -```mvn -mvn clean install -D maven.test.skip=true -P prod -``` -前端参考下方前端部署章节 - - -## docker 后端部署 - -### 请优先阅读 [idea环境配置](https://gitee.com/dromara/RuoYi-Cloud-Plus/wikis/pages?sort_id=5985190&doc_id=2056143) - -**重点: 一知半解的必看** -> [docker安装](https://lionli.blog.csdn.net/article/details/83153029)
-> [docker-compose安装](https://lionli.blog.csdn.net/article/details/111220320)
-> [docker网络模式讲解](https://lionli.blog.csdn.net/article/details/109603785)
-> [docker 开启端口 2375 供外部程序访问](https://lionli.blog.csdn.net/article/details/92627962) - -### 将配置使用FTP上传到根目录 -idea拖拽文件到远程目录即可上传
-![输入图片说明](https://foruda.gitee.com/images/1662109450908169859/eaac9299_1766278.png "屏幕截图") - -### 给docker分配文件夹权限 -**重点注意: 一定要确保目录 `/docker` 及其所有子目录 具有写权限 如果后续出现权限异常问题 重新执行一遍分配权限** -![输入图片说明](https://foruda.gitee.com/images/1662109847279259882/3a2202c1_1766278.png "屏幕截图") -```shell -chmod -R 777 /docker -``` -### 构建应用镜像 - -**1.需要先使用maven打包成jar包**
-![输入图片说明](https://foruda.gitee.com/images/1662110477410977621/c6931c42_1766278.png "屏幕截图") - -**2.执行构建**
-> 项目初始化后会自动生成构建镜像的运行配置
-配置好docker连接之后 运行如下即可构建对应的应用镜像 - -**重点注意: idea2024及以上版本要求必须在本地安装docker才可以执行如下操作** - -![输入图片说明](https://foruda.gitee.com/images/1662110192257483752/0f754b47_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1662120029312793237/89dee3e5_1766278.png "屏幕截图") - -**3.结构讲解**
-右键编辑 即可看到内部配置
- -![输入图片说明](https://foruda.gitee.com/images/1662458355500139498/eaa26036_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1662458446794722159/32c086a7_1766278.png "屏幕截图") - - -### 创建基础服务 - -```shell -docker-compose up -d mysql nginx-web redis minio -``` - -### 创建中心服务(需要先构建服务镜像) - -1.X -```shell -docker-compose up -d nacos seata-server sentinel ruoyi-monitor ruoyi-xxl-job-admin -``` - -2.X -```shell -docker-compose up -d nacos seata-server sentinel ruoyi-monitor ruoyi-snailjob-server -``` - -### 创建业务服务(需要先构建服务镜像) - -```shell -docker-compose up -d ruoyi-gateway ruoyi-auth ruoyi-system ruoyi-resource -``` - -### docker其他操作(idea的docker插件 推荐使用) -![输入图片说明](https://foruda.gitee.com/images/1662458296425228696/90b4b4f8_1766278.png "屏幕截图") - - -## 前端部署 - -执行打包命令 -```shell -# 打包正式环境 -npm run build:prod -``` -打包后生成打包文件在 `ruoyi-ui/dist` 目录
-将 `dist` 目录下文件(不包含 `dist` 目录) 上传到部署服务器 `docker/nginx/html` 目录下(手动部署放入自己配置的路径即可)
-![输入图片说明](https://foruda.gitee.com/images/1662110914769648699/07f344c4_1766278.png "屏幕截图")
-重启 `nginx` 服务即可 - - -### 如需更改后端代理路径或者后端ip地址的话往下看 - -更改`nginx.conf`配置文件代理路径(注意: /开头/结尾) - -![输入图片说明](https://foruda.gitee.com/images/1660185698211067202/屏幕截图.png "屏幕截图.png") - -更改前端`.env.环境` 文件内的 `VITE_APP_BASE_API` - -![输入图片说明](https://foruda.gitee.com/images/1724318035232137124/5d035a09_1766278.png "屏幕截图") - -更改`nginx.conf`配置文件后端ip地址 - -![输入图片说明](https://foruda.gitee.com/images/1660185711265558730/屏幕截图.png "屏幕截图.png") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/extend_project.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/extend_project.md deleted file mode 100644 index 8d68fa4d..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/extend_project.md +++ /dev/null @@ -1,42 +0,0 @@ -# 基于 RuoYi-Cloud-Plus 的扩展项目列表 -- - - -### 精品PR 欢迎投稿 -| 功能介绍 | PR地址 | -|-------------------------------------|------------------------------------------------------| -| 拖拽图片调整显示顺序 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/173 | -| 增加Jasypt加密库对配置文件加密 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/177 | -| 使用富文本wangeditor5替换Quill | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/213 | -| sentinel持久化nacos动态更改 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/37 | -| 集成screw数据库文档功能模块 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/42 | -| Excel导入模板增加批注支持 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/222 | -| 压缩包处理工具 支持本地文件/目录+oss文件/网络文件混合 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/44 | -| 添加websocket模块 支持satoken鉴权 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/65 | -| 数据库字段加解密(支持 base64 aes rsa sm2 sm4) | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/274 | -| 增加liquibase迁移数据库 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/299 | -| 增加OSS模块支持本地环境 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/353 | -| 扩展模块独立集成flyway | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/439 | -| 扩展模块独立集成go-view大屏看板 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/445 | -| 基于AmazonS3协议的分片上传 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/130 | -| 扩展forest http客户端 声明式http请求 二次封装像工具类 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/547 | -| 增加短链接生成工具 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/515 | -| 新增oss预签名上传工具组合使用异步客户端分片 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/522 | -| 新增规则引擎LiteFlow,SQL持久化接入,支持可视化页面 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/552 | -| 一键部署到私有Nexus仓库 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/181 | -| 服务状态监控发送邮件钉钉等 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/568 | -| 登录验证支持2FA验证 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/578 | - -### 欢迎投稿 项目介绍+项目地址 - - -| 项目介绍 | 项目地址 | -|--------------------------------|-------------------------------------------------------------------------| -| 分布式集群扩展 | https://gitee.com/dromara/RuoYi-Vue-Plus | -| Plus学习笔记(常规功能) | https://zhonglingyuxiu1028.github.io/zlyx-space/#/ruoyi-vue-plus/home | -| Plus学习笔记(微服务组件) | https://zhonglingyuxiu1028.github.io/zlyx-space/#/ruoyi-cloud-plus/home | -| 基于uniapp+TmUI从0开发 支持H5/小程序/安卓 | https://gitee.com/dapppp/ruoyi-plus-miniapp | -| 基于RuoYi-App框架二次修改使用Uniapp+Vue3 | https://gitee.com/wangying110166/ruo-yi-uni-app-plus | -| 基于RuoYi-App框架对接Plus后端 | https://gitee.com/FnTop/RuoYi-App-Plus | -| 基于vben(ant-design-vue)前端项目 | https://gitee.com/dapppp/ruoyi-plus-vben | -| 基于vue-next-admin的vue3+ts前端 | https://gitee.com/thiszhc/RuoYi-Vue3-UI | -| MybatisFlex版本 | https://gitee.com/yhan219/ruoyi-cloud-flex | - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/idea_environment.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/idea_environment.md deleted file mode 100644 index 25a5fa3c..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/idea_environment.md +++ /dev/null @@ -1,38 +0,0 @@ -# idea环境配置 -- - - -## 配置项目编码 -![输入图片说明](https://foruda.gitee.com/images/1662107706295343419/e27065a9_1766278.png "屏幕截图") - -## 配置运行看板 -![输入图片说明](https://foruda.gitee.com/images/1662108673306567278/8af97b47_1766278.png "屏幕截图") -### 配置spring与docker看板 -![输入图片说明](https://foruda.gitee.com/images/1662111392476935892/6b6760fb_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1662108865191892425/3c045999_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1662108877322329668/ddb6d93d_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1662108894122798039/6a53a38c_1766278.png "屏幕截图") - -## 配置服务器SSH连接 -进入 `Settings -> Tools -> SSH Configurations` 点击加号创建SSH连接配置
-填写 服务器IP 用户名 密码 端口号 点击 Test Connection 测试连接
-![输入图片说明](https://foruda.gitee.com/images/1662107776533098115/bd78467b_1766278.png "屏幕截图") -使用Terminal 工具 点击箭头找到上方创建的SSH连接配置
-选择即可进入SSH连接界面 在这里可以对服务器进行命令操作
-![输入图片说明](https://foruda.gitee.com/images/1662108010120640495/c70f9f9a_1766278.png "屏幕截图") - -## 配置服务器FTP连接 -进入 `Settings -> Build-> Deployment` 点击加号 选择SFTP 创建 FTP 连接配置
-选择之前创建好的SSH配置 点击 Test Connection 测试连接
-![输入图片说明](https://foruda.gitee.com/images/1662107899553257979/e2eeb7fd_1766278.png "屏幕截图") -在IDEA上方工具栏 找到 `Tools -> Deployment -> Browse Remote Host` 打开远程界面
-点击箭头找到我们上方配置的SFTP连接配置 即可连接到服务器的文件目录
-![输入图片说明](https://foruda.gitee.com/images/1662107974682787233/b8a601fd_1766278.png "屏幕截图") - -## 配置Docker连接 -### 可操作远程docker与构建上传docker镜像(代替原来maven docker插件) -tcp连接需要开放服务器2375端口
-ssh需要使用上方的SSH连接配置
-建议使用SSH连接
-![输入图片说明](https://foruda.gitee.com/images/1662108188005932060/75872bf8_1766278.png "屏幕截图") -配置好之后 在运行窗口会多出一个Docker图标 双击即可连接远程docker
-可以查看容器实时日志 启动 重启 停止 等操作
-![输入图片说明](https://foruda.gitee.com/images/1662108250902891875/b82d022b_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/init.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/init.md deleted file mode 100644 index f6d4fadc..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/init.md +++ /dev/null @@ -1,102 +0,0 @@ -# 2.X项目初始化 -- - - -### 项目分支说明 - -`2.X` 主分支 新2.X版本 稳定发布分支
-`dev` 开发分支 代码随时更新 不推荐使用 经测试后会发布到主分支
-`future/*` 新功能预览分支 - -### 项目必备环境 -> 推荐使用 `docker` 安装 项目内置 `docker` 编排文件 - -**注意: 禁止使用 `oraclejdk`(由于spring的bug导致打包运行会报错)** - -**Spring官方推荐使用JDK https://bell-sw.com/pages/downloads/** - -![输入图片说明](https://foruda.gitee.com/images/1720080025744223375/0213a652_1766278.png "屏幕截图") - -* openjdk-17/21 或 graalvm-community-jdk-17/21 [下载地址](https://github.com/graalvm/graalvm-ce-builds/releases) 版本 -* mysql 5.7 8.0 (其他版本未测试 如其他版本没问题 可以告知咱们) -* oracle >= 12c (其他版本未测试 如其他版本没问题 可以告知咱们) -* postgres 13 14 (其他版本未测试 如其他版本没问题 可以告知咱们) -* redis 5.X 6.X 7.X 由于框架大量使用了redis特性 版本必须 >= 5.X ([win redis 下载地址](https://github.com/zkteco-home/redis-windows)) -* minio 本地文件存储 或 阿里云 腾讯云 七牛云等一切支持S3协议的云存储 -* maven >= 3.8.X -* nodejs 18.18 (其他版本未测试 如其他版本没问题 可以告知咱们) -* npm >= 8.X (7.X确认有问题) -* idea 2022 2024 (一定不要使用2023后果自负 bug太多影响项目开发) -* nacos >= 2.X(框架已经内置 采用nacos官方jar包) -* sentinel 框架内置(采用sentinel官方jar包) -* seata 框架内置(采用seata官方jar包) - -### 需勾选 maven 对应环境 - -![输入图片说明](https://foruda.gitee.com/images/1678976284045210056/a2f28d33_1766278.png "屏幕截图") - -### 默认 `JDK17` 如有变动 需更改以下配置 - -![输入图片说明](https://foruda.gitee.com/images/1678941027820943505/c688e01e_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1678941120518807034/4d56fcc9_1766278.png "屏幕截图") - -### sql导入 - -将sql导入到与sql文件名对应的数据库(不要放到一个库下)
-默认数据库为mysql如需使用其他数据库 看这里 => [多数据库数据源](../framework/extend/dynamic_datasource.md)
- -![输入图片说明](https://foruda.gitee.com/images/1717122730708924506/7f3aaecf_1766278.png "屏幕截图") - -### 使用内置 `ruoyi-naocs` 服务 从这开始 - -> 更改 ruoyi-nacos 数据库地址 - -![输入图片说明](https://foruda.gitee.com/images/1664422006264405180/cac5afc6_1766278.png "屏幕截图") - -**其余流程同下方步骤一致** - -### 自建 Nacos 从这开始 - -**Nacos 数据库指向 ry-config 数据库(此处重点: 此数据库为定制数据 未使用此库会无法读取配置)** - -> 将项目 `config/nacos` 下所有配置 复制到 `nacos` 内(建议手动复制内容 防止编码不一致问题) - -**注意: 不懂就不要乱改配置文件内容 框架内所有功能都是配置好的!!!不要画蛇添足**
-**注意: 不懂就不要乱改配置文件内容 框架内所有功能都是配置好的!!!不要画蛇添足**
-**注意: 不懂就不要乱改配置文件内容 框架内所有功能都是配置好的!!!不要画蛇添足**
- -![输入图片说明](https://foruda.gitee.com/images/1678979826345958752/913142c9_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1678979856705927770/75cc1e8c_1766278.png "屏幕截图") - -> 更改 `主pom文件` 对应环境的 `nacos` 地址 - -![输入图片说明](https://foruda.gitee.com/images/1678979881888833924/7e6a191f_1766278.png "屏幕截图") - -### 更改 `Nacos` 自定义配置 - -**忠告: 微服务配置相当复杂 请勿在不懂原理的情况下乱改**
-**忠告: 微服务配置相当复杂 请勿在不懂原理的情况下乱改**
-**忠告: 微服务配置相当复杂 请勿在不懂原理的情况下乱改**
- -> `application-common.yml` 更改 - -![输入图片说明](https://foruda.gitee.com/images/1678979889410167794/100db4ab_1766278.png "屏幕截图") - -> `datasource.yml` 更改 - -![输入图片说明](https://foruda.gitee.com/images/1678979894464784408/0d020c07_1766278.png "屏幕截图") - -> `seata-server.properties` 更改 - -![输入图片说明](https://foruda.gitee.com/images/1678979902433843257/12da2839_1766278.png "屏幕截图") - -### 使用内置 `ruoyi-seata-server` 服务 从这开始 - -执行 `ry-seata.sql` 文件 初始化服务端数据库
-修改 `nacos` 内的 `seata-server.properties` 的数据库地址
-启动 `ruoyi-seata-server` 服务即可 - -### 服务启动顺序说明 - -1. 必须启动基础建设: mysql redis nacos
-2. 可选启动基础建设: minio(影响文件上传) seata(影响分布式事务 默认开启) sentinel(影响熔断限流) monitor(影响监控) snailjob(影响定时任务)
-3. 必须启动应用服务: gateway auth system
-4. 可选启动应用服务: resource(影响资源使用 websocket 文件上传 邮件 短信等) workflow(工作流) gen(代码生成) job(影响定时任务) demo(影响demo使用) diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/power_job_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/power_job_init.md deleted file mode 100644 index 907c7fc7..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/power_job_init.md +++ /dev/null @@ -1,33 +0,0 @@ -# 搭建PowerJob任务调度中心(2.X分支已废弃) -- - - -### 废弃原因 - -接到大量投诉 使用困难 用法诡异 各种问题等 - -### 配置调度中心客户端 -> 查看ruoyi-job配置文件(默认情况下无需做任何更改) -> -![输入图片说明](https://foruda.gitee.com/images/1688013407489024239/9b619e0d_1766278.png "屏幕截图") - -* `enabled` 可启用或关闭客户端注册 -* `server-address` 为调度中心地址 -* `server-name` 为调度中心服务名 -* `app-name` 为执行器组账户名(需在调度中心注册方可登录查看) - -### 启用调度中心 -**需执行 ry-job.sql 默认账号密码 `ruoyi-worker` `123456` 账号在数据库里 可以在页面修改密码** -
- -![输入图片说明](https://foruda.gitee.com/images/1688634898607827011/8853b387_1766278.png "屏幕截图") - -> 在 `ruoyi-visual -> ruoyi-powerjob-server` 启动 -> -![输入图片说明](https://foruda.gitee.com/images/1688013606234848334/cf2028cd_1766278.png "屏幕截图") - -> 需修改配置文件数据库连接地址(**注意: 此处为ruoyi-powerjob-server服务的配置文件**) -> -![输入图片说明](https://foruda.gitee.com/images/1688013663152608235/6c5d6a9c_1766278.png "屏幕截图") - -> 也可配置邮件发送 钉钉推送 和 mongodb存储 -> -![输入图片说明](https://foruda.gitee.com/images/1687335842722317559/f875c07a_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/snail_job_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/snail_job_init.md deleted file mode 100644 index 25c21ebb..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/snail_job_init.md +++ /dev/null @@ -1,38 +0,0 @@ -# 搭建SnailJob任务调度中心(2.2.0新功能) -- - - - -### 视频介绍 - -[Snail job任务调度中心:轻松掌握任务管理、重试机制和任务编排](https://www.bilibili.com/video/BV19i421m7GL/) - -### 配置调度中心客户端 -> 修改主服务配置文件 -> - -![输入图片说明](https://foruda.gitee.com/images/1716175076777941469/db565dc1_1766278.png "屏幕截图") - -* `enabled` 可启用或关闭客户端注册 -* `server.server-name` 为调度中心服务名(自动从Nacos获取服务 支持动态扩容调度中心) -* `server.address` 为调度中心地址(服务名优先 ip垫底) -* `server.port` 为调度中心通信端口 -* `token` 为组通信校验token(可在调度中心组配置更换) -* `group-name` 为执行器组 -* `namespace` 作用域(不同作用域相互隔离请勿填错) - -### 启用调度中心 -**需执行 ruoyi-job.sql 默认账号密码 `admin` `admin` 账号在数据库里 可以在页面修改密码** -
- -![输入图片说明](https://foruda.gitee.com/images/1688634898607827011/8853b387_1766278.png "屏幕截图") - -> 在 `ruoyi-visual -> ruoyi-snailjob-server` 模块启动 -> -![输入图片说明](https://foruda.gitee.com/images/1716175119324078438/ca667a0c_1766278.png "屏幕截图") - -> 需修改配置文件数据库连接地址(**注意: 此处为ruoyi-snailjob-server服务的配置文件 支持多种不同数据库**) -> -![输入图片说明](https://foruda.gitee.com/images/1688013663152608235/6c5d6a9c_1766278.png "屏幕截图") - -### 快速入门 - -[Snailjob快速入门 基本使用介绍](https://juejin.cn/post/7412955032092442675) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/worker_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/worker_init.md deleted file mode 100644 index 121a094d..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/worker_init.md +++ /dev/null @@ -1,52 +0,0 @@ -# 工作流初始化 -- - - - -### 注意事项 - -设置 RabbitMQ 配置 `application-common.yml` 配置文件 (可使用其他例如 kafka、rocketmq 详见 ruoyi-common-bus 模块) - -此功能用于跨服务同步流程与业务状态 MQ安装方式可参考文档扩展功能 - -![输入图片说明](https://foruda.gitee.com/images/1718728432072816698/47eadbb1_1766278.png "屏幕截图") - - -### 工作流使用及配置方式 - -1.找到项目中bpmn文件夹 - -![输入图片说明](https://foruda.gitee.com/images/1714211764058540441/5c8b97af_5363069.png "屏幕截图") - -2.启动项目找到流程定义通过**部署流程文件**将bpmn文件夹下**模型.zip**上传 - -![输入图片说明](https://foruda.gitee.com/images/1714211950485333575/1e2b3ff4_5363069.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1714212113004821592/96586e69_5363069.png "屏幕截图") - -3.导入**模型.zip**后将会出现以下列表,默认使用**leave1**,test_leave为请假申请表名称 - -![输入图片说明](https://foruda.gitee.com/images/1714212222766335759/1227bbd6_5363069.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1714212493602552742/9e0258b1_5363069.png "屏幕截图") - -**此处表名由来与表单源码内编写的表名保持一致方可互相绑定** - -![输入图片说明](https://foruda.gitee.com/images/1716447357161482917/2c9b1639_1766278.png "屏幕截图") - - -4.新增一条请假申请,提交后将会得到如下信息 - -![输入图片说明](https://foruda.gitee.com/images/1714212617432902105/3609f6ef_5363069.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1714212630860787365/2922d38e_5363069.png "屏幕截图") - -5.关于如何切换一个新的流程使用,当前默认使用得KEY为leave1 ,我们切换到leave2使用,我们只需点击绑定业务将表名绑定,重新发起一个新的请假申请就可以得到一个新的流程信息 - -![输入图片说明](https://foruda.gitee.com/images/1714212876442323110/4554ea95_5363069.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1714213037864274694/613149f5_5363069.png "屏幕截图") - -**此处表名由来与表单源码内编写的表名保持一致方可互相绑定** - -![输入图片说明](https://foruda.gitee.com/images/1716447357161482917/2c9b1639_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1714212963457174382/add768db_5363069.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/_sidebar.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/_sidebar.md deleted file mode 100644 index 9fd7aad1..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/_sidebar.md +++ /dev/null @@ -1,64 +0,0 @@ - -- **特别赞助** -- [![输入图片说明](https://foruda.gitee.com/images/1704162419429172656/d0521e59_1766278.png "2024-01-02=>2028-01-02")](http://ccflow.org/?frm=ryPlus) -- [![输入图片说明](https://foruda.gitee.com/images/1705569347386939952/3f187980_1766278.jpeg "2024-01-18=>2025-01-18")](http://www.shuduokeji.com) -- [![输入图片说明](https://foruda.gitee.com/images/1711681233267310022/2ffbcff2_1766278.png "2024-03-29=>2025-03-29")](https://www.jnpfsoft.com/index.html?from=plus-doc) - - -* **简介** - * [项目简介](/ruoyi-vue-plus/home.md) - * [更新日志](/ruoyi-vue-plus/changlog.md) -* **快速开始** - * [项目初始化](/ruoyi-vue-plus/quickstart/init.md) - * [5.X新功能介绍](/ruoyi-vue-plus/quickstart/5.Xnew.md) - * [4.X项目初始化](/ruoyi-vue-plus/quickstart/4.Xinit.md) - * [工作流初始化](/ruoyi-vue-plus/quickstart/worker_init.md) - * [搭建Admin监控](/ruoyi-vue-plus/quickstart/admin_init.md) - * [搭建SnailJob调度中心](/ruoyi-vue-plus/quickstart/snail_job_init.md) - * [(废弃)搭建PowerJob调度中心](/ruoyi-vue-plus/quickstart/power_job_init.md) - * [(废弃)搭建XXLJob调度中心](/ruoyi-vue-plus/quickstart/xxl_job_init.md) - * [idea环境配置](/ruoyi-vue-plus/quickstart/idea_environment.md) - * [应用部署](/ruoyi-vue-plus/quickstart/deploy.md) - * [扩展项目](/ruoyi-vue-plus/quickstart/extend_project.md) -* **框架功能** - * [项目结构](/ruoyi-vue-plus/framework/tree.md) - * [软件架构图](/ruoyi-vue-plus/framework/architecture_diagram.md) - * 框架相关 - * [创建新模块](/ruoyi-vue-plus/framework/association/new_module.md) - * [修改包名](/ruoyi-vue-plus/framework/association/update_package_name.md) - * [接口文档](/ruoyi-vue-plus/framework/association/doc.md) - * [修改应用路径](/ruoyi-vue-plus/framework/association/update_url.md) - * [国际化](/ruoyi-vue-plus/framework/association/i18n.md) - * 基础功能 - * [系统用户相关](/ruoyi-vue-plus/framework/basic/user.md) - * [权限控制](/ruoyi-vue-plus/framework/basic/permissions_control.md) - * [导出功能](/ruoyi-vue-plus/framework/basic/export.md) - * [导入功能](/ruoyi-vue-plus/framework/basic/import.md) - * [参数校验](/ruoyi-vue-plus/framework/basic/param_check.md) - * [代码生成](/ruoyi-vue-plus/framework/basic/code_generate.md) - * [分页功能](/ruoyi-vue-plus/framework/basic/page.md) - * [OSS功能](/ruoyi-vue-plus/framework/basic/oss.md) - * [数据权限](/ruoyi-vue-plus/framework/basic/permissions.md) - * [接口放行](/ruoyi-vue-plus/framework/basic/interface_release.md) - * [多租户功能](/ruoyi-vue-plus/framework/basic/tenant.md) - * [第三方授权功能](/ruoyi-vue-plus/framework/basic/social.md) - * [客户端管理功能](/ruoyi-vue-plus/framework/basic/client.md) - * 扩展功能 - * [多数据源](/ruoyi-vue-plus/framework/extend/dynamic_datasource.md) - * [短信模块](/ruoyi-vue-plus/framework/extend/sms.md) - * [邮件功能](/ruoyi-vue-plus/framework/extend/mail.md) - * [防重幂等](/ruoyi-vue-plus/framework/extend/idempotent.md) - * [数据脱敏](/ruoyi-vue-plus/framework/extend/sensitive.md) - * [API加解密](/ruoyi-vue-plus/framework/extend/api_encrypt.md) - * [数据加解密](/ruoyi-vue-plus/framework/extend/encrypt.md) - * [翻译功能](/ruoyi-vue-plus/framework/extend/translation.md) - * [WebSocket功能](/ruoyi-vue-plus/framework/extend/websocket.md) - * [SSE功能](/ruoyi-vue-plus/framework/extend/sse.md) - * [Skywalking链路监控](/ruoyi-vue-plus/framework/extend/skywalking.md) - * [对接MaxKey单点登录](/ruoyi-vue-plus/framework/extend/maxkey.md) - * [对接TOPIAM单点登录](/ruoyi-vue-plus/framework/extend/topiam.md) - * 功能说明 - * [事务相关](/ruoyi-vue-plus/framework/explain/transaction.md) - * [单元测试](/ruoyi-vue-plus/framework/explain/test.md) - * [主键使用说明](/ruoyi-vue-plus/framework/explain/key.md) - * [关于多表查询](/ruoyi-vue-plus/framework/explain/about_join.md) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/changlog.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/changlog.md deleted file mode 100644 index ac8eb907..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/changlog.md +++ /dev/null @@ -1,2028 +0,0 @@ -# 更新日志 -- - - - -## v5.2.2 - 2024-08-26 - -### 重大改动 - -* 增加 ruoyi-common-sse 模块 支持SSE推送 比ws更轻量更稳定的推送 -* 增加 springboot snailjob 等 actuator 账号密码认证 杜绝内外网信息泄漏问题 -* 增加 重构代码生成器 集成anyline开源框架 支持400+种数据库适配 - -### 依赖升级 - -* update springboot 3.2.6 => 3.2.9 -* update snailjob 1.0.1 => 1.1.2 -* update mapstruct-plus 1.4.3 => 1.4.4 -* update hutool 5.8.27 => 5.8.31 解决hutool不兼容jakarta问题 -* update anyline 8.7.2-20240808 -* update sms4j 3.2.1 => 3.3.2 -* update redisson 3.31.0 => 3.34.1 -* update mapstruct-plus 1.3.6 => 1.4.3 -* update lombok 1.18.32 => 1.18.34 -* update easyexcel 3.3.4 => 4.0.2 -* update springdoc 2.5.0 => 2.6.0 -* update flowable 7.0.0 => 7.0.1 - -### 功能更新 - -* update 优化 去除日志部署环境判断 通过日志级别控制 -* update 优化 忽略租户与忽略数据权限支持嵌套使用(感谢 amadeus5201) -* update 优化 租户相关controller 增加租户开关配置控制是否注册 -* update 优化 移除 alibaba ttl 与线程池搭配有问题(可传递但无法清除与更新) -* update 优化 个人中心编辑 忽略数据权限 -* update 优化 兼容部分用户不想给用户分配角色与部门的场景 -* update 优化 租户套餐重名校验 -* update 优化 部门下存在岗位不允许删除 -* update 优化 角色编辑状态未校验问题 -* update 优化 用户脱敏增加编辑权限标识符 -* update 优化 代码生成器 自动适配oss翻译 -* update 优化 临时升级 undertow 版本 解决虚拟线程溢出问题 -* update 优化 支持通过配置文件关闭工作流 -* update 优化 增加mybatis-plus填充器兜底策略 -* update 优化 TenantSpringCacheManager 处理逻辑 -* update 优化 角色权限判断 -* update 优化 增加删除标志位常量优化查询代码 -* update 优化 监控使用独立web依赖 -* update 优化 更多脱敏策略(感谢 hemengji) -* update 优化 设置nginx sse相关代理参数 -* update 优化 调整默认推送使用SSE -* update 优化 Monitor监控服务通知分类打印(感谢 AprilWind) -* update 优化 限流注解 又写key又不是表达式的情况 -* update 优化 WorkflowUtils查询用户信息发送消息未查询邮件和手机号(感谢 yanzy) -* update 优化 注释掉其他数据库 jdbc 依赖 由用户手动添加 -* update 优化 oracle snailjob 兼容低版本oracle索引名称长度限制 -* update 优化 数据权限支持通过菜单标识符获取数据所有权 -* update 优化 数据权限支持自定义连接符 -* update 优化 TestDemo 删除前校验数据权限 -* update 优化 更换docker镜像底层系统 避免无字体情况 - -### 问题修复 - -* fix 修复 三方登录构建去除无用代码 -* fix 修复 多线程对同一个session发送ws消息报错问题 -* fix 修复 依赖漏洞 限制部分依赖版本 -* fix 修复 excel 基于其他字段 合并错误问题 -* fix 修复 一级缓存key未区分租户问题 -* fix 修复 id字符串格式转换错误问题 -* fix 修复 登出无法正确删除对应的租户数据问题 -* fix 修复 登录错误锁定不区分租户问题 -* fix 修复 转换模型缺少分类字段 -* fix 修复 权限标识符处理未设置成功状态问题 -* fix 修复 无法导入 bpmn 类型文件问题 - -### 前端改动 - -* update element-plus 2.7.5 => 2.7.8 -* update vue 3.4.25 => 3.4.34 -* update vite 5.2.10 => 5.2.12 -* add 增加 使用 vueuse 编写 sse 推送功能 -* update 优化 使用匹配模式简化预编译配置 -* update 优化 时间搜索组件统一 -* update 优化 oss 配置按钮 使用ossConfig权限标识符与oss权限分离 -* update 优化 类型报错问题 -* update 优化 切换租户后刷新首页 -* update 优化 实现表格行选中切换 -* update 优化 使用 vueuse 重构 websocket 实现 -* update 优化 代码生成器编辑页禁用缓存 防止同步后页面不更新问题 -* update 优化 调整默认推送使用SSE -* fix 修复 租户套餐导出路径错误问题 -* fix 修复 登出后重新登录 sse推送报错问题 - - -## v5.2.1 - 2024-07-09 - -### 功能更新 - -* update 优化 更改prod环境 snailjob状态 默认启用 -* update 优化 替换过期方法 -* update 优化 租户列表接口 避免登录之后列表被域名过滤 -* update 优化 获取用户账户方法 LoginHelper#getUsername(感谢 AprilWind) -* update 优化 用户ID查询角色列表代码实现(感谢 AprilWind) -* update 优化 大数据量下join卡顿问题 使用子查询提高性能 -* update 优化 修改路由name命名规则 防止重复路由覆盖问题(感谢 玲娜贝er) -* update 优化 修改 snailjob 默认端口 避免与系统内置端口冲突问题 -* update 优化 isTenantAdmin 空校验 -* update 优化 webscoket 配置与异常拦截 -* update 优化 更新 redis 密码策略(密码必填 升级需注意) -* update 优化 更新使用 Spring 官方推荐 JDK -* update 优化 StreamUtils 抽取 findFirst findAny 方法 -* update 优化 工作流相关代码方法 - -### 问题修复 - -* fix 修复 postgres flowable sql 缺失字段问题 -* fix 修复 新版上传未设置acl问题 -* fix 修复 get路径特殊规则 导致 actuator 泄漏问题 [issue#4f9ceb0a](https://gitee.com/dromara/RuoYi-Vue-Plus/commit/4f9ceb0a8057284a0d9d69da58df630d8bc2e84f) -* fix 修复 pg数据库 用户查询报错问题 -* fix 修复 isLogin 方法抛异常无法正常返回值问题 - -### 前端改动 - -* update 优化 工作流选人改为懒加载窗口 -* update 优化 路由name重复检查 -* update 优化 eslint 语法 -* update 优化 动态创建组件实例时, 设置路由name为组件名 解决缓存问题 -* fix 修复 由于没有await 导致执行顺序不可控 -* fix 修复 富文本编辑器 添加之后内容未清理问题 - -## v5.2.0 - 2024-06-20 - -### 重大改动 - -* 集成 flowable 增加工作流相关功能(感谢 May) -* 集成 snailjob 移除 powerjob(投诉的人太多使用成本太高)(感谢 dhb52) -* 升级 aws s3 升级到 2.X 性能大幅提升 -* 优化 数据权限 数据加密 使用预扫描mapper注解提升代码性能(感谢 老马) -* 新增 caffeine 减少将近90%的redis查询提高性能 - -### 依赖升级 - -* update springboot 3.1.7 => 3.2.6 支持虚拟线程 -* update springboot-admin 3.1.8 => 3.2.3 -* update mybatis-plus 3.5.4 => 3.5.7 适配更改代码 -* update springdoc 2.2.0 => 2.5.0 -* update easyexcel 3.3.3 => 3.3.4 -* update redisson 3.24.3 => 3.31.0 -* update lombok 1.18.30 => 1.18.32 -* update sms4j 2.2.0 => 3.2.1 支持自定义配置key 可用于多厂商多租户等 -* update satoken 1.37.0 -> 1.38.0 -* update hutool 5.8.22 => 5.8.26 -* update mapstruct-plus 1.3.5 => 1.3.6 -* update lock4j 2.2.5 => 2.2.7 -* update dynamic-ds 4.2.0 => 4.3.1 - -### 功能更新 - -* update 优化 三方登录不同域名问题 采用新方案 -* update 优化 获取aop代理的方式 减少与其他使用aop的功能冲突的概率 -* update 优化 token无效时关闭ws连接(感谢 AprilWind) -* update 优化 移除表单构建菜单(没有可用组件 用处不大以后再考虑) -* update 优化 切换动态租户 默认线程内切换(如需全局 手动传参) -* update 优化 代码生成注释,删除无用引入(感谢 AprilWind) -* update 优化 代码生成 el-radio 标签过期属性 -* update 优化 异常处理器自动配置 -* update 优化 文件下载使用对流下载降低内存使用(感谢 PhoenixL) -* update 优化 去除gc日志参数(有需要自己加) -* update 优化 拆分异常处理器 -* update 优化 常规web异常状态码 -* update 优化 设置静态资源路径防止所有请求都可以访问静态资源 -* update 优化 redis 对Long值的存储类型不同问题 -* update 优化 去除加密请求类型限制 -* update 优化 mp多租户插件注入逻辑 -* update 优化 RedisUtils 支持忽略租户 -* update 优化 更新ip地址xdb文件 -* update 优化 验证码背景色改为浅灰色 -* update 优化 mybatis依赖设置为可选依赖 避免出现不应该注入的情况 -* update 优化 GET 方法响应体支持加密 -* update 优化 excel插件合并策略 去除被合并单元格的非首行内容(感谢 司猫子) -* update 优化 下拉选接口数据权限 -* update 优化 OssFactory 获取实例锁性能 -* update 优化 使用翻译注解简化用户查询 调整用户查询逻辑 -* update 优化 框架整体提高查询性能 -* update 优化 将p6spy配置文件统一放置到 common-mybatis 插件包内 - -### 新增功能 - -* add 新增 分布式锁Lock4j异常拦截器 -* add 新增 个人中心-在线设备管理 -* add 新增 岗位编码与部门编码并将岗位调整到部门下(感谢 AprilWind) -* add 新增 BaseMapperPlus提供可选是否抛异常selectVoOne方法(感谢 秋辞未寒) -* add 新增 用户、部门、角色、岗位 下拉选接口与代码实现优化 -* add 增加 StringUtils.isVirtual 方法 -* add 增加 JustAuth 整合 TopIam 单点登录 - -### 问题修复 - -* fix 修复 websocket clientid 参数不走mvc拦截器 无法生效问题 -* fix 修复 oss未使用租户 拼接租户id null问题 -* fix 修复 用户昵称修改后未清除对应缓存问题(感谢 zhuweitung) -* fix 修复 图片预览问题(感谢 AprilWind) -* fix 修复 三方账号可以绑定多平台账号问题 -* fix 修复 主建错别字(感谢 good) -* fix 修复 兼容redis5.0出现的问题 -* fix 修复 部分浏览器无法获取加密响应头问题 -* fix 修复 用户未设置部门 登录报错问题 -* fix 修复 excel 表达式字典 下拉框导出格式错误 -* fix 修复 提升锁的作用域 并采用双重校验锁(感谢 fanc) -* fix 修复 用户登录查询部门缓存无法获取租户id问题 -* fix 修复 关闭租户功能 三方登录报错问题 - - -### 前端改动 - -* update element-plus 2.7.5 -* update vite 5.2.10 -* update vue 3.4.25 -* update vue-router 4.3.2 -* update nodejs 升级到最低 18.18.0 -* update 优化 跟密码相关的默认前端关闭防重功能 -* update 优化 点击左边菜单时页面空白或者刷新整个页面的问题 -* update 优化 el-select 与 el-input 全局样式 -* update 优化 首页打开topNav不展开菜单问题 -* update 优化 支持全局开启或关闭接口加密功能 -* update 优化 密码校验策略增加非法字符限制 -* update 优化 图片上传组件增加压缩功能支持 可自行开关(感谢 fengheguai) -* update 优化 request请求类判断请求头方式 -* update 优化 更改客户端状态接口 使用clientId传参 -* update 优化 ws开关改为常开(vite5修复了崩溃bug) -* fix 修复 移动端下 无法展开菜单问题 -* fix 修复 面板因为min width原因收缩不全 -* fix 修复 文件预览大写后缀不展示的问题(感谢 北桥) -* fix 修复 i18n无感刷新问题 -* fix 修复 websocket 非index页面刷新无法重连问题 - -## v5.1.2 - 2023-12-22 - -### 依赖升级 - -* update springboot 3.1.5 => 3.1.7 -* update mybatis-boot 3.0.2 => 3.0.3 优化依赖传递 -* update powerjob 4.3.3 => 4.3.6 -* update easyexcel 3.3.2 => 3.3.3 -* update transmittable-thread-local 2.14.2 => 2.14.4 -* update justauth 1.16.5 => 1.16.6 -* update redisson 3.24.1 => 3.24.3 修复订阅重启连接超时问题 - -### 功能更新 - -* update 优化 为 admin 模块 单独增加 ratelimiter 模块 -* update 优化 验证码接口 增加限流配置 -* update 优化 excel合并注解会根据第一合并列的结果来决定后续的列合并 (感谢 Simple) -* update 优化 SocialUtils 代码 -* update 优化 删除无用异常类 -* update 优化 补全三方登录校验国际化 -* update 优化 sms组件 预留自动配置类 -* update 更新 关于数据库的说明 -* update 优化 sms组件 预留自动配置类 -* update 优化 将 OSS配置 改为全局模式 降低使用难度 保留sql便于用户自行扩展(常规项目用不上配置分多租户) -* update 优化 细化oss配置管理权限控制 -* update 优化 开启 redisson 脚本缓存 减少网络传输 -* update 优化 删除 hikaricp 官方不推荐使用的配置 jdbc4 协议自带校验方法 -* update 优化 减少 PlusSaTokenDao 不必要的查询优化性能 -* update 优化 更新用户异常提示 使用登录账号 -* update 优化 使用登录用户判断是否登录 提高效率 -* update 优化 重构 LoginHelper 将本地存储代码操作封装 -* update 优化 getTenantId 判断是否开启多租户 -* update 优化 Dockerfile 使用shell模式 支持环境变量传入jvm参数 -* update 优化 WebSocketUtils 连接关闭改为警告 -* update 优化 excel多sheet页导出 (感谢 May) -* update 优化 删除无用接口实现 -* update 优化 jvm参数调整 全面启用zgc -* update 优化 使用动态租户重构业务对租户的逻辑 -* update 优化 TenantHelper 动态租户支持函数式方法 -* update 优化 支持多租户绑定相同的三方登录 -* update 优化 更新用户登录信息方法忽略数据权限 -* update 优化 补全三方绑定时间字段 删除无用excel注解 -* update 优化 将登录记录抽取到监听器统一处理 -* update 优化 租户插件 ignoreTable 方法支持动态租户 - -### 新增功能 - -* add 新增 RedisUtils.setObjectIfExists 如果存在则设置方法 -* add 新增 丰富RedisUtils对List Set类型的操作 -* add 新增 翻译组件 用户昵称翻译实现 -* add 新增 响应加密功能 支持注解强制加密接口数据 (感谢 MichelleChung) - -### 问题修复 - -* fix 修复 selectDictTypeByType 查询方法错误问题 -* fix 修复 一些不正常类无法加载报错问题 -* fix 修复 powerjob sql脚本针对其他数据库转义符问题 (感谢 branches) -* fix 修复 MybatisSystemException 空指针问题 -* fix 修复 excel合并注解会根据第一合并列的结果来决定后续的列合并 -* fix 修复 session 多账号共用覆盖问题 改为 tokenSession 独立存储 -* fix 修复 token 失效后 登录获取用户null问题 -* fix 修复 powerjob部署方案 高版本nginx不生效问题 -* fix 修复 OssFactory 并发多创建实例问题 -* fix 修复 延迟队列在投递消息未到达时间的时候 服务死机导致重启收不到消息 - -### 前端改动 - -* update 优化 用户头像 img 变量无确定类型问题 -* update 优化 细化oss配置管理权限控制 -* update 优化 明确打包命令 -* update 优化 代码中存在的警告 -* update 优化 前端白名单页面放行逻辑 -* update 优化 页面关于权限标识符说明 -* fix 修复 append-to-body 编写错误 (感谢 Ai3_刘小龙) -* fix 关闭动态路由tab页签时不清理组件缓存 (感谢 NickLuo) -* fix 删除重复环境变量ElUploadInstance (感谢 棉花) -* fix 修复 在线用户 强推按钮点击取消控制台警告问题 -* fix 修复 字典使用 default 样式报警告问题 - -## v4.8.2 - 2023-11-27 - -### 依赖升级 - -* update springboot 2.7.17 => 2.7.18 升级到2.X最终版本(官方停更) -* update mybatis-plus 3.5.3.2 => 3.5.4 -* update springboot 2.7.14 => 2.7.17 -* update satoken 1.36.0 => 1.37.0 -* update aws-java-sdk-s3 1.12.400 => 1.12.540 -* update vue-quill 1.1.0 => 1.2.0 - -### 功能更新 - -* update 优化 页面关于权限标识符说明 -* update 优化 数据权限拦截器优先判断方法是否有效 提高性能减少无用sql解析 -* update 优化 部门数据权限使用默认兜底方案 -* update 优化 更改默认日志等级为info 避免日志过多(按需开启debug) -* update 优化 补全代码生成 columnList 接口参数注解缺失 -* update 优化 操作日志 部门信息完善 vue3页面 -* update 优化 AddressUtils 兼容linux系统本地ip -* update 优化 操作日志 部门信息完善 (感谢 柏竹) -* update 优化 数据权限 减少二次校验查询 -* update 优化 vue3 版本用户初始密码从字典查询 -* update 优化 富文本Editor组件检验图片格式 -* update 优化 操作日志列表新增IP地址查询 -* update 优化 全局数据存储用户编号 -* update 优化 菜单管理类型为按钮状态可选 - -### 问题修复 - -* fix 修复 OssFactory 并发多创建实例问题 -* fix 修复 demo的form字段有误 (感谢 dhb52) -* fix 修复 延迟队列在投递消息未到达时间的时候 服务死机导致重启收不到消息 -* fix 修复 数据权限优化后 update delete 报null问题 -* fix 修复 五级路由缓存无效问题 -* fix 修复 oss服务无法连接 导致业务异常问题 查询不应该影响业务 -* fix 修复 内链iframe没有传递参数问题 -* fix 修复 外链带端口出现的异常 -* fix 修复 普通角色编辑使用内置管理员code越权问题 -* fix 修复 代码生成 是否必填与数据库不匹配问题 -* fix 修复 HeaderSearch组件跳转query参数丢失问题 -* fix 修复 树结构代码生成新增方法赋值错误 (感谢 这夏天依然平凡) - -## v5.1.1 - 2023-11-14 - -### 依赖升级 - -* update springboot 3.1.3 => 3.1.5 -* update springboot 2.7.14 => 2.7.17(扩展服务) -* update springboot-admin 3.1.5 => 3.1.7 -* update satoken 1.35.0.RC => 1.37.0 -* update mybatis-plus 3.5.3.2 => 3.5.4 适配mp新版本改动 -* update dynamic-ds 4.1.3 => 4.2.0 -* update bouncycastle 1.72 => 1.76 -* update poi 5.2.3 => 5.2.4 -* update redisson 3.23.2 => 3.24.1 -* update hutool 5.8.20 => 5.8.22 -* update lombok 1.18.26 => 1.18.30(适配支持jdk21) -* update vue-quill 1.1.0 => 1.2.0 - -### 功能更新 - -* update 优化 数据权限拦截器优先判断方法是否有效 提高性能减少无用sql解析 -* update 优化 适配 maxkey 新版本 -* update 优化 @Sensitive脱敏增加角色和权限校验 (感谢 盘古给你一斧) -* update 优化 部门数据权限使用默认兜底方案 -* update 优化 更改默认日志等级为info 避免日志过多(按需开启debug) -* update 优化 登录策略代码优化(感谢 David Wei) -* update 优化 补全代码生成 columnList 接口参数注解缺失 -* update 优化 nginx 配置支持 websocket -* update 优化 notice 新增通知公告发送ws推送 -* update 优化 websocket 模块减少日志输出 增加登录推送 -* update 优化 重构登录策略增加扩展性降低复杂度 -* update 优化 addressUtils 兼容linux系统本地ip -* update 优化 补全操作日志部门数据 -* update 优化 支持数据库操作在非web环境下切换租户 -* update 优化 排除powerjob无用的依赖 减少打包30M体积 -* update 优化 删除 satoken yml 时间配置 此功能已迁移至客户端管理 -* update 优化 redis 集群模式注释说明 -* update 优化 客户端禁用限制 -* update 优化 登录日志, 在线用户展示信息(增加 客户端, 设备类型)(感谢 MichelleChung) -* update 优化 限制框架中的fastjson版本 -* update 优化 数据权限 减少二次校验查询 -* update 优化 将部门id存入token避免过度查询redis -* update 优化 增加租户ID为Null错误日志 -* update 优化 操作日志列表新增IP地址查询 -* update 优化 通过参数键名获取键值接口的返回体(感谢 David Wei) -* update 优化 为 sys_grant_type 字典增加样式 -* update 优化 代码生成 页面输入框样式 -* update 优化 全业务分页查询增加排序规则避免因where条件导致乱序问题 -* update 优化 登录接口租户id被强制校验问题 -* update 优化 加密模块 支持父类统一使用加密注解(感谢 Tyler Ge) -* update 优化 将graalvm镜像更新为openjdk镜像 需要的人自行切换即可 -* update 优化 部分使用者乱设权限导致无法获取用户信息 增加权限提示 -* update 优化 表格列的显示与隐藏小组件(感谢 bestrevens) -* update 优化 增加表单构建不能使用说明 -* update 优化 富文本Editor组件检验图片格式 -* update 优化 操作日志列表新增IP地址查询 -* update 优化 菜单管理类型为按钮状态可选 -* update 优化 用户初始密码从参数配置查询 -* update 优化 通过参数键名获取键值接口的返回体(感谢 David Wei) -* update 优化 字典标签支持数组和多标签(感谢 抓蛙师) - -### 新增功能 - -* add 新增 websocket 群发功能 -* add 新增 前端接入websocket接收消息(感谢 三个三) - -### 问题修复 - -* fix 修复 oss服务无法连接 导致业务异常问题 查询不应该影响业务 -* fix 修复 租户id为null 无法匹配字符串导致的嵌套key问题 -* fix 修复 部门管理orderNum排序失效问题 -* fix 修复 外链带端口出现的异常 -* fix 修复 普通角色编辑使用内置管理员code越权问题 -* fix 修复 代码生成 是否必填与数据库不匹配问题 -* fix 修复 用户注册接口校验用户名不区分租户问题 -* fix 修复 错误增加组导致的校验不生效问题 -* fix 修复 新增校验主键id问题 -* fix 修复 powerjob 使用 nginx 部署无法访问的问题 -* fix 修复 SysUserMapper 内标签使用错误(不影响使用) -* fix 修复 新增或编辑 SysOssConfig 数据后 推送到 redis 数据不完整 -* fix 修复 树表生成查询变量使用错误 -* fix 修复 个人信息修改密码接口隐藏新旧密码参数明文(感谢 bleachtred) -* fix 修复 删除字段后 * update sql 未更新问题 -* fix 修复 三方登录支付宝source与实际支付宝业务code不匹配问题 -* fix 修复 五级路由缓存无效问题 -* fix 修复 内链iframe没有传递参数问题 -* fix 修复 绑定第三方帐号参数“wechar”更正为“wechat” (感谢 scmiot) -* fix 修复 用户注册缺失 clientid 问题 -* fix 修复 HeaderSearch组件跳转query参数丢失问题 -* fix 修复 自定义字典样式不生效的问题 -* fix 修复 login 页面 loading 未关闭问题 - -## v4.8.1 - 2023-09-25 - -### 依赖升级 - -* update springboot 2.7.15 => 2.7.16 -* update springboot-admin 2.7.10 => 2.7.11 -* update satoken 1.35.0.RC => 1.36.0 -* update lombok 1.18.26 =. 1.18.30 -* update mybatis-plus 3.5.3.1 => 3.5.3.2 -* update easyexcel 3.3.1 => 3.3.2 -* update hutool 5.8.18 => 5.8.20 - -### 功能更新 - -* update 优化 重置密码注释参数中文解释错误 -* update 优化 getTokenActivityTimeout => getTokenActiveTimeout -* update 优化字典标签支持传分隔符分隔的字符串和数组,优化渲染效果 -* update 优化 控制台debuger位置错误问题 -* update 优化 TopNav 菜单样式 -* update 优化 全局异常处理器 业务异常不输出具体堆栈信息 减少无用日志存储 -* update 优化 用户管理 只查询未禁用的部门角色岗位数据 -* update 优化 岗位如果绑定了用户则不允许禁用 -* update 优化 部门与角色如果绑定了用户则不允许禁用 -* update 优化 加密实现 使用 EncryptUtils 统一处理 -* update 优化 excel导出字典转下拉框 无需标记index自动处理 -* update 优化 excel 导出字典默认转为下拉框 -* update 优化 删除一些跟 swagger 有关的字眼 避免误解 -* update 优化 角色权限支持仅本人权限查看 解决无法查看自己创建的角色问题 -* update 优化 RedisCacheController 注释错误 -* update 优化 xxljob 端口随着主应用端口飘逸 避免集群冲突 -* update 优化 powerjob 端口随着主应用端口飘逸 避免集群冲突 - -### 问题修复 - -* fix 修复 代码生成后 vo 定义 'serialVersionUID' 字段的不可序列化类 -* fix 修复 自定义字典样式不生效的问题 -* fix 修复 布局配置失效问题 -* fix 修复 新建用户可能会存在的越权行为 -* fix 修复 字典缓存删除方法参数错误问题 -* fix 修复 修复树模板父级编码变量错误 -* fix 修复 有界队列与优先队列 错误使用问题 -* fix 修复 升级 mp 版本导致的问题 -* fix 修复 vue3 版本注册页验证码不显示问题 -* fix 修复 加密模块数据转换异常问题 -* fix 修复 动态设置 token 有效期不生效问题 -* fix 修复 token 过期登出无法清理在线用户问题 - - -## v5.1.0 - 2023-09-05 - -# 开发历程 - -* 2023年5月 开始 5.1.0 计划 历经1个月的设计与讨论 -* 2023年6月 开始着手开发 历经2个多月的开发 特别感谢团队的小伙伴与一些热心的粉丝 参与功能开发与测试 -* 2023年8月 开始公测 历经将近1个月的公测与修复工作(期间成功支持多位使用者生产使用) -* 2023年9月初 正式发布(经过多个小伙伴的生产实践 已基本可尝试生产使用) -> 关于4.X的说明 由于SpringBoot2.X与vue2.X均在11月底停止维护
-> 故而咱们vue版本4.X也无法再继续更新
-> 介于4.X的用户量特别庞大 功能也非常的稳定
-> 计划于11月底同Boot2.X一同停止更新但还会持续维护修复bug(修复的形式为直接提交到4.X分支停止发版)
- -# 视频介绍 - -为了更好的让大家了解 5.1.0 作者录制了相关的视频 供大家快速了解上手 - -* 5.1.0 新功能与变更介绍: https://www.bilibili.com/video/BV1fj411y71X/ -* 搭建与运行: https://www.bilibili.com/video/BV1Fg4y137JK/ -* 生产环境搭建部署: https://www.bilibili.com/video/BV1mL411e7ha/ - -# 更新日志 - -### 重大更新 - -* [重大更新] 优化 相关代码 完成代码生成多数据源统一存储(感谢 WangBQ !pr349) -* [不兼容更新] 移除 原短信功能 集成更强大的 sms4j 短信工具包(感谢 友杰 !pr367) -* [不兼容更新] 对接 powerjob 实现分布式任务调度 删除原有 xxljob 原因为社区不更新功能太少只支持mysql(感谢 yhan219 !pr359) -* [重大更新] 新增 三方授权绑定登录功能 基于 justauth 支持市面上大部分三方登录(感谢 三个三 !pr370) -* [不兼容更新] 新增 客户端授权功能 不需要更改任何代码即可完成多端动态对接(感谢 Michelle.Chung !pr379) -* [重大更新] 新增 前后端接口请求加密传输 基于AES+RSA动态高强度加密(感谢 wdhcr !pr377) -* [重大更新] 新增 三方授权登录 对接 maxkey 单点登录 -* [不兼容更新] 优化 redis序列化配置 更改为通用格式(升级需清除redis所有数据) - -### 依赖升级 - -* update springboot 3.0.7 => 3.1.3 -* update springboot-admin 3.1.3 => 3.1.5 -* update springdoc 2.1.0 => 2.2.0 -* update spring-mybatis 3.0.1 => 3.0.2 -* update mybatis-plus 3.5.3.1 => 3.5.3.2 -* update easyexcel 3.2.1 => 3.3.2 -* update mapstruct-plus 1.2.3 => 1.3.5 解决修改实体类 idea不编译问题 -* update satoken 1.34.0 => 1.35.0.RC 优化过期配置 支持多端token自定义有效期 -* update dynamic-ds 3.6.1 => 4.1.3 支持 SpringBoot3 -* update sms4j 2.2.0 -* update hutool 5.8.18 => 5.8.20 -* update redisson 3.20.1 => 3.23.4 -* update lock4j 2.2.4 => 2.2.5 -* update aws-java-sdk-s3 1.12.400 => 1.12.540 -* update maven-surefire-plugin 3.0.0 => 3.1.2 - -### 功能更新 - -* update 优化 excel 导出合并 在初始化类时进行数据的处理 -* update 优化 简化 flatten 插件语法写法 -* update 优化 支持本地虚拟域名调试(感谢 代星登 !pr363) -* update 重构 将框架内的 swagger 命名更改为 springdoc 命名避免误解 -* update 重构 将系统内置配置放置到 common 包内独立加载 不允许用户随意修改 -* update 优化 切换 maven 仓库到 华为云(aliyun依赖不更新拉取不到) -* update 优化 升级 satoken 支持多端 token 自定义有效期功能 -* update 优化 RepeatSubmitAspect 逻辑避免并发请求问题 -* update 优化 在全局异常拦截器中增加两类异常处理 -* update 优化 提供powerjob完整sql脚本 降低用户使用难度 -* update 优化 StreamUtils 其他方法过滤null值(感谢 bleachtred !pr390) -* update 优化 powerjob 端口随着主应用端口飘逸 避免集群冲突 -* update 优化 角色权限支持仅本人权限查看 解决无法查看自己创建的角色问题 -* update 修改代码生成模版,日期范围统一采用addDateRange方法(感谢 LiuHao !pr397) -* update 优化 树表生成前端缺少 children 字段 -* update 优化 CryptoFilter null判断工具 -* update 优化 websocket 路径与 cloud 版本保持一致 -* update 优化 更新登录策略返回值(感谢 zlyx) -* update 修改代码生成模板,调整列表打开对话框和接口请求顺序 -* update 优化 SaInterceptor 拦截器判断 token 客户端id是否有效(感谢 zlyx !pr402) -* update 优化 excel 导出字典默认转为下拉框 -* update 优化 兼容 clientid 通过 param 传输 -* update 优化 excel导出字典转下拉框 无需标记index自动处理(感谢 一夏coco) -* update 优化 简化线程池配置 -* update 优化 屏蔽 powerjob 无用的心跳日志 -* update 优化 适配 mysql 8.0.34 升级连接机制 -* update 优化 加密实现 使用 EncryptUtils 统一处理 -* update 优化 删除字典无用状态字段(基本用不上 禁用后还会导致回显问题) -* update 优化 部门与角色如果绑定了用户则不允许禁用 -* update 优化 岗位如果绑定了用户则不允许禁用 -* update 优化 用户管理 只查询未禁用的部门角色岗位数据 -* update 优化 登录用户增加昵称返回 -* update 优化 将部门管理 负责人选项改为下拉框选择(感谢 Lionel !pr410) -* update 优化 全局异常处理器 业务异常不输出具体堆栈信息 减少无用日志存储 -* update 优化 登录用户缓存 去除冗余统一存储 -* update 优化 放宽菜单权限 角色关联菜单无需管理员 - -### 新增功能 - -* add 增加 RedisUtils 批量删除 hash key 方法 -* add 新增 Oss 上传 File 文件方法(感谢 jenn !pr362) -* add 增加 excel 导出下拉框功能 -* add 新增 RedisUtils.setObjectIfAbsent 如果不存在则设置方法 - -### 修复问题 - -* fix 修复 脱敏注解标记位置错误 -* fix 修复 OssClient 实例多租户相同key缓存覆盖问题 -* fix 修复 关闭多租户 脱敏判断问题 -* fix 修复 OssClient 切换服务 实例不正确问题(感谢 jenn !pr360) -* fix 修复 传参类型不正确导致 postgreSql 同步套餐报错问题 -* fix 修复 参数类型修改 未修改校验注解 -* fix 修复 登录校验错误次数未达到上限时 错误次数缓存未设置有效时间问题(感谢 konbai !pr366) -* fix 修复 common-core 包使用aop注解 但未添加aop实现类导致单独使用报错问题 -* fix 修复 Mapper 多参数未加 @Param 注解问题 -* fix 修复 邮箱登录 查询值错误问题 -* fix 修复 用户篡改管理员角色标识符越权问题 -* fix 修复 字典缓存注解使用错误问题 -* fix 修复 查询部门下拉树未过滤数据权限问题 -* fix 修复 CacheName 缓存key存储错误问题 -* fix 修复 代码生成 前端添加或修改表单修改列生成问题 -* fix 修复 新增角色使用内置管理员标识符问题 -* fix 修复 代码生成 前端添加或修改表单修改列生成问题 -* fix 修复 token 过期登出无法清理在线用户问题 -* fix 修复 加密模块数据转换异常问题 -* fix 修复 可能导致异常类无法反序列化问题 -* fix 修复 代码生成 编辑按钮刷新列表问题 -* fix 修复 客户端编辑时授权类型变更未保存的问题(感谢 David Wei !pr400) -* fix 修复 有界队列与优先队列 错误使用问题 -* fix 修复 修复树模板父级编码变量错误 -* fix 修复 部署部分系统出现乱码问题 -* fix 修复 一级菜单无法显示问题 -* fix 修复 可能会存在的越权行为(感谢 丶Stone !pr416) -* fix 修复 代码生成页面参数缺少逗号问题 - -### 移除功能 - -* remove 移除原有短信功能(建议使用sms4j) -* remove 移除xxljob功能(建议使用powerjob) - - -## v4.8.0 - 2023-07-10 - -### 重大更新 - -* [重大更新] 新增 sms4j 短信融合框架整合(支持数十种短信厂商接入、发送限制、负载均衡等功能) -* [不兼容更新] 移除 原短信功能(建议使用新 sms4j 功能) -* [重要迁移] 迁移 vue3 前端到主仓库统一维护 - -### 依赖升级 - -* update springboot 2.7.11 => 2.7.13 -* update satoken 1.34.0 => 1.35.0.RC -* update easyexcel 3.2.1 => 3.3.1 -* update sms4j 2.2.0 - -### 功能更新 - -* update 优化 StreamUtils 方法过滤null值 -* update 优化 页签在Firefox浏览器被遮挡 -* update 优化 在全局异常拦截器中增加两类异常处理 -* update 优化 下载zip方法增加遮罩层(感谢@梁剑锋) -* update 优化 用户昵称非空校验 -* update 优化 修改角色如果未绑定用户则无需清理 -* update 优化 RepeatSubmitAspect 逻辑避免并发请求问题 -* update 优化 satoken 过期配置 支持多端token自定义有效期 -* update 优化 加密注解注释错误 -* update 优化 切换 maven 仓库到华为云(aliyun 不可用) -* update 优化 excel 导出存在合并项时在初始化类时进行数据的处理避免多次调用(感谢@yueye) -* update 优化 重构 CellMergeStrategy 支持多级表头修复一些小问题 整理代码结构 - -### 新增功能 - -* add 新增 RedisUtils.setObjectIfAbsent 不存在则设置方法 -* add 新增 Excel 导出附带有下拉框(字典自动导出为下拉框) 可自定义多级下拉框(感谢@Emil.Zhang) -* add 新增 OssClient File 文件上传方法 -* add 增加 RedisUtils 批量删除 hash key 方法 - -### 问题修复 - -* fix 修复 新增角色使用内置管理员标识符问题 -* fix 修复 缓存监控图表 支持跟随屏幕大小自适应调整(感谢@抓蛙师) -* fix 修复 防重组件 错删注解问题 -* fix 修复 CacheName 缓存key存储错误问题 -* fix 修复 字典缓存注解使用错误问题 -* fix 修复 用户篡改管理员角色标识符越权问题 -* fix 修复 登录校验错误次数未达到上限时 错误次数缓存未设置有效时间问题 -* fix 修复 OssClient 切换服务 实例不正确问题 -* fix 修复 element ui 因版本而未被工具识别问题(感谢@梁剑锋) -* fix 修复 admin监控 切换tab页需要重复登录问题 - -## v5.0.0 - 2023-05-19 - -# 开发历程 - -* 2022年11月 开始5.X计划 历经2个月的设计与讨论 -* 2023年1月 开始着手开发 历经3个月的开发 特别感谢团队的小伙伴与一些热心的粉丝 参与功能开发与测试 -* 2023年4月 开始公测 历经将近2个月的公测与修复工作(期间成功支持多位使用者生产使用) -* 2023年5月底 正式发布 虽然已经有生产实践 但是springboot3.0与jdk17使用者还处于少数 另外5.X后续还有一些不兼容更新 求稳者建议在等一等 -* 关于4.X的说明 由于springboot2.X 与 vue2.X 匀在年底停止维护 故此4.X也将于年底同boot2一同停止维护 - -# 视频介绍 - -为了更好的让大家了解 5.X 作者录制了相关的视频 供大家快速了解上手 - -* 搭建与运行: https://www.bilibili.com/video/BV1Fg4y137JK/ -* 新功能与变更介绍: https://www.bilibili.com/video/BV1Us4y1m7ky/ -* 生产环境搭建部署: https://www.bilibili.com/video/BV1mL411e7ha/ - -# 更新日志 - -### 重大更新 - -* [不兼容升级] java 版本从 jdk 8 升级到 jdk 17 且需要使用 graalvm 运行(暂时未解决原生jdk存在的问题) -* [不兼容升级] springboot 升级 3.0 版本 -* [不兼容升级] 重构 项目模块结构 采用插件化结构 易扩展易解耦 -* [不兼容升级] com.sun.mail 更改为 jakarta.mail 修改最新写法 -* [不兼容升级] javax.servlet 替换为 jakarta.servlet 更新所有代码 -* [简化性升级] 默认开启复杂结构 resultMap 自动映射 简化xml编码(多结构实体需带上主键id) -* [数据库改动] 更新 create_by update_by 字段类型 (保存用户id) -* [数据库改动] 新增 create_dept 字段 (保存创建部门id) -* [不兼容更新] system 模块 所有实体类均使用 bo|vo 规范化 -* [重大更新] 新增 多租户功能设计 整体框架代码结构与数据库更改 -* [重大更新] 新增 mapstruct-plus 替换 BeanUtil 与 BeanCopyUtils 工具 -* [不兼容更新] 重构 登录注解接口与cloud版本统一接口路径 -* [不兼容更新] 重构 BaseMapperPlus接口 去除 `@param Mapper` 泛型 -* [不兼容更新] 移除 vue2 前端工程 全面启用 vue3 -* [重大更新] 新增 vue3 + TS 版本前端(独立仓库后续与Cloud版本共用) -* [重大更新] 增加 websocket 模块 支持token鉴权 支持分布式集群消息同步 -* [重大更新] 框架文档全面翻新 https://plus-doc.dromara.org - -### 依赖升级 - -* update java 1.8 => 17 -* update springboot 2.7.7 => 3.0.7 -* update springboot-admin 2.7.10 => 3.0.4 -* update springdoc 1.6.14 => 2.1.0 -* update lock4j 2.2.3 => 2.2.4 -* update dynamic-ds 3.5.2 => 3.6.1 -* update easyexcel 3.1.5 => 3.2.1 -* update hutool 5.8.11 => 5.8.18 -* update redisson 3.19.2 => 3.20.1 -* update lombok 1.18.24 => 1.18.26 -* update spring-boot.mybatis 2.2.2 => 3.0.1 -* update mapstruct-plus 1.2.3 -* update maven-compiler-plugin 3.10.1 => 3.11.0 -* update maven-surefire-plugin 3.0.0-M7 => 3.0.0 -* update docker mysql 8.0.31 => 8.0.33 -* update docker nginx 1.22.1 => 1.32.4 -* update docker redis 6.2.7 => 6.2.12 -* update docker minio RELEASE.2023-04-13T03-08-07Z - -### 功能更新 - -* update 适配 AsyncConfig 替换过期继承类改为实现 AsyncConfigurer 接口 -* update 适配 redis 新版本配置文件写法 -* update 适配 获取redis 监控参数接口 替换过期语法 -* update 适配 sa-token 替换新依赖 sa-token-spring-boot3-starter -* update 适配 springboot-admin 改为最新 spring-security 写法 -* update 适配 springdoc 新版本配置方式 -* update 适配 ServletUtils 更换继承 JakartaServletUtil -* update 适配 新序列化注解 -* update 优化 利用 resultMap 自动映射配置 简化 xml (非嵌套) -* update 优化 调整 system entity 实体与 controller 包结构 -* update 优化 实体类中校验注解的提示信息 -* update 优化 使用 jdk17 语法优化代码 -* update 优化 所有 properties 文件改为注解启用 -* update 更新 docker 基础镜像 graalvm java17 -* update 优化 用户头像 改为存储 ossId 使用转换模块转为 url 展示 -* update 优化 重构 CellMergeStrategy 支持多级表头修复一些小问题 整理代码结构 -* update 优化 登录流程代码注释 - -### 新增功能 - -* add 新增 flatten-maven-plugin 插件统一版本号管理 -* add 新增 ip2region 实现离线IP地址定位库 - -### 移除功能 - -* remove 移除 BeanCopyUtils 工具类 与 JDK17 不兼容 -* remove 移除 devtools 依赖 并不好用(建议直接用idea自带的热更) -* remove 移除 vue2 前端工程 统一使用 vue3 工程 - -## v4.7.0 - 2023-05-08 - -### 依赖升级 - -* update springboot 2.7.9 => 2.7.11 修复 DoS 漏洞 -* update xxljob 2.3.1 => 2.4.0 -* update minio 升级至最新版 避免低版本信息泄漏问题 -* update hutool 5.8.15 => 5.8.18 -* update redisson 3.20.0 => 3.20.1 - -### 功能更新 - -* update 优化 更改 sys_oss_config 表注释 避免误解 -* update 项目正式入驻 dromara 开源社区 更改项目地址 -* update 全新 logo 全新背景图(设计师打造) -* update 优化代码生成 同步操作使用批量处理 -* update 重写项目 readme 说明 -* update 修改controller中校验直接返回R.fail -* update 更换默认用户头像 -* update 优化 限流注解 key 支持简单 spel 表达式 -* update 优化弹窗后导航栏偏移的问题 -* update 优化$tab.closePage后存在非首页页签时不应该跳转首页 -* update delete build style -* update 优化选择图标组件 -* update 移除vue-multiselect样式 -* update 优化固定头部页签滚动条被隐藏的问题 -* update 按代码规范补全重写注解 -* update 优化 极端情况获取LoginUser可能为null问题 -* update 优化 更改系统所有服务日志配置文件命名为 logback-plus.xml 避免与其他框架默认配置冲突 -* update 优化 加解密模块 将null判断下推防止任何可能的null出现 -* update 优化 调整配置文件错误注释 -* update 优化 在线用户token获取方式 -* update 优化 用户更改角色 踢掉角色相关所有在线用户 -* update 优化 下拉图标选择组件优化:1.已选择图标高亮回显 2.滚动条采用el-scrollbar -* update 优化 Vue的DictTag组件 当value没有匹配的值时 展示空value -* update 优化 恢复翻页/切换路由滚动功能 - -### 新增功能 - -* add 新增 ip2region 实现离线IP地址定位库 -* add 增加 邮箱验证码发送接口 -* add 增加 邮箱登陆接口 -* add 增加 EncryptUtils 加解密安全工具类 可以处理base64,aes,sm4,sm2,rsa,md5,sha256加解密 -* add 增加 EncryptUtils 类中增加国密sm3的不可逆加密算法 -* add 新增 忽略数据权限写法 防止异常不执行关闭问题 - -### 问题修复 - -* fix 修复 代码生成 点选按钮不生效问题 -* fix 修复 用户密码更新无效问题 -* fix 修复 findInSet 在mysql下方法搜索非数字字段时 无引号报错问题 -* fix 修复 oracle postgres 数据库日志表索引创建错误 -* fix 角色列表关联多表sort值都一样 导致排序不稳定、临时表没有原来的主键顺序 -* fix 修复 DefaultExcelResult 单词拼写错误 -* fix 修复页面切换时布局错乱的问题 -* fix 修复tab栏“关闭其他”异常的问题 -* fix 修复 加解密拦截器 对象属性为null问题 -* fix 修复 取消oss预览状态修改 图标变化不正常问题 -* fix 修复 开启TopNav后一级菜单路由参数设置无效问题 -* fix 修复 路由跳转被阻止时vue-router内部产生报错信息问题 -* fix 修复 缓存列表:多次清除操作,提示不变的问题 - -## v4.6.0 - 2023-03-13 - -### 重大更新 - -[重大更新] add 新增 基于 Mybatis 实现数据库字段加解密功能 -[重大更新] add 新增 通用翻译注解及实现(部门名、字典、oss、用户名) - -### 依赖升级 - -* update springboot 2.7.7 => 2.7.9 -* update easyexcel 3.1.5 => 3.2.1 -* update redisson 3.19.1 => 3.20.0 -* update hutool 5.8.11 => 5.8.15 (13与14有问题勿使用) -* update springdoc 1.6.14 => 1.6.15 -* update aws-java-sdk-s3 1.12.373 => 1.12.400 -* update element-ui 2.15.10 => 2.15.12 -* update lombok 1.18.24 => 1.18.26 - -### 功能更新 - -* update 优化 实体类中校验注解的提示信息 -* update 优化 修改 oss 配置页面开关说明 避免造成误解 -* update 优化 框架代码书写格式 -* update 优化 调整连接池默认参数 -* update 优化 `DictDataMapper` 注解标注过期 推荐使用 `@Translation` 注解 -* update 优化 部门更新接口 清理缓存 -* update 优化 获取菜单数据权限接口 删除无用角色属性与逻辑 -* update 优化 调整连接池最长生命周期 防止出现警告 -* update 优化 连接池增加 `keepaliveTime` 探活参数 -* update 优化 `DataPermissionHelper` 增加 `开启/关闭` 忽略数据权限功能 -* update 重构 `OssFactory` 加载方式 改为每次比对配置做实例更新 -* update 优化 `SaToken` 自定义扩展类 改为配置类注入 便于扩展 -* update 优化 启用 `sqlserver` 高版本语法 简化sql脚本语法 -* update 优化 更新角色后踢掉所有相关的登录用户 用户量过大会导致redis阻塞卡顿(应粉丝要求) -* update 优化 翻译组件 支持返回值泛型 支持多种类型数据翻译(例如: 根据主键翻译成对象) -* update 优化 限流注解使用 `SpringEl` 表达式动态定义 Key 与 message 国际化支持 -* update 优化 限流功能 `redis key` 生成规则 以 `功能头+url+ip+key` 格式 -* update 优化 只拦截系统内存在的路径 减少不必要的拦截造成的性能消耗 -* update 优化 `tagsView` 右选框,首页不应该存在关闭左侧选项 -* update 优化 `copyright 2023` -* update 优化 监控页面图标显示 -* update 优化 日志注解支持排除指定的请求参数 -* update 优化 业务校验优化代码 -* update 优化 日志管理使用索引提升查询性能 -* update 优化 框架时间检索使用时间默认值 `00:00:00 - 23:59:59` -* update 优化 oss 预览使用 `ImagePreview` 组件 - - -### 新增功能 - -* add 新增 `BeanCopyUtils#mapToMap` 方法 -* add 新增 `StringUtils` `splitTo` 与 `splitList` 方法 优化业务代码 -* add 新增 `EasyExcel` `@ExcelEnumFormat` 枚举类数据翻译注解 - - -### 问题修复 - -* fix 修复 新版本 `Redisson` 存在与 `springboot 2.X` 的兼容性问题 -* fix 修复 vue3 模板点击删除按钮后弹框显示`[object Object]`或控制台报错的问题 -* fix 修复 接口问题开关不生效问题 -* fix 修复 前端优化文件下载出现的异常 -* fix 修复 修改密码日志存储明文问题 -* fix 修复 用户密码注解误删暴露问题 -* fix 修复 代码生成 使用 `postgreSQL` 数据库查出已删除的字段 - - -## v4.5.0 - 2023-01-12 - -### 重大更新 - -* [重大更新] 使用 spring 事件发布机制 重构登录日志与操作日志 支持多事件监听无入侵扩展 -* 例如: 可以增加一个监听者将日志上传至ES等存储 对原有逻辑无影响 - -### 依赖升级 - -* update springboot 2.7.6 => 2.7.7 -* update springboot-admin 2.7.7 => 2.7.10 -* update mybatis-plus 3.5.2 => 3.5.3.1 -* update redisson 3.18.0 => 3.19.1 -* update sa-token 1.33.0 => 1.34.0 -* update easyexcel 3.1.3 => 3.1.5 -* update springdoc 1.6.13 => 1.6.14 -* update snakeyaml 1.32 => 1.33 -* update hutool 5.8.10 => 5.8.11 -* update aws-s3 1.12.349 => 1.12.373 -* update aliyun-sms 2.0.22 => 2.0.23 -* update tencent-sms 3.1.635 => 3.1.660 -* update echarts 4.9.0 => 5.4.0 -* update vue3 element-plus 2.2.21 => 2.2.27 - -### 功能更新 - -* update 优化 BaseMapperPlus 使用 MP V3.5.3 新工具类 Db 简化批处理操作实现 -* update 优化 将环境配置放到 pom 文件上方 便于查看使用 -* update 优化 代码生成与框架主体使用相同的主键生成器 全局统一避免问题 -* update 优化 系统登录 使用单表查询校验用户 避免多次 join 查询 -* update 优化 删除 vue3 模板无用参数 -* update 优化 xss 包装器 变量命名错误 -* update 优化 重构 ExcelUtil 全导出方法支持 OutputStream 流导出 不局限于 response -* update 优化 maven 地址切换回 aliyun 仓库 -* update 优化 去除无用 guava 依赖管理 项目中已无此依赖 -* update 优化 springdoc 配置鉴权头写死问题 增加持久化鉴权头配置 -* update 优化 验证码结果使用 spel 引擎自动计算 -* update 优化 弹窗内容过多展示不全问题 -* update 优化 删除 fuse 无效选项 maxPatternLength -* update 优化 minio 安装警告 使用新版本参数 -* update 优化 使用 spring 事件机制 重构 OssConfig 缓存更新 -* update 优化 抽取 SysLoginService recordLogininfor 记录登录信息方法 简化日志记录 -* update 优化 使用 spring 事件发布机制 重构登录日志与操作日志 -* update 优化 单元格合并判断 cellValue 是否相等方法调整 -* update 优化 去除 RedisConfig 无用继承 - -### 新增功能 - -* add 增加 GET 请求提交日期参数 默认格式化配置 -* add 增加 RedisUtils 检查缓存对象是否存在方法 - -### 问题修复 - -* fix 修复 根据 key 更新参数配置报null问题 -* fix 修复 树形下拉不能默认选中 -* fix 修复 读取 generator.yml 中文乱码问题 -* fix 修复 代码生成图片/文件/单选时选择必填无法校验问题 -* fix 修复 修改参数键名时 未移除过期缓存配置 -* fix 修复 用户注册 用户类型字段书写错误 -* fix 修复 文件名包含特殊字符(+、-、*...)的文件无法下载问题 -* fix 修复 短信校验模板参数传参错误 -* fix 修复 vue3 closeSidebar 这个方法定义的参数没有解构问题 - -## v4.4.0 - 2022-11-28 - -### 重大更新 -* [重大更新] 优化支持 oss 私有库功能(数据库字段改动) #cd9c3c3f -* [重大更新] 连接池由 druid 修改为 hikari 更新相关配置(原因可看文档) #1f42bd3d -* [重大更新] 移除 tlog(不支持UI界面 使用的人太少) 建议使用 skywalking -* [重大更新] 增加 skywalking 集成 默认注释不开启(使用看文档) - -### 依赖升级 -* update springboot 2.7.5 => 2.7.6 -* update springboot-admin 2.7.6 => 2.7.7 -* update satoken 1.31.0 => 1.33.0 -* update spring-doc 1.6.12 => 1.6.13 -* update easyexcel 3.1.1 => 3.1.3 -* update hutool 5.8.8 => 5.8.10 -* update redisson 3.17.7 => 3.18.0 -* update lock4j 2.2.2 => 2.2.3 -* update s3-adk 1.12.324 => 1.12.349 -* update mysql-docker 8.0.29 => 8.0.31 - -### 功能更新 -* update 优化 oss 云厂商增加 华为obs关键字 -* update 优化 冗余的三元表达式 -* update 优化 重置时取消部门选中 -* update 优化 新增返回警告消息提示 -* update 优化 hikari 参数顺序 最常用的放上面 删除无用 druid 监控页面 -* update 优化 p6spy 排除健康检查 sql 执行记录 -* update 优化 Dockerfile 创建目录命令 -* update 优化 将空‘catch’块形参重命名为‘ignored’ -* update 优化 使用本地缓存优化 excel 导出 数据量大字典转换慢问题 -* update 优化 字典转换实现 去除字符串查找拼接优化效率 -* update 优化 减小腾讯短信引入jar包的体积 -* update 消除Vue3控制台出现的警告信息 -* update 忽略不必要的属性数据返回 -* update 替换 mysql-jdbc 最新坐标 - -### 新增功能 -* add 新增 junit5 单元测试案例 #6e8ef308 -* add 增加 sys_oss_config access_policy 桶权限类型字段 -* add 增加 4.3-4.4 更新 sql 文件 -* add 新增 字典数据映射注解 #da94e898 -* add 增加 RedisUtils 获取缓存Map的key列表 - -### 问题修复 -* fix 修复 上传png透明图片 生成头像透明部分变成黑色 -* fix 修复 sqlserver sql文件 重复主键数据问题 -* fix 修复 sqlserver 特定情况下报 ssl 证书问题 默认关闭 ssl 认证 -* fix 修复 table中更多按钮切换主题色未生效修复问题 -* fix 修复 菜单激活无法修改其填充颜色 去除某些svg图标的fill="#bfbfbf"属性 -* fix 修复 使用缓冲流 导致上传异常问题 -* fix 修复 过滤器链使用IoUtil.read方法导致request流关闭 -* fix 修复 Log注解GET请求记录不到参数问题 -* fix 修复 某些特性的环境生成代码变乱码TXT文件问题 -* fix 修复 开启TopNav没有子菜单隐藏侧边栏 -* fix 修复 回显数据字典数组异常问题 - -### 移除功能 -* remove 移除过期 Anonymous 注解与其实现代码 -* remove 移除 tlog(不支持UI界面 使用的人太少) 建议使用 skywalking - -## v4.3.1 - 2022-10-24 - -### 依赖升级 -* update springboot 2.7.3 => 2.7.5 -* update springboot-admin 2.7.4 => 2.7.6 -* update sa-token 1.30.0 => 1.31.0 -* update springdoc 1.6.11 => 1.6.12 -* update poi 5.2.2 => 5.2.3 -* update hutool 5.8.6 => 5.8.8 -* update aws-s3 1.12.300 => 1.12.324 -* update aliyun-sms 2.0.18 => 2.0.22 -* update tencent-sms 3.1.591 => 3.1.611 -* update tlog 1.4.3 => 1.5.0 安全性升级 -* update snakeyaml 1.30 => 1.32 存在漏洞 -* update redisson 3.17.6 => 3.17.7 -* update nginx 1.21.6 => 1.22.1 存在漏洞 -* update element-ui 2.15.8 => 2.15.10 -* update core-js 3.19.1 => 3.25.3 - -### 功能更新 -* update 修改 差异命名与镜像名同步 -* update 优化 通用下载方法新增config配置选项 -* update 优化 日志操作中重置按钮时重复查询的问题 -* update 优化 `@Anonymous` 注解标注过期 使用 `@SaIgnore` 替换 -* update 优化 前端可以配置多排序参数支持依次排序 -* update 优化 oss管理 支持时间排序 -* update 优化 替换 sa-token 过期配置 -* update 优化 sa-token 拦截器注册 `SaTokenConfig#addInterceptors` 排除拦截路径配置 -* update 优化 vue3说明文件 编码问题 -* update 优化 导入更新用户数据前校验数据权限 -* update 优化 `R` 类 `isError` 和 `isSuccess` 改为静态方法 -* update 优化 获取用户信息getInfo接口 使用缓存数据获取 -* update 优化 选择按钮宽度 - -### 问题修复 -* fix 修复 用户导入存在则更新不生效 -* fix 修复 日志转换非json数据导致报错 -* fix 修复 控制台SQL日志打印时间格式化问题 -* fix 修复 不同网段因reset请求头导致下载导出跨域问题 -* fix 修复 在线用户设置永不过期 被过滤问题 -* fix 修复 在线用户设置永不过期 超时时间-1推送redis无效问题 -* fix 修复 snakeyaml 漏洞 强制升级依赖版本(临时处理等boot升级) -* fix 修复 开启账号同端互斥登录 被顶掉后登出报null异常问题 -* fix 修复 Redisson 设置 `NameMapper` 导致队列功能异常问题 -* fix 修复 文件上传组件格式验证问题 -* fix 修复 内部调用缓存不生效问题 -* fix 修复 主题颜色在Drawer组件不会加载问题 -* fix 修复 小屏幕上修改头像界面布局错位的问题 -* fix 修复 内链域名特殊字符替换 合并错误导致问题 -* fix 修复 nginx 漏洞 https://www.oschina.net/news/214309 - -## v4.3.0 - 2022-09-14 - -### 重大更新 -* [重大更新] 整合 springdoc 基于 javadoc 实现无注解零入侵生成接口文档 -* [重大更新] 重写 spring-cache 实现 更人性化的操作 支持注解指定ttl等一些参数 -* [不兼容更新] 移除 swagger 所属所有功能 建议使用 springdoc -* [重大更新] 移除maven docker插件 过于老旧功能缺陷大 使用idea自带的docker插件替代 - -### 依赖升级 -* update springboot 2.6.9 => 2.7.3 -* update springboot-admin 2.7.2 => 2.7.4 -* update redisson 3.17.4 => 3.17.6 -* update hutool 5.8.3 => 5.8.6 -* update okhttp 4.9.1 => 4.10.0 -* update lock4j 2.2.1 => 2.2.2 -* update aws-java-sdk-s3 1.12.248 => 1.12.300 修复依赖安全漏洞 -* update aliyun.sms 2.0.9 => 2.0.18 -* update tencent.sms 3.1.537 => 3.1.591 -* update guava 30.0-jre => 31.1-jre -* update springdoc 1.6.9 => 1.6.11 -* update druid 1.2.11 => 1.2.12 -* update dynamic-ds 3.5.1 => 3.5.2 - -### 功能更新 -* update 优化 短信接口实现类 `@Override` 注解 -* update 优化 登出方法代码逻辑 -* update 优化 代码中的一些魔法值 -* update 优化 使用 StreamUtils 简化业务流操纵 -* update 修改 oss 客户端自定义域名 统一使用https开关控制协议头 -* update 更新 监控过时配置 WebSecurityConfigurerAdapter 改为 bean 注入 -* update 修改 生成错误注释 -* update 优化 docker 部署方式 使用 host 模式简化部署流程 降低使用成本 -* update 修改 验证码开关变量名 -* update 优化 DateColumn 支持单模板多key场景 -* update 优化 redission 处理增加前缀 -* update 优化 缓存监控 相关代码 -* update 优化 部署脚本 防止出现权限问题 -* update 优化 多个相同角色数据导致权限SQL重复问题 -* update 优化 字典数据使用store存取 -* update 优化 布局设置使用el-drawer抽屉显示 -* update 更新框架文档 专栏与视频 链接地址 -* update 优化 OSS文件上传 主动设置文件公共读 适配天翼云OSS -* update 优化 表格上右侧工具条(搜索按钮显隐&右侧样式凸出) -* update 优化 前后端多环境部署保持一致 删除无用环境文件 -* update 优化 错误登录锁定与新增解锁功能 -* update 优化 getLoginId 增加必要参数空校验 -* update 使用 SpringCache注解 优化参数管理、字典管理、在线用户等业务缓存 -* update 优化 多角色数据权限匹配规则 -* update 优化 页面内嵌iframe切换tab不刷新数据 -* update 优化 调整 oss表key 与 ossconfig的service 字段长度不匹配 -* update 优化 操作日志密码脱敏 -* update 重构 QueueUtils 抽取通用方法 统一使用 适配优先队列新用法 - -### 新功能 -* add 增加 StreamUtils 流工具 简化 stream 流操纵 -* add 新增 缓存列表菜单功能 -* add 新增 获取oss对象元数据方法 -* add 增加 QueueUtils 操作普通队列的方法 - -### 问题修复 -* fix 修复 mysql sys_notice 与 sys_config 表主键类型长度不够问题 -* fix 修复 获取 SensitiveService 空问题 增加空兼容 -* fix 修复 代码生成首字母大写问题 -* fix 修复 minio 上传自定义域名回显路径错误问题 -* fix 修复 短信功能返回实体 SysSms 序列化问题 -* fix 修复 sqlserver 更新sql错误提交 -* fix 修复 RedisUtils 并发 set ttl 错误问题 -* fix 修复 防止主键字段名与'row'或'ids'一致导致报错的问题 -* fix 修复 幂等组件 逻辑问题导致线程变量未清除 -* fix 修复 脱敏没有实现类导致返回数据异常问题 -* fix 修复 用户导出字典使用错误 -* fix 修复 用户登录与短信登录 国际化格式不一致 -* fix 修复 BaseMapperPlus 方法命令不一致问题 -* fix 修复 短信功能是否启用判断不生效BUG -* fix 修复 xxljob prod 环境配置文件 数据库ip漏改 -* fix 修复 部署脚本 cp 命令缺少参数问题 -* fix 修复 菜单管理的一些操作问题 -* fix 修复 国际化文件提交为特殊编码问题 -* fix 修复 minio配置https遇到的问题 -* fix 修复 点击删除后点击取消控制台报错问题 -* fix 修复 文件/图片上传组件 第一次上传报错导致后续上传无限loading问题 -* fix 修复 postgresql 时间查询类型转换报错问题 -* fix 修复 部门与角色 状态导出字典使用错误 -* fix 修复 openapi结构体 因springdoc缓存导致多次拼接接口路径问题 -* fix 修复 没有权限的用户编辑部门缺少数据 -* fix 修复 oss配置删除内部数据id匹配类型问题 -* fix 修复 用户导入存在则更新不生效 -* fix 修复 日志转换非json数据导致报错 - -## v4.2.0 - 2022-06-28 -### 重大更新 -* [重大更新] 增加 `ruoyi-sms` 短信模块 整合 阿里云、腾讯云 短信功能 -* [重大改动] 基于 `AWS S3` 协议重新实现 OSS模块 支持自定义域名 -* [安全性] 优化 nginx 限制外网访问内网 actuator 相关路径(建议升级) -* [不兼容] 优化 文件与图片上传组件 使用id存储回显(升级的用户需要注意 上传组件返回值变成了 ossid 便于关联) -* [不兼容] 升级 mybatis-plus 3.5.2 解决新版本兼容性问题 关键字冲突修改(新增了很多关键字 升级的需要注意 冲突的关键字建议换一个命名) - -### 依赖升级 -* update springboot-admin 2.6.6 => 2.6.9 -* update springboot-mybatis 2.2.0 => 2.2.2 -* update sa-token 1.29.0 => 1.30.0 -* update hutool 5.7.22 => 5.8.3 -* update druid 1.2.8 => 1.2.11 -* update tlog 1.3.6 => 1.4.3 -* update easyexcel 3.0.5 => 3.1.1 去除cglib 支持jdk17 -* update xxl-job 2.3.0 => 2.3.1 -* update redisson 3.17.0 => 3.17.4 -* update mybatis-plus 3.5.1 => 3.5.2 -* update poi 4.1.2 => 5.2.2 性能大幅提升 -* update docker mysql 8.0.27 => 8.0.29 -* update docker nginx 1.21.3 => 1.21.6 -* update docker redis 6.2.6 => 6.2.7 -* update docker minio 2021-10-27 => 2022-05-26 - -### 功能更新 -* update 优化 redis 序列化 使用系统自带json工具 全局统一 -* update 优化 RedisUtils 重构过期方法 -* update 完善短信验证码发送接口 -* update 优化 弹窗点击遮罩层 默认不关闭 可在 main.js 修改 -* update 调整 CacheManager 使用系统 系统序列化器 -* update 调整 图片预览组件 去除无用根目录拼接 -* update 用户管理左侧树型组件增加选中高亮保持 -* update 优化 DataPermissionHelper 上下文存储 使用 SaToken 的请求存储器 -* update 优化 用户头像上传限制只能为图片格式 -* update 优化 redis 与 jackson 使用自动装配定制器简化配置 -* update 优化 getLoginUser 获取 使用一级缓存 -* update 增加 redis 无密码使用说明 -* update 手动配置 Undertow 缓冲池 消除运行警告 -* update 优化 表单构建按钮不显示正则校验 -* update 优化 oss 回显查询 使用 redis 缓存 -* update 优化 用户列表查询 剔除密码字段 -* update 优化 验证码 登录 登出 注册 等接口 使用匿名注解放行 -* update 修改 代码生成 controller 去除查询校验 由用户自行选择是否校验 -* update 优化 ExcelUtil 工具支持合并处理器 -* update 使用 SaStorage 优化 LoginHelper 一级缓存 避免 ThreadLocal 清理不干净问题 -* update 优化 新增用户与角色信息、用户与岗位信息逻辑 -* update 优化 代码生成 业务接口 增加事务回滚 -* update 优化 logback 删除无用配置 - -### 新功能 -* add 增加 MailUtils 邮件工具 -* add 增加 RedisUtils 操作原子值方法 -* add 增加 demo 短信演示案例 -* add 增加 获取短信验证码接口 -* add 新增 SpringUtils 获取配置文件中的属性值方法 -* add 新增 Anonymous 匿名访问不鉴权注解 -* add 新增 easyexcel 单元格合并注解与处理器 -* add 增加 ExcelUtil 模板导出方法 支持 单列表/多列表 -* add 增加 Excel 模板导出 测试类 - -### 问题修复 -* fix 修复 ExcelUtil 表达式解析 参数添反导致无法解析问题 -* fix 修复 全局线程池配置 核心线程与最大线程 参数填反问题 -* fix 修复 查询未分配用户角色列表 角色无绑定用户情况下 空列表问题 -* fix 修复 sqlserver 新增数据 id 错误 -* fix 修复 token 超时时间设置 -1 导致的单位转换问题 -* fix 修复 编辑 OssConfig 在 postgres 字段重复报错 补全 remark 字段 -* fix 修复 postgres 数据库 菜单部分字段类型无法转换问题 -* fix 修复 脱敏实现逻辑问题 -* fix 修复 登录未选部门报空问题 -* fix 修复 用户注销时记录注销日志异常问题 -* fix 修复 代码生成表字段类型不匹配 导致查询不准确问题 - -## v4.1.0 - 2022-04-24 -### 重大更新 -* [重大更新] 增加应用适配 oracle -* [重大更新] 增加应用适配 SQL Server -* [重大更新] 增加应用适配 postgresql -* [重大更新] 确保更好的适配 多数据库 主键策略统一改为 雪花ID - -### 依赖升级 -* update springboot 2.6.4 => 2.6.7 修复 CVE-2022-22965 漏洞 -* update springboot-admin 2.6.2 => 2.6.6 -* update hutool 5.7.21 => 5.7.22 -* update dynamic-datasource 3.5.0 => 3.5.1 -* update redisson 3.16.8 => 3.17.0 -* update qiniu 7.9.3 => 7.9.5 -* update qcloud 5.6.68 => 5.6.72 -* update minio 8.3.7 => 8.3.8 -* update okhttp 4.9.2 => 4.9.3 - -### 功能更新 -* update 简化查询 部门、菜单、角色、用户、代码生成列表 功能 -* update 优化 部门修改子元素关系 使用批量更新 -* update 优化去除sql差异化 时间范围统一使用 between 处理 -* update 优化 RepeatSubmit 注解 支持业务处理失败 与 异常快速放行 -* update 优化 防重 与 限流 功能支持国际化消息返回 -* update 开启TopNav没有子菜单情况隐藏侧边栏 -* update 更新minio压缩配置 -* update 重命名 菜单字段 query -> query_param 解决系统关键字问题 -* update 使用 in 优化 or 提升索引命中率 -* update 优化 TreeEntity 树实体 去除未知泛型 -* update 优化菜单名称过长悬停显示标题 -* update 优化固定Header后顶部导航栏样式问题 -* update 优化 logback 日志 异步输出 -* update 全局异常处理器引入DuplicateKeyException主键冲突异常拦截 -* update topNav自定义隐藏侧边栏路由 -* update 更名 SaInterfaceImpl 为 SaPermissionImpl 完善相关注释 -* update 优化 sa-token 路由拦截器语法 增加注释 避免误操作 -* update 优化文件上传、图片上传组件 文件列表展示文件原名便于后续处理, 完善组件删除功能 -* update 优化登录失败相关部分代码结构 -* update 使用 spring cglib 替换 停止维护的 cglib -* update 简化 全局线程池配置 使用cpu核心数自动处理 -* update 移除 重复提交 配置文件全局配置 使用注解默认值替代 - -### 新功能 -* add 增加 4.0 升级 4.1 的 sql 脚本(升级需执行此sql) -* add 增加 DataBaseHelper 数据库助手 用于屏蔽多类型数据库sql语句差异 -* add 增加 短信登录 与 小程序登录 示例 -* add 增加 Mybatis 全局异常处理 开启多数据源切换 严格模式 找不到数据源报错 - -### 问题修复 -* fix 修复 数据权限 从 aop 切换到 拦截器 导致获取代理失败问题 -* fix 修复表单清除元素位置未垂直居中问题 -* fix 修复 poi 组件漏洞 与 mysql jdbc 漏洞 -* fix 修复单独访问 接口文档 请求 favicon.ico 报错问题 -* fix 修复 minio 上传, 因 socket 导致 available 获取数值不精确问题 -* fix 修复 cos_api bcprov-jdk15on 漏洞 -* fix 修复 guava 漏洞 统一依赖版本 -* fix 修复 tlog 依赖漏洞 - -## v4.0.1 - 2022-03-01 -### 依赖升级 -* update springboot 2.6.3 => 2.6.4 -* update hutool 5.7.20 => 5.7.21 -* update qiniu 7.9.2 => 7.9.3 -* update minio 8.3.5 => 8.3.7 - -### 功能更新 -* update 图片上传 文件上传 支持并发上传 -* update 组件ImageUpload支持多图同时选择上传 -* udpate 组件fileUpload支持多文件同时选择上传 -* update 优化 R 默认返回 msg -* update 增加 用户注册 用户类型默认值 -* update 增加用户登出日志 -* update 更新 多用户多设备的注释说明 -* update 优化 是否为管理员的判断 -* update 优化 页面若未匹配到字典标签则返回原字典值 -* update 调整用户登录 将日志调整到最后 防止获取不到用户警告 -* update 优化随机数生成方式 避免容易生成两个相同随机数的问题 - -### 问题修复 -* fix 修复代码生成 基于路径生成 路径为空问题 -* fix 恢复误删 `@Async` 注解线程池配置类 -* fix 修复 minio 适配 https 导致的问题 -* fix 修复分页组件请求两次问题 - -## v4.0.0 - 2022-02-18 -### 重大更新 -* [重大更新] 重写项目整体结构 数据处理下沉至Mapper符合MVC规范 减少循环依赖 -* [重磅更新] 主分支与satoken分支合并 权限统一使用 sa-token -* [重磅更新] 适配升级 SpringBoot 2.6 -* [重磅更新] EasyExcel大版本升级3.X -* [重磅更新] 移除链式调用注解 因链式调用不符合java规范 导致很多问题 -* [重磅更新] 增加 轻量级 分布式队列 支持 -* [重磅更新] 增加 数据脱敏注解 使用序列化控制脱敏 支持多种表达式 -* [重磅更新] 重构 使用 Spring 简化 oss 模块代码 -* [重磅更新] 重构 调整返回类型为 R 精简 Controller 代码 - -### 依赖升级 -* update springboot 2.5.8 => 2.6.3 -* update mybatis-plus 3.4.3.4 => 3.5.1 -* update maven-jar-plugin 3.2.0 => 3.2.2 -* update maven-war-plugin 3.2.0 => 3.2.2 -* update maven-compiler-plugin 3.1 => 3.9.0 -* update hutool 5.7.18 => 5.7.20 -* update springboot-admin 2.6.0 => 2.6.2 -* update redisson 3.16.7 => 3.16.8 -* update qiniu 7.9.0 => 7.9.2 -* update aliyun 3.13.1 => 3.14.0 -* update qcloud 5.6.58 => 5.6.68 -* update minio 8.3.4 => 8.3.5 - -### 功能更新 -* update 用户管理部门查询选择节点后分页参数初始 -* update 防重复提交标识组合(key + url + header) -* update 接口文档增加 basic 账号密码验证 -* update 用户修改减少一次角色列表关联查询 -* update 优化部门修改缩放后出现的错位问题 -* update 指定 maven 资源过滤为具体文件 防止错误过滤 -* update hutool 引入改为 bom 依赖项引入 -* update 降低开发环境 redis连接池数量 -* update 升级 springboot 2.6.X 解决 springfox 兼容性问题 -* update 优化多用户体系处理 更名 LoginUtils 为 LoginHelper 支持 LoginUser 多级缓存 -* update 优化加载字典缓存数据 -* update 数据库更改 对接多用户体系 -* update 移除掉 StringUtils 语义不明确的api方法 使用特定工具替换 -* update 优化登录、注册在接口通过`@Validated`注解进行数据基础校验 -* update 优化 查询登录用户数据 统一走缓存 -* update 优化 redisson 配置 去除掉不常用的配置 使用默认配置 -* update 用户访问控制时校验数据权限,防止越权 -* update 修改用户注册报未登录警告 -* update 调整oss预览开关 使用前端直接调用更改配置参数 -* update 使用 satoken 自带的 BCrypt 工具 替换 Security 加密工具 减少依赖 -* update 优化 TreeBuildUtils 工具 使用反射自动获取顶级父id -* update 使用 hutool Dict 优化 JsonUtils 防止类型解析异常 -* update 优化代码生成 使用新 JsonUtils.parseMap 方法 -* update 更新 所有 oss 均支持 https 配置 - -### 新功能 -* add 增加 RedisUtils 工具 hasKey 检查key存在方法 -* add 增加 监控中心 自定义事件通知 -* add 增加 3.X update 4.0 更新sql - -### 问题修复 -* fix 修复登录失效后多次请求提示多次弹窗问题 -* fix 修复 StringUtils 通配符匹配无效 -* fix 修复选项卡点击右键刷新丢失参数问题 -* fix 修复 数据权限 缓存方法名错误问题 -* fix 修复自定义组件`file-upload`无法显示第一个文件,列表显示的文件比实际文件少一个的问题 -* fix 修复因升级 sa-token 导致 doLogin 无法获取 token 问题 -* fix 修复分页组件请求两次问题 - -### 移除功能 -* remove 移除过期代码 分页工具相关 -* remove 移除过期代码 多数据源切换 -* remove 移除过期代码 数据权限 - -### 其他 -* 3.X 版本进入维护阶段 不进行更新 只修复bug 持续维护到2022年10月 -* 4.X 版本公测将近一个月 大部分bug已修复 官网主分支更改为 4.X 版本 推荐使用 - - -## v3.5.0 - 2021-12-28 -### 重大更新 -* [重大更新] 重写数据权限实现 -* [重磅更新] 重构分页 简化使用 -* [重磅更新] 用户登录 支持校验错误次数锁定登录 -* [重磅更新] 增加 jdbc 批处理参数 大幅提升批量操作性能 对原生语句与 MP 均有效 - -### 依赖升级 -* update springboot 2.5.7 => 2.5.8 升级预防 log4j2 问题 -* update springboot-admin 2.5.4 => 2.5.5 -* update hutool 5.7.16 => 5.7.18 -* update redisson 3.16.4 => 3.16.7 -* update dynamic-ds 3.4.1 => 3.5.0 -* update qiniu 7.8.0 => 7.9.0 -* update minio 8.3.3 => 8.3.4 -* update tlog 1.3.4 => 1.3.6 启用 tlog 自动配置 -* update clipboard 2.0.6 => 2.0.8 - -### 功能更新 -* update 多数据源切换标注过期 3.6.0 移除 推荐使用原生注解 -* update 通用权限服务 迁移回 ruoyi-framework 模块 -* update 使用 hutool-jwt 替换老旧 jjwt 依赖 -* update 调整 OSS 表字段内容长度 -* update LoginUser 增加角色缓存 优化角色权限代码 -* update 使用 Cglib 重构 BeanCopyUtils 性能优异 -* update 禁止所有工具类实例化 优化代码书写规范 -* update 优化查询用户的角色组、岗位组代码 -* update 更新 RedisUtils 返回客户端实例 -* update 修改 健康检查权限 改为用户放行 提高安全性 -* update hutool 工具 改为单包引入 减少无用依赖 -* update ServicePlusImpl 功能 下沉到 BaseMapperPlus -* update 去除 jdk17 标签 由于很多组件还未适配 导致一些问题 -* udpate 代码生成预览支持复制内容 -* update 用户导入提示溢出则显示滚动条 -* update 路由支持单独配置菜单或角色权限 -* update 优化web拦截器 使用原生接口处理 默认非生产环境开启 -* update 调整监控依赖 从 common 迁移到 framework - -### 新功能 -* add 新增 Vue3 分支 与 代码生成模板(由于组件还未完善 仅供学习) -* add 增加 RedisUtils 注册监听器方法 -* add 增加 自定义 Xss 校验注解 用户导入增加 Bean 校验 -* add oss下载增加 loading 层 -* add 新增图片预览组件 -* add 集成compression-webpack-plugin插件实现打包Gzip压缩 -* add 新增 SqlUtils 检查关键字方法 - -### 问题修复 -* fix 修复 集群雪花id重复问题 使用网卡信息绑定生成 -* fix 修复 count 语法异常 -* fix 修复更改密码问题 -* fix 修复sql关键字处理 防止解析器报错 -* fix 修复 TreeBuildUtils 顶节点不为 0 问题 -* fix 修复 SysOssConfig 主键类型错误 -* fix 修复代码生成 导出注解错误 -* fix 修复 redisson 集群模式 路径未匹配协议头问题 -* fix 修复打包后字体图标偶现的乱码问题 -* fix 修复版本差异导致的懒加载报错问题 -* fix 修复代码生成字典组重复问题 - -### 移除功能 -* remove 删除 jjwt 无用依赖 -* remove 移除过期 用户导入 -* remove 移除过期工具 DictUtils - -## v3.4.0 - 2021-11-29 - -### 重磅更新 -* update [重磅更新] 重构 Excel 导入 支持 Validator 校验 支持自定义监听器 -* update [重磅更新] Validator 校验框架支持国际化 - -### 依赖升级 -* update springboot 2.5.6 => 2.5.7 -* update hutool 5.7.15 => 5.7.16 -* update okhttp 4.9.1 => 4.9.2 -* update spring-boot-admin 2.5.2 => 2.5.4 -* update redisson 3.16.3 => 3.16.4 -* update tlog 1.3.3 => 1.3.4 -* update axios 0.21.0 => 0.24.0 -* update core-js 3.8.1 => 3.19.1 -* update js-cookie 2.2.1 => 3.0.1 -* update velocity 1.7 => 2.3 -* update 升级 docker 基础镜像 - -### 功能更新 -* update 基于 hutool 封装树构建工具 重构部门与菜单树结构返回 -* update 减少使用特定数据库函数 -* update 配置应用前缀路径 改为配置文件统一配置 -* update 升级 swagger 配置 使用 knife4j 增强模式 -* update 监控中心 集成监控客户端 实现自监控 -* update 调度中心 集成监控客户端 注册到监控中心 -* update 优化 tab 对象简化页签操作 -* update 解耦 LoginUser 与 SysUser 强关联 -* update 更新 RepeatSubmit 注解 aop 处理 针对特殊参数进行过滤 -* update DictUtils 字典工具类 标记过期 3.5.0 版本移除 使用 DictService 代替 -* update 抽象 DictService 通用 字典服务 -* update 抽象 ConfigService 通用 参数配置服务 -* update 基于 DictService 重构 Excel 内字典查询功能 -* update OSS 模块 整体重命名 消除歧义 -* update 更新 redis.conf 存储策略 aof 与 rdb 配置参数 -* update 初始化数据转移到 ApplicationRunner 统一处理 -* update 优化时间查询语句 - -### 新功能 -* add 增加 框架缓存懒加载 开关 -* add 新增 监控中心 Bean 初始化 startup trace 监控插件 -* add 增加 ValidatorUtils 校验框架工具 用于在非 Controller 的地方校验对象 - -### 漏洞修复 -* fix 修复 SysOss、SysOssConfig 未继承 BaseEntity 基础实体问题 -* fix 修复 xxl-job-admin 部署问题 -* fix 修复 回显数据字典键值修正 -* fix 修复 Linux 清除临时目录 导致上传找不到目录报错问题 -* fix 修复通用实体 传参无法接收问题 -* fix 修复 SysLoginController 接口文档书写错误问题 -* fix 修复 用户逻辑删除 差异问题 -* fix 修复 OSS 七牛云 token 过期未刷新问题 -* fix 修复 分页工具 排序字段 null 处理 -* fix 修复 用户导入字典使用错误 -* fix 修复 关闭 xss 功能导致可重复读 RepeatableFilter 失效 -* fix 修复 使用 this.$options.data 报错问题 -* fix 修复 代码生成复选框字典遗漏问题 -* fix 修复 重复提交不生效问题 由于概念不同 使用 RedisUtils 重构 -* fix 修复 OSS 工厂 未实例化服务更新加载问题 - -### 功能移除 -* remove 移除 quartz 相关代码与依赖 -* remove 移除 feign 相关代码与依赖 -* remove 移除 MybatisPlusRedisCache 二级缓存 - -## v3.3.0 - 2021-10-29 - -### 重磅更新 -* add [重磅更新] 增加分布式日志框架 TLog -* add [重磅更新] 增加分布式任务调度系统 Xxl-Job -* add [重大更新] 增加 ruoyi-job 任务调度模块(基于xxl-job) -* update [重大更新]全业务 增加 接口文档注解 格式化代码 - -### 依赖更新 -* update springboot 2.5.5 => 2.5.6 -* update springboot-admin 2.5.1 => 2.5.2 -* update element-ui 2.15.5 => 2.15.6 -* update hutool 5.7.13 => 5.7.15 -* update qcloud.cos 5.6.55 => 5.6.58 -* update minio 8.3.0 => 8.3.3 - -### 功能更新 -* update 更新 element 2.15.6 表格样式 -* update 优化 代码生成常量 关于 BO VO 注释 -* update 优化代码生成 导入表 列表返回 主键默认选中 -* update MybatisPlusRedisCache 标记过期 推荐使用 spring-cache -* update Quartz 标记过期 推荐迁移至新框架 xxl-job -* update Feign 标记过期 -* update 前端增加默认国际化参数 -* update 更新 Admin 监控 注释 避免错误使用 -* update Admin 监控增加日志文件输出 -* update 优化 xxl-job-admin 增加格式化日志输出与 docker 镜像 -* update 更新 xxl-job 执行器开关功能 -* update 代码生成 改为生成抽象实体 -* update 代码生成 搜索框 更新文本域生成 用于模糊查询 -* update 通用数据注入改为适配通用实体类 -* update 使用路由懒加载提升页面响应速度 -* update 迁移所有脚本文件至 script 目录 -* update swagger 组顺序配置 -* update sql 文件更新 xxljob 控制台菜单 -* update 前端增加 任务调度中心页面与环境及 nginx 配置 -* update 合并 oss.sql 至主 sql -* update 补全国际化文件(英文) -* update 更新关于全局路径设置与文档链接 -* update 删除无用 setUsername 使用自动注入 -* update RedisUtils 更新删除 hash 数据方法 - -### 漏洞修复 -* fix 修复 多数据源 aop 语法错误 -* fix 修复 子菜单无 query 参数问题 -* fix 修复 oss 配置删除时删除缓存 bug -* fix 修复无权限获取请求头 download-filename 导致文件名为空问题 - -## v3.2.0 - 2021-9-28 - -### 重大更新 -* update [重大改动]接口文档 支持分组配置 -* update [重大改动]security 路径配置抽取到配置文件 -* update [重大改动] 将 framework 与 system 模块 解耦 调整依赖结构 解决依赖冲突 -* update [重大改动]重写 防重提交实现 使用分布式锁 解决并发问题 压测通过 - -### 依赖更新 -* update springboot 2.5.4 => 2.5.5 bugfix版本 -* update mybatis-plus 3.4.3.3 => 3.4.3.4 bugfix版本 -* update redisson 3.16.2 => 3.16.3 bugfix版本 -* update easyexcel 2.2.10 => 2.2.11 -* update hutool 5.7.11 => 5.7.13 -* update file-saver 2.0.4 => 2.0.5 -* update dart-sass 1.32.0 => 1.32.13 -* update sass-loader 10.1.0 => 10.1.1 - -### 功能更新 -* update 优化代码生成 根据MP生成特性 调整导入表结构默认值合理化 -* update 将所有 云存储字样 改为 对象存储 避免误解 -* update 更新 @Cacheable 错误用法 注意事项 -* update 优化 AddressUtils 空校验处理 -* update 菜单管理支持配置路由参数 -* update 优化aop语法 使用spring自动注入注解 -* update 使用 Redisson 限流工具 重写限流实现 -* update 使用 vue-data-dict 简化数据字典使用 -* update 增加日志注解新增是否保存响应参数开关 -* update 用户未登录日志改为 warn 级别 -* update OSS模块 关于下载403报错信息优化 -* update 更新 Actuator prod 默认暴漏端点 增加暴漏 logfile 日志端点 -* update 默认适配jdk11 测试 jdk17 无异常 -* update 封装通用下载方法简化下载使用 - -### 新功能 -* add 新增通用方法简化模态/缓存使用 -* add 增加 限流演示案例 -* add 增加 redis redisson 集群配置 - -### 漏洞修复 -* fix Cron表达式生成器关闭时销毁,避免再次打开时存在上一次修改的数据 -* fix 全局限流key会多出一个"-" 将其移动到IP后面 去除多余的空格 -* fix 修复多主键代码生成bug -* fix 修复 @Cacheable 与 @DataScope 冲突问题 -* fix 修复代码生成页面数据编辑保存之后总是跳转第一页的问题 - -### 功能移除 -* remove 移除过期工具 RedisCache -* remove 移除无用配置类 ServerConfig -* remove 移除 SysUser 无用字段 salt - -## v3.1.0 - 2021-9-7 - -### 重大更新 -* add [重大改动] 过期 RedisCache 新增 RedisUtils 工具类 新增 发布订阅功能 更灵巧便于使用 -* add [重大改动] 新增 saveOrUpdateAll 方法 可完美替代 saveOrUpdateBatch 高性能 -* update [重大改动] 重写 InsertAll 方法实现 可完美替代 saveBatch 秒级插入上万数据 -* update [重大改动] 更改OSS上传通用路径生成 按照年月日分三级目录 -* update [重大改动] MP字段验证策略更改为 NOT_NULL 个别特殊字段使用注解单独处理 -* update [重大改动] 所有业务适配 RedisUtils 新工具 - -### 依赖升级 -* update springboot 2.5.3 => 2.5.4 -* update spring-boot-admin 2.5.0 => 2.5.1 -* update mybatis-plus 3.4.3 => 3.4.3.3 适配升级 (包含不兼容升级) -* update aliyun.oss 3.13.0 => 3.13.1 -* update qcloud.cos 5.6.47 => 5.6.51 -* update hutool 5.7.9 => 5.7.11 -* update maven-jar-plugin 3.1.1 => 3.2.0 -* update feign-okhttp 11.2 => 11.6 -* update redisson 3.16.1 => 3.16.2 - -### 新功能 -* add 优化 docker 增加 redis 配置文件 -* add 新增暗色菜单风格主题 -* add 菜单&部门新增展开/折叠功能 -* add 页签右键按钮添加图标 页签新增关闭左侧 - -### 功能更新 -* update 优化 OSS 模块与上传组件 异常处理 -* update 更新 jackson 配置 支持 LocalDateTime 全局格式化 -* update 优化 使用权限工具 获取用户信息 -* update 自定义可拖动弹窗宽度指令 -* update 重构 将下载excel工具提取到全局 -* update 定时任务对检查异常进行事务回滚 -* update 优化spy配置文件为 UTF8编码 解决中文注释乱码问题 -* update 修改时检查用户数据权限范围 -* update 解决 logout 写死 无法扩展路径问题 -* update 优化代码生成 导入与同步 批处理效率 -* update 修改时检查用户数据权限范围 -* update 修改代码生成字典回显样式 -* update 修改数据字典回显 -* update 优化验证码配置 使用泛型 防止错误输入 -* update 优化全局线程池配置 使用泛型 防止错误输入 -* update 使用 MP 全局配置分页溢出 -* update 代码生成器 导入表时查询 新创建表的优先排序在前面 -* update 定时任务支持在线生成cron表达式 -* update 自定义弹层溢出滚动样式 -* update 优化分页工具排序处理 -* update 优化 oss配置 使用发布订阅工具 刷新配置 -* update 代码生成 查询数据库列表 按照时间倒序 -* update 使用MP自行判断数据库类型 - -### 漏洞修复 -* fix 修复保存配置主题颜色失效问题 -* fix 修复 导出雪花id excel失真问题 -* fix 修复 druid 监控 集群模式下 无法路由到同一台服务器问题 -* fix 解决搜索校验不通过问题 -* fix 修复定时器工具编写错误问题 -* fix 修复 minio 无 perfix 问题 -* fix 修复 富文本图片路径错误问题 -* fix 修复 OSS配置清空被过滤问题 -* fix 修复 excel 导入与 class 未对应问题 -* fix 修复字典组件值为整形不显示问题 - -## v3.0.0 - 2021-8-18 - -### 重大更新 -* add [重大更新]重写 OSS 模块相关实现 支持动态配置(页面配置) -* add [重大更新]增加 jackson 超出 JS 最大数值自动转字符串(雪花id序列化)处理 -* add [重大更新]重写 防重提交拦截器 支持全局与注解自定义 拦截时间配置配置 优化逻辑 -* add [重大更新]新增是否开启用户注册功能 -* add [重大更新]增加 easyexcel 工具类 -* add [重大更新]集成 性能分析插件 p6spy 更强劲的 SQL 分析 -* add [重大更新]增加 完整国际化解决方案 -* add [重大更新]支持自定义注解实现接口限流 - -### 依赖升级 -* update feign-okhttp 11.0 => 11.2 -* update okhttp 3.19.4 => 4.9.1 -* update minio 8.2.0 => 8.3.0 -* update hutool 5.7.6 => 5.7.7 -* update element-ui 2.15.2 => 2.15.5 -* update springboot admin 2.4.3 => 2.5.0 (新增 Quartz 专属监控页) - -### 新功能 -* add 增加 admin 监控客户端开关 -* add 增加 国际化演示demo - -### 依赖更新 -* update 更新软件架构图 -* update 优化XSS跨站脚本过滤 -* update 优化BLOB下载时清除URL对象引用 -* update 更新 防重提交拦截器 demo演示案例 -* update 日常字符串校验 统一重构到 StringUtils 便于维护扩展 -* update 修改 自动注入器 用户未登录异常拦截抛出警告 返回Null -* update 重构 统一使用 流工具下载 -* update 重写 所有业务导出 适配easyexcel工具 -* update 移动文件存储业务到 system 模块 -* update 代码生成模板 适配新excel导出 -* update 将 Actuator 配置 移动到全局配置 -* update 统一镜像时区配置 移除主机时间映射 -* update 更改多数据源框架更清晰的依赖名 -* update 更新 阿里云 maven源 新地址 -* update 补全基础实体 文档注解 -* update 代码生成文档注解 增加必填判断配置 -* update 注入器 insert 增加 update 字段处理 -* update 默认首页使用keep-alive缓存 - -### 漏洞修复 -* fix 生产minio回显问题 -* fix 修复角色分配用户页面接收参数与传递参数类型不一致导致的错误 -* fix 修复代码生成 删除按钮报错 loading 不取消问题 -* fix 解决登录后浏览器后台Breadcrumb组件报错 -* fix 修复DictUtils方法报错 -* fix 头像上传 未走OSS存储问题 -* fix oss列表 jpeg 不回显问题 -* fix 修复操作日志根据状态查询异常问题 - -### 功能移除 -* remove 移除原生excel工具 -* remove 移除通用上传下载接口与配置 - -## v2.6.0 - 2021-7-28 - -### 重大更新 -* add [重大新增] 增加 OSS 对象存储模块 -* remove [重大改动] 删除 自带通用上传 接口 使用OSS模块替换 -* update [重大改动] 重写VO转换 支持深拷贝 将VO类抽象到 ServicePlus 泛型处理 -* update [重大改动] 多BO合并 使用分组校验 生成BO代码 -* update [重大改动] 重构 IServicePlus 功能 增加 BeanCopyUtils 深拷贝工具 - -### 依赖升级 -* update springboot 2.4.9 => 2.5.3 -* update hutool 5.7.4 => 5.7.6 -* update minio 8.2.2 => 8.3.0 -* update docker plugin 1.2.0 => 1.2.2 -* update redisson 3.16.0 => 3.16.1 -* update datasource 3.4.0 => 3.4.1 -* update element-ui 2.15.2 => 2.15.3 - -### 新功能 -* add 演示Demo增加自定义分页接口案例 -* add 角色&菜单新增字段属性提示信息 - -### 功能更新 -* update 更新druid配置 独立配置更明显 -* update 顶部菜单排除隐藏的默认路由 -* update 富文本新增上传文件大小限制 -* update 导入用户样式调整 -* update 顶部菜单样式调整 -* update 密码框新增显示切换密码图标 -* update 内链设置meta信息 -* update 跳转路由高亮相对应的菜单栏 - -### 漏洞修复 -* fix 修复多数据源druid全局配置缩进错误 引起无效配置问题 -* fix 修复定时任务日志执行状态显示 -* fix 修复 授权角色空数据问题 -* fix 修复 DictData 删除逻辑问题 -* fix 修复任意账户越权漏洞 - -## v2.5.2 - 2021-7-19 - -### 功能更新 -* update 优化代码生成器注释格式 - -### 漏洞修复 -* fix 回滚代码生成 批处理优化 -* fix 代码生成 queryType 重复勾选数据库无默认值问题 -* fix 修复接口单参数校验无效问题 -* fix 代码生成 queryType >= <= 标识符错误问题 -* fix 修复代码生成字典问题 -* fix 修复 thread-pool: enabled 配置不生效问题 - -### 功能移除 -* remove 删除无用文档与脚本 - -## v2.5.1 - 2021-7-13 -* update 验证码开关 转移到表 参数管理 内 -* update 使用hutool重构 判断是否url - -### 漏洞修复 - -### 功能更新 -* fix 修复 docker业务集群部署与文件上传的问题 -* fix 修复代码生成同步表结构id冲突问题 -* fix 修复代码生成选择字典 无法取消问题 -* fix 修复代码生成字典为null问题 -* fix 图片上传 多图时无法删除相应图片修复 - -### 功能移除 -* remove 删除富文本video事件 - -## v2.5.0 - 2021-7-12 - -### 依赖升级 -* update springboot 2.4.7 => 2.4.8 -* update knife4j 3.0.2 => 3.0.3 -* update hutool 5.7.2 => 5.7.4 -* update spring-boot-admin 2.4.1 => 2.4.3 -* update redisson 3.15.2 => 3.16.0 - -### 新功能 -* add 增加 docker 编排 与 shell 脚本 -* add 增加 feign 熔断 自定义结构体解析方法 与 demo 注释 -* add 用户管理新增分配角色功能 -* add 角色管理新增分配用户功能 -* add 增加spring-cache演示案例 - -### 功能更新 -* update 独立 springboot-admin 监控到扩展模块项目 -* update springboot-admin 监控 增加用户登录权限管理 -* update 优化代码生成器 批量导入 -* update 优化 增加MP注入异常拦截 -* update 关闭默认二级缓存 推荐使用 spring-cache 注解手动缓存 -* update FileUpload ImageUpload组件 支持多图片上传 -* update 优化中英文语言配置 -* update 规范maven写法 - -### 漏洞修复 -* fix redis获取map属性bug修复。 -* fix 修复 按钮loading 后端500卡死问题 -* fix 相对路径下载问题 -* fix 修复 hutool 工具返回结果不一致问题 - -## v2.4.0 - 2021-6-24 - -### 依赖升级 -* update springboot 2.3.11 => 2.4.7 -* update springboot-admin 2.3.1 => 2.4.1 -* update feign 2.2.6 => 3.0.3 -* update hutool 5.6.7 => 5.7.2 - -### 功能更新 -* update 多数据源替换成dynamic-datasource -* update 适配 jdk11 -* update 集成 Lock4j 分布式锁 -* update 移除 fastjson 增加 jackson 工具类 重写相关业务 -* update 优化 异步工厂重写 使用 spring 异步处理 -* update 全局挂载字典标签组件 -* update 日志列表支持排序操作 -* update 更新 feign demo 更清晰的用法 -* update 更新多数据源演示案例 - -### 新功能 -* add 增加 ServicePlusImpl 自动以实现类 重写移除事务注解方法 防止多数据源失效 -* add 增加 自定义 批量insert方法 -* add 增加 Swagger3 用法示例 - -### 漏洞修复 -* fix 修复地址ip地址特殊回环问题 - -## v2.3.2 - 2021-6-11 - -### 新功能 -* add redis锁工具类编写 - -### 功能更新 -* update spring-cache 整合 redisson -* update MybatisPlus整合Redis二级缓存 -* update swagger 升级为 3.0.0 使用 OAS_30 协议 -* update 优化 代码生成器 增加表单防重注解 -* update 优化 锁切面代码 key到常量类 - -### 漏洞修复 -* fix 修复相对路径上传异常问题 - -## v2.3.1 - 2021-6-4 - -### 新功能 -* add 增加 redisson 分布式锁 注解与demo案例 -* add 增加 Oracle 分支 - -### 功能更新 -* update 优化 redis 空密码兼容性 -* update 优化前端代码生成按钮增加 loading - -### 漏洞修复 -* fix 修复 redisson 不能批量删除的bug -* fix 修复表单构建选择下拉选择控制台报错问题 -* fix 修复 vo 代码生成 主键列表显示 重复生成bug -* fix 修复上传路径 win 打包编译为 win 路径, linux 报错bug - -## v2.3.0 - 2021-6-1 - -### 新功能 -* add 升级 luttuce 为 redisson 性能更强 工具更全 -* add 增加测试数据sql文件 -* add 增加demo模块 单表演示案例(包含数据权限) - -### 功能更新 -* update 完美修复 数据权限功能(支持单表多表过滤) -* update 优化代码生成模板 -* update 优化 system 模块 批量操作性能 - -## v2.2.1 - 2021-5-29 - -### 新功能 -* add 增加 security 权限框架 `@Async` 异步注解配置 - -### 功能更新 -* update 优化dataScope参数防止注入 -* update 优化参数&字典缓存操作 -* update 增加修改包名文档 -* update 文档增加演示图例 - -### 漏洞修复 -* fix 修复部门类sql符号错误 - -## v2.2.0 - 2021-5-25 - -* 同步升级 RuoYi-Vue 3.5.0 - -### 新功能 -* add 增加验证码开关 -* add 新增IE浏览器版本过低提示页面 - -### 功能更新 -* update 升级druid到最新版本v1.2.6 -* update 升级fastjson到最新版1.2.76 -* update 修改bo加入判断是否设置必填再加载必填注解 -* update 生成vue模板导出按钮点击后添加遮罩 -* update Redis设置HashKey序列化 -* update 优化Redis序列化配置 - -### 漏洞修复 -* fix 修复代码生成器中表字段取消必填无法更新问题 - -## v2.1.2 - 2021-5-21 - -### 功能更新 -* update springboot 升级 2.3.11 -* update mybatis-plus 升级 3.4.3 分页Plus对象适配更新 -* update 验证码生成更新为无符号整数计算 -* update 请求响应对象 与 分页对象 结构修改 适配接口文档配置 -* update swagger增加请求前缀 - -## v2.1.1 - 2021-5-19 - -### 功能更新 -* update 配置统一提取为 properties 配置类 -* update 分页工具 删除过期方法 -* update admin 实时监控日志 改为保留一天 - -### 漏洞修复 -* fix 修复swagger开关无法控制关闭问题 -* fix maven install 异常 - -## v2.1.0 - 2021-5-17 - -### 功能更新 -* update knife4j升级3.0.2 -* update 增强分页工具兼容性 -* update 通用Service接口 增加自定义vo转换函数 - -### 移除功能 -* remove 移除ruoyi自带服务监控(Admin已全部包含) - -## v2.0.0 - 2021-5-15 - -### 依赖升级 -* springboot 升级 2.3.10 依赖全面升级适配 - -### 新功能 -* add 增加分页工具 -* add 增加 增强Mapper 与 增强Service 重写业务适配 -* add 代码生成器 增加校验注解 - -### 功能更新 -* update 代码生成器修改为MP分页 -* update 使用 MP 分页工具 重构业务 -* update 重写文档介绍 - -### 移除功能 -* remove 移除 pagehelper 分页工具 - -### 漏洞修复 -* fix 修复代码生成 数据权限问题 - -## v1.0.2 - 2021-5-13 - -### 功能更新 -* update 更新整合打包文档 重新排版 - -### 漏洞修复 -* fix vue与boot整合打包与admin页面路由冲突 - -## v1.0.1 - 2021-5-11 - -### 依赖更新 -* update 更新banner -* update 配置转移到 yml 文件 统一管理 -* update 上传媒体类型添加视频格式 -* update 树级结构更新子节点使用replaceFirst -* update 删除操作日志记录日志 - -### 漏洞修复 -* fix 修正导入表权限标识 -* fix 文件上传时报错 - -## v1.0.0 - 2021-5-10 -* 基于 ruoyi-vue 3.4.0 发布 v1.0.0 稳定版 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/architecture_diagram.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/architecture_diagram.md deleted file mode 100644 index ef65fef3..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/architecture_diagram.md +++ /dev/null @@ -1,3 +0,0 @@ -# 软件架构图 -- - - -![输入图片说明](https://foruda.gitee.com/images/1722569328704494018/e84442b6_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/doc.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/doc.md deleted file mode 100644 index 06e62dc5..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/doc.md +++ /dev/null @@ -1,89 +0,0 @@ -# 接口文档 -- - - -## 版本 >= `4.3.0` -## 说明 - -由于 `springfox` 与 `knife4j` 均停止维护 bug众多
-故从 `4.3.0` 开始 迁移到 `springdoc` 框架
-基于 `javadoc` 无注解零入侵生成规范的 `openapi` 结构体
-由于框架自带文档UI功能单一扩展性差 故移除自带UI 建议使用外置文档工具 - -## 文档工具使用 -由于框架采用 `openapi` 行业规范 故市面上大部分的框架均支持 可自行选择
-例如: `apifox` `apipost` `postman` `torna` `knife4j` 等 根据对应工具的文档接入即可 - -## Swagger升级SpringDoc指南 - -常见功能如下 其他功能自行挖掘
-**注意: `javadoc` 只能替换基础功能 特殊功能还需要使用注解实现** - -| swagger | springdoc | javadoc | -|----------------------------------|---------------------------------|--------------------| -| @Api(name = "xxx") | @Tag(name = "xxx") | java类注释第一行 | -| @Api(description= "xxx") | @Tag(description= "xxx") | java类注释 | -| @ApiOperation | @Operation | java方法注释 | -| @ApiIgnore | @Hidden | 无 | -| @ApiParam | @Parameter | java方法@param参数注释 | -| @ApiImplicitParam | @Parameter | java方法@param参数注释 | -| @ApiImplicitParams | @Parameters | 多个@param参数注释 | -| @ApiModel | @Schema | java实体类注释 | -| @ApiModelProperty | @Schema | java属性注释 | -| @ApiModelProperty(hidden = true) | @Schema(accessMode = READ_ONLY) | 无 | -| @ApiResponse | @ApiResponse | java方法@return返回值注释 | - -# 建议使用 `Apifox`(常见问题有其他对接方式) - -官网连接: [https://www.apifox.cn/](https://www.apifox.cn/)
-视频教程: [springdoc与apifox配合使用](https://www.bilibili.com/video/BV1mr4y1j75M?p=8&vd_source=8f52c77be3233dbdd1c5e332d4d45bfb) - -![输入图片说明](https://foruda.gitee.com/images/1678976476639902970/f1617b40_1766278.png "屏幕截图") - -支持 文档编写 接口调试 Mock 接口压测 自动化测试 等一系列功能 - -### 接入框架 - -> 1.下载或使用web在线版 创建一个自己的项目 - -![输入图片说明](https://foruda.gitee.com/images/1678976502850663851/7bbd8728_1766278.png "屏幕截图") - -> 2.进入项目 选择项目设置 找到自动同步 - -![输入图片说明](https://foruda.gitee.com/images/1678976508918240326/6a4a61a8_1766278.png "屏幕截图") - -> 3.根据项目内所有文档组完成所有数据源创建(拉取后端`openapi`结构体)
-数据源URL格式 `http://后端ip:端口/v3/api-docs/组名`
-项目内所需:
-`http://localhost:8080/v3/api-docs/1.演示模块`
-`http://localhost:8080/v3/api-docs/2.通用模块`
-`http://localhost:8080/v3/api-docs/3.系统模块`
-`http://localhost:8080/v3/api-docs/4.代码生成模块`
-也可不分组统一导入: `http://localhost:8080/v3/api-docs`
- -![输入图片说明](https://foruda.gitee.com/images/1678976514385097727/05c7e0a6_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1686626073422245046/df4b6a54_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1678976527495742967/79836e7f_1766278.png "屏幕截图") - -> 4.选择 接口管理 项目概览 点击立即导入 并等待导入完成
-后续会根据策略每3个小时自动导入一次
-每次重新进入apifox也会自动同步一次
-后端有改动也可以手动点击导入
- -![输入图片说明](https://foruda.gitee.com/images/1678976534677430926/f32c64c5_1766278.png "屏幕截图") - -> 5.(注意版本号)设置鉴权 选择接口管理 项目概览 找到Auth 按照如下配置 - -**版本号: >= 5.X** - -![输入图片说明](https://foruda.gitee.com/images/1690966897370710566/6a688aea_1766278.png "屏幕截图") - -**版本号: 4.X** - -![输入图片说明](https://foruda.gitee.com/images/1678976539608390075/77246461_1766278.png "屏幕截图") - -> key对应项目配置 默认为 `Authorization` - -![输入图片说明](https://foruda.gitee.com/images/1678976544342001474/c2ff85d3_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1678976549237304743/bcdfadda_1766278.png "屏幕截图") - - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/i18n.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/i18n.md deleted file mode 100644 index 4052979a..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/i18n.md +++ /dev/null @@ -1,33 +0,0 @@ -# 国际化方案 -- - - -* 前端国际化参考 [ruoyi前端国际化文档](http://doc.ruoyi.vip/ruoyi-vue/document/htsc.html#前端国际化流程)
-* 后端国际化(2.7.0 以上增加) -* 3.4.0 以上支持 `Validator` 校验框架 -* 参考 `demo` 模块 `TestI18nController` 国际化演示案例 - 在 `Header` 请求头 增加上下文语言参数 `content-language` 参数需与国际化配置文件后缀对应 - 如 `zh_CN` `en_US` 等
- -![输入图片说明](https://foruda.gitee.com/images/1678976722892396585/60917594_1766278.png "屏幕截图") - -## 获取 `code` 对应国际化内容 - -![输入图片说明](https://foruda.gitee.com/images/1678976728533100954/0ab8e36a_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678976733019209506/a16574d6_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678976738409745057/a073b425_1766278.png "屏幕截图") - -## 使用 `Validator` 框架校验 `controller` 参数返回国际化 - -`controller` 校验接口参数 需要在类增加 `@Validated` 注解
-![输入图片说明](https://foruda.gitee.com/images/1678976741834729507/6c19b9cc_1766278.png "屏幕截图")
-参数对应校验注解 使用 `{code}` 形式标注使用国际化处理
-![输入图片说明](https://foruda.gitee.com/images/1678976746093285542/ad0989db_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678976750822808564/56bd60d7_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678976754755107198/b89bf173_1766278.png "屏幕截图") - -## 使用 `Validator` 框架校验 `Bean` 返回国际化 - -`Bean` 校验需要在接口校验 `Bean` 参数使用 `@Validated` 注解
-![输入图片说明](https://foruda.gitee.com/images/1678976761015767874/729da3bc_1766278.png "屏幕截图")
-`Bean` 内属性校验注解 使用 `{code}` 形式标注使用国际化处理
-![输入图片说明](https://foruda.gitee.com/images/1678976765122587920/0b1027af_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678976769965314387/0c416ede_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/new_module.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/new_module.md deleted file mode 100644 index 87b992aa..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/new_module.md +++ /dev/null @@ -1,15 +0,0 @@ -# 关于如何创建新模块 -- - - -* 参考ruoyi-demo模块 -* 需要改动: 父pom 与 admin模块pom - -![输入图片说明](https://foruda.gitee.com/images/1719814203987728184/6940ecf8_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1719814254968294155/70fe6d77_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1719814280768521481/14fb11cd_1766278.png "屏幕截图") - -### 注意事项 -如果是两个不同包名的模块 需要修改如下配置 - -![输入图片说明](https://foruda.gitee.com/images/1719813861680271619/82435586_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1692006501957936219/059f8526_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/update_package_name.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/update_package_name.md deleted file mode 100644 index 2dcab848..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/update_package_name.md +++ /dev/null @@ -1,33 +0,0 @@ -# 关于修改包名 -- - - - -**注意: 老包名为 com.ruoyi** - -## 1.随便找个地方新建 org.dromara 包 -![输入图片说明](https://foruda.gitee.com/images/1708491220807198688/b95c0c34_1766278.png "屏幕截图") - -## 2.在包上右键选择 refactor -> rename 选择 All Directories -![输入图片说明](https://foruda.gitee.com/images/1683276891079076405/79808b22_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1708491697128844860/1e87ad39_1766278.png "屏幕截图") - -**因为dromara组织下有很多依赖导致idea无法识别完整包名** -
-![输入图片说明](https://foruda.gitee.com/images/1708490576909691001/692e5b37_1766278.png "屏幕截图") - -**需要先将dromara修改为 例如: ruoyi 然后重复上述步骤 这样就可以整包修改了** -
-![输入图片说明](https://foruda.gitee.com/images/1708490906933084793/ff104cd7_1766278.png "屏幕截图") - -## 3.使用IDEA全局替换 org.dromara 替换为 com.xxx - -![输入图片说明](https://foruda.gitee.com/images/1708491055347995519/dedda0d1_1766278.png "屏幕截图") - -**注意: 由于dromara组织下项目很多 非本框架的依赖模块 请勿修改 例如上图中的 org.dromara.sms4j** - -## 4.如有需要 将所有模块名逐一修改即可 - -## 5.修改完成后需查看所有common包下模块spi文件是否修改正确 - -**老版本idea或者未按照教程修改包名可能导致文件丢包问题** - -![输入图片说明](https://foruda.gitee.com/images/1708491365841192006/8bc337c2_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/update_url.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/update_url.md deleted file mode 100644 index 0f5f106b..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/update_url.md +++ /dev/null @@ -1,26 +0,0 @@ -# 修改应用路径 -- - - -## 修改后端路径 - -更改 `application.yml` 的 `server.servlet.context-path` 即可更改后端容器路径 - -![输入图片说明](https://foruda.gitee.com/images/1724316662536650741/41d534b1_1766278.png "屏幕截图") - -与之对应前端 `dev`环境 需更改 `vite.config.ts` 的代理路径 - -![输入图片说明](https://foruda.gitee.com/images/1724316844091667249/9b0badc5_1766278.png "屏幕截图") - -`prod` 生产环境需修改 `nginx.conf` 后端代理路径 - -![输入图片说明](https://foruda.gitee.com/images/1661823876773225117/f1f912a9_1766278.png "屏幕截图") - -## 修改前端路径 -### 注意: 3.4.0 提供便捷更改方式 -直接修改对应环境的 `.env.环境` 文件内的 `VITE_APP_CONTEXT_PATH` 应用访问路径即可 - -![输入图片说明](https://foruda.gitee.com/images/1661824572484410642/14265f05_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1724317049535973756/0a2cc43b_1766278.png "屏幕截图") - -生产环境 `nginx.conf` 与之对应修改即可
-**注意: 文件真实目录为 `/usr/share/nginx/html/admin/index.html` 此功能一般为多项目部署需要 故会增加一层目录 如不需要可以自行修改**
-![输入图片说明](https://foruda.gitee.com/images/1678976662194341301/2720b7e9_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/client.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/client.md deleted file mode 100644 index bec103d8..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/client.md +++ /dev/null @@ -1,85 +0,0 @@ -# 客户端管理功能 -- - - -## 版本 >= 5.X - -## 客户端管理页面 - -![输入图片说明](https://foruda.gitee.com/images/1690961819029076660/c44374ac_4959041.png "屏幕截图") - -### 客户端管理字段说明 -| 字段名称 | 取值说明 | 注意事项 | -|----------------|----------------------------|--------------------------------| -| 客户端id | 由后端生成,用于前端登录校验以及接口数据加密 | 无法修改,不要删除默认数据,否则会报错 | -| 客户端key | 前端自定义 | 无法修改,不要删除默认数据,否则会报错 | -| 客户端秘钥 | 前端自定义 | 无法修改,不要删除默认数据,否则会报错 | -| 授权类型 | 密码认证、短信认证、邮件认证、小程序认证、第三方认证 | 根据授权类型判断当前客户端是否支持该登录方式 | -| 设备类型 | PC端、APP端 | | -| Token活跃超时时间 | 自定义 | 指定时间无操作则过期(单位:秒),默认30分钟(1800秒) | -| Token固定超时时间 | 自定义 | 指定时间必定过期(单位:秒),默认七天(604800秒) | - -### 前后端使用新的客户端id - -步骤如下: -1. 前端管理页面生成新的客户端id。 -2. 将新的客户端id复制到前端配置文件。 - -![输入图片说明](https://foruda.gitee.com/images/1690962894318847386/133d2f90_4959041.png "屏幕截图") - -## 新增自定义客户端 - -### 步骤一:新增客户端数据(例如增加小程序端) - -![输入图片说明](https://foruda.gitee.com/images/1690965463070099188/baeb4441_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1690965508836621042/df06248f_4959041.png "屏幕截图") - -### 步骤二:配置前端请求头信息 - -需要在全局请求头 header 中增加 cientid
-确保客户端所有请求都携带此id 可参考项目 `request.ts` - -![输入图片说明](https://foruda.gitee.com/images/1690965768235114596/980b88d2_4959041.png "屏幕截图") - -`VITE_APP_CLIENT_ID` 即配置文件中的客户端id。 - -**重点:不同客户端登录获取到的token不同与其他端不互通(例如: app登录获取到的token无法用于pc端接口查询)** - -## 新增自定义登录方式授权类型 - -**重点说明: 不要单独增加登录接口 系统全局统一只有一个登录接口 只需增加不同的鉴权方式即可** - -如何调试使用登录看这里 -> [关于登录调试步骤](/questions/login_step.md) - -### 步骤一:新增字典数据 - -![输入图片说明](https://foruda.gitee.com/images/1690968849418013624/3b28417e_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1690968865819397010/64529fad_4959041.png "屏幕截图") - -### 步骤二:新增/修改客户端数据 - -### 步骤三:后端新增认证策略 - -新增策略实现类实现 `IAuthStrategy` 接口。
- -![输入图片说明](https://foruda.gitee.com/images/1690972828588111954/7614a4c5_4959041.png "屏幕截图") - -参照已有策略实现类实现自定义参数校验登录方法逻辑。
- -![输入图片说明](https://foruda.gitee.com/images/1718951146945578143/789c80e4_1766278.png "屏幕截图") - -**注意修改 `@Service` 名称保证规范性** - -![输入图片说明](https://foruda.gitee.com/images/1718951179571300385/8db730b9_1766278.png "屏幕截图") - -`LoginBody` 校验参数(可自定义)
- -![输入图片说明](https://foruda.gitee.com/images/1718951237123374392/f7840db2_1766278.png "屏幕截图") - -例如 扩展小程序登录参数 只需要继承 `LoginBody
- -![输入图片说明](https://foruda.gitee.com/images/1718951283931895761/e6348be5_1766278.png "屏幕截图")` - -校验分组(可自定义)
- -![输入图片说明](https://foruda.gitee.com/images/1718951343601334215/8ef404b4_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/code_generate.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/code_generate.md deleted file mode 100644 index e20e09ac..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/code_generate.md +++ /dev/null @@ -1,85 +0,0 @@ -# 代码生成 -- - - -## 功能介绍 - -### 数据源配置 - -![输入图片说明](https://foruda.gitee.com/images/1678976867341325193/a2be0608_1766278.png "屏幕截图") - -**>= 4.1.0版本 项目适配多种类型数据库 可以在代码生成页面切换**
- -> 填写对应的数据源名称 点击搜索按钮 即可切换到对应的数据源
- -![输入图片说明](https://foruda.gitee.com/images/1678976876081856486/4ef4841c_1766278.png "屏幕截图") - -**>= 5.2.2版本 项目支持100+种数据库适配 在代码生成模块增加对应的数据库依赖即可**
- -![输入图片说明](https://foruda.gitee.com/images/1722396530340741054/3914eb72_1766278.png "屏幕截图") - -### 导入数据表 - -> 点击导入按钮 会加载系统数据库所有的表
- -![输入图片说明](https://foruda.gitee.com/images/1678976880393939803/3ecf1dcc_1766278.png "屏幕截图") - -> 选择需要的表 点击确定即可
- -![输入图片说明](https://foruda.gitee.com/images/1678976885370716109/4834faa5_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678976891856866728/853420d9_1766278.png "屏幕截图") - -### 编辑表生成结构 - -> 点击表对应的编辑按钮
- -![输入图片说明](https://foruda.gitee.com/images/1678976899111822310/aeaa33f9_1766278.png "屏幕截图") - -> 更改要生成表的数据
- -![输入图片说明](https://foruda.gitee.com/images/1678976903345795925/4326f6ee_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678976908897387614/4cdf939b_1766278.png "屏幕截图") - -### 生成条件影响 - -![输入图片说明](https://foruda.gitee.com/images/1678976913809284051/24da09b0_1766278.png "屏幕截图") - - -* `插入` `编辑` 影响生成 BO 类 与 前端添加编辑页面 是否有该字段 -* `列表` 影响生成 VO 类 与 前端列表页面展示 是否有该字段 -* `查询` 影响 前端页面是否有该字段的搜索框 与 后端代码是否生成对应的查询条件 -* `查询方式` 影响生成查询条件的类型 -* `必填` 影响 BO 类 与 页面是否强制校验 -* `显示类型` 影响生成页面使用何种展示组件 -* `字典类型` 影响页面是否生成与字典的关联 - -### 树表配置 - -> 编辑表生成信息 生成模板为 `树表` 填写对应数据即可
- -![输入图片说明](https://foruda.gitee.com/images/1678976917918548901/f5886c5c_1766278.png "屏幕截图") - -### 主子表说明 - -框架不支持也不推荐使用主子表
-原因一般业务场景 基本都是一对N表 多表关联场景
-还有一些 主 => 子 <= 主 场景 需求很复杂 很少有单纯主子表场景出现
-另外主子表关联 很容易出现 笛卡尔积 或者数据错乱等问题 需要自行sql调优场景
-所以建议大家都按照 单表生成 自行编写业务逻辑 - -### 预览功能 - -> 配置好生成信息后 可以点击预览按钮
- -![输入图片说明](https://foruda.gitee.com/images/1678976924411765532/2e9747df_1766278.png "屏幕截图") - -> 系统会根据已经配置好的数据 生成对应的代码预览
-> 可以再此处观察代码的生成结构和数据是否正确等
- -![输入图片说明](https://foruda.gitee.com/images/1678976945982406065/ca7383bb_1766278.png "屏幕截图") - - -### 代码结构同步 - -> 实际开发中 难免会有表结构更改的需求
-> 这时可以使用 同步功能 点击同步按钮 即可与实时数据库表进行字段同步
- -![输入图片说明](https://foruda.gitee.com/images/1678976952919156537/3c47c078_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/export.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/export.md deleted file mode 100644 index 1dd01c17..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/export.md +++ /dev/null @@ -1,249 +0,0 @@ -# 导出功能 - -- - - - -在本框架中引入了 `Easy Excel` 依赖(对 `Apache POI`进行了封装以及扩展),可以对数据进行导出操作(即写 Excel)。 - -[EasyExcel 文档地址](https://easyexcel.opensource.alibaba.com/) - -## 导出功能使用流程说明 - -### 步骤一:定义导出实体对象 - -以框架中 `SysUserExportVo` 为例: - -```Java - /** - * 用户ID - */ - @ExcelProperty(value = "用户序号") - private Long userId; - - // ....................... - - /** - * 用户性别 - */ - @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "sys_user_sex") - private String sex; - - /** - * 帐号状态(0正常 1停用) - */ - @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "sys_normal_disable") - private String status; -``` - -> 说明:
-> 1. 使用 `@ExcelProperty` 注解标注需要导出的属性。 -> 2. 注解 `@ExcelProperty` 中 `value` 属性代表表格头部标题字段,`converter` 代表使用的转换器,后面会详细说明。 -> 3. 注解 `@ExcelDictFormat` 为自定义注解,与自定义转换器结合使用,同样在后面进行详细说明。 - -### 步骤二:使用导出方法 - -以框架中 `SysUserController#export` 方法为例: - -```Java - /** - * 导出用户列表 - */ - @PostMapping("/export") - public void export(SysUserBo user, HttpServletResponse response) { - // 根据参数查询导出的用户列表数据 - List list = userService.selectUserList(user); - // 将列表转换为导出对象列表 - List listVo = MapstructUtils.convert(list, SysUserExportVo.class); - // 导出方法 - ExcelUtil.exportExcel(listVo, "用户数据", SysUserExportVo.class, response); - } -``` - -> 说明:
-> 使用 `ExcelUtil.exportExcel` 方法完成导出功能,上述 Demo 传入参数分别是:导出对象集合,Excel sheet 表名称,导出对象类型,response。 - -## 框架工具使用说明 - -### 1:字典转换器 - -字典转换器 `ExcelDictConvert` 与自定义注解 `@ExcelDictFormat` 结合使用,标注在需要转换的属性上。 - -使用方式一: - -```Java - /** - * 用户性别 - */ - @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "sys_user_sex") - private String sex; -``` - -使用方式二: - -```Java - /** - * 用户性别 - */ - @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) - @ExcelDictFormat(readConverterExp="0=男,1=女,2=未知", separator=",") - private String sex; -``` - -`@ExcelDictFormat` 注解属性说明: - -| 属性名称 | 属性类型 | 默认值 | 说明 | -|------------------|--------|-----|-----------------------------------| -| dictType | String | "" | 字典的type值 (如: sys_user_sex) | -| readConverterExp | String | "" | 读取内容转表达式 (如: 0=男,1=女,2=未知) | -| separator | String | "," | 与 readConverterExp 属性结合使用,表达式的分隔符 | - -### 2:枚举转换器 - -字典转换器 `ExcelEnumConvert` 与自定义注解 `@ExcelEnumFormat` 结合使用,标注在需要转换的属性上。 - -使用方式: - -```Java - /** - * 用户类型 - *

- * 使用ExcelEnumFormat注解需要进行下拉选的部分 - */ - @ExcelProperty(value = "用户类型", index = 1, converter = ExcelEnumConvert.class) - @ExcelEnumFormat(enumClass = UserStatus.class, textField = "info") - private String userStatus; -``` - -`@ExcelEnumFormat` 注解属性说明: - -| 属性名称 | 属性类型 | 默认值 | 说明 | -|-----------|------------|------|------------------------------| -| enumClass | Enum Class | - | 字典枚举类型 | -| codeField | String | code | 字典枚举类中对应的 code 属性名称,默认为 code | -| textField | String | text | 字典枚举类中对应的 text 属性名称,默认为 text | - -### 3:合并单元格 - -`@CellMerge` 注解用于合并相同的列数据,需要结合 `CellMergeStrategy` 策略使用,标注在需要转换的属性上。 - -使用方式: - -步骤一:在属性标注 `@CellMerge` 注解: -```Java - /** - * 部门id - */ - @CellMerge - @ExcelProperty(value = "部门id") - private Long deptId; -``` - -`@CellMerge` 注解属性说明: - -| 属性名称 | 属性类型 | 默认值 | 说明 | -|---------|----------|-----|------------------------------| -| index | int | -1 | 合并列的下标,建议使用默认值 | -| mergeBy | String[] | {} | 合并需要依赖的其他字段名称(基于这个字段内容做合并条件) | - -步骤二:导出方法开启合并: -```Java - /** - * 导出测试单表列表 - */ - @PostMapping("/export") - public void export(@Validated TestDemoBo bo, HttpServletResponse response) { - List list = testDemoService.queryList(bo); - // 参数 true 表示开启合并单元格策略 - ExcelUtil.exportExcel(list, "测试单表", TestDemoVo.class, true, response); - } -``` -![输入图片说明](https://foruda.gitee.com/images/1700128921644543994/e8d4704f_1766278.png "屏幕截图") - -### 4:复杂 Excel 导出示例 -`TestExcelController` 提供了几种导出示例,如果需要可以参照相应方法进行导出。 - -#### 4.1:单列表多数据导出(模板导出) - -模板内容: - -![输入图片说明](https://foruda.gitee.com/images/1700124852002972562/d9f57a8c_4959041.png "屏幕截图") - -模板位置:`ruoyi-modules/ruoyi-demo/src/main/resources/excel/` - -导出示例代码:参考 demo 模块 `TestExcelController` 模板写法请查看 `EasyExcel` 文档 - -导出结果: - -![输入图片说明](https://foruda.gitee.com/images/1700124885532359879/0d011d05_4959041.png "屏幕截图") - -#### 4.2:多列表多数据导出(模板导出) - -模板内容: - -![输入图片说明](https://foruda.gitee.com/images/1700125025931981176/105dbaaa_4959041.png "屏幕截图") - -模板位置:`ruoyi-modules/ruoyi-demo/src/main/resources/excel/` - -导出示例代码:参考 demo 模块 `TestExcelController` 模板写法请查看 `EasyExcel` 文档 - -导出结果: - -![输入图片说明](https://foruda.gitee.com/images/1700125054011300002/71869c1d_4959041.png "屏幕截图") - -#### 4.3:导出下拉框 - -`ExcelDictFormat` 注解指定的字典项默认都会转换成下拉框 - -自定义导出省市区下拉框示例代码:参考 demo 模块 `TestExcelController` - -导出结果: - -![输入图片说明](https://foruda.gitee.com/images/1700125265411678973/7f767719_4959041.png "屏幕截图") - -## Easy Excel 常用注解 - -`Easy Excel` 提供了丰富的注解可以对导出对象进行定制化操作,这里的注解说明针对的是原生注解,自定义注解会结合转换器一起进行说明。 - -| 类型 | 注解名称 | 使用举例 | 说明 | -|-------|-------------------------|------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------| -| 格式化注解 | @DateTimeFormat | @DateTimeFormat(value=格式化值) | 对字符串进行日期格式化 (参照 `java.text.SimpleDateFormat` 书写即可) | -| 格式化注解 | @NumberFormat | @NumberFormat(value=格式化值, roundingMode=舍入模式) | 对字符串进行数值格式化 (参照 `java.text.DecimalFormat` 书写即可, `roundingMode` 默认 `RoundingMode.HALF_UP`) | -| 样式注解 | @ColumnWidth | @ColumnWidth(value=值) | 设置列宽 | -| 样式注解 | @ContentFontStyle | @ContentFontStyle(color=颜色) | 可以设置字体类型,颜色,粗细,是否斜体,下划线等,具体可查看注解 `@ContentFontStyle` | -| 样式注解 | @ContentLoopMerge | @ContentLoopMerge(eachRow=行值, columnExtend=列值) | 设置循环合并的区域 | -| 样式注解 | @ContentRowHeight | @ContentRowHeight(value=值) | 设置内容行高 | -| 样式注解 | @ContentStyle | - | 设置单元格样式,具体可查看注解 `@ContentStyle` | -| 样式注解 | @HeadFontStyle | @HeadFontStyle(color=颜色) | 设置表头字体格式,类似 `@ContentFontStyle`,具体可查看注解 `@HeadFontStyle` | -| 样式注解 | @HeadRowHeight | @HeadRowHeight(value=值) | 设置表头行高 | -| 样式注解 | @HeadStyle | - | 设置表头样式,具体可查看注解 `@HeadStyle` | -| 样式注解 | @OnceAbsoluteMerge | @OnceAbsoluteMerge(firstRowIndex=开始行下标, lastRowIndex=结束行下标, firstColumnIndex=开始列下标, lastColumnIndex=结束列下标) | 根据设置值合并单元格 | -| 属性注解 | @ExcelIgnore | @ExcelIgnore | 导出忽略该字段 | -| 属性注解 | @ExcelIgnoreUnannotated | @ExcelIgnoreUnannotated | 默认不管加不加 `@ExcelProperty` 的注解的所有字段都会参与读写,加了 `@ExcelIgnoreUnannotated` 注解以后,不加 `@ExcelProperty` 注解的字段就不会参与 | -| 属性注解 | @ExcelProperty | @ExcelProperty(value=值, order=排序值, index=下标, converter=转换器) | 默认按照对象属性顺序导出,如果设置了 `order` 以及 `index`,优先级 `index` > `order` > 默认;converter 可以自定义 | - -## 扩展说明 - -### 自定义转换器实现 - -由于业务需要,原生注解不一定能够符合需要,因而衍生出了自定义转换器。能够实现定制化的内容转换需要。 -以下以框架中的字典转换器 `ExcelDictConvert` 为例进行说明。 - -字典转换器 `ExcelDictConvert`,字典转换器使用了自定义注解 `@ExcelDictFormat` 配合使用。 - -_**注:自定义转换器并非一定需要自定义注解,也可以针对已有的注解进行自定义转换实现。**_ - -#### 实现方式 - -自定义转换器需要实现 `com.alibaba.excel.converters.Converter` 接口,实现接口中的方法。 - -![输入图片说明](https://foruda.gitee.com/images/1700104014304819918/33eb0c42_4959041.png "屏幕截图") - -转换方法 `ExcelDictConvert#convertToExcelData` : - -![输入图片说明](https://foruda.gitee.com/images/1700104426131801297/72931ef0_4959041.png "屏幕截图") - -## 更多功能 - -更多导出功能使用可以参照 `Easy Excel` [官方文档](https://easyexcel.opensource.alibaba.com/docs/current/api/write)。 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/import.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/import.md deleted file mode 100644 index f1bbca7d..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/import.md +++ /dev/null @@ -1,202 +0,0 @@ -# 导入功能 -- - - - -在本框架中引入了 `Easy Excel` 依赖(对 `Apache POI`进行了封装以及扩展),可以对数据进行导入操作(即读 Excel)。 - -## 导入功能使用流程说明 - -### 步骤一:定义导入实体对象 - -以框架中 `SysUserImportVo` 为例: - -```java - /** - * 用户ID - */ - @ExcelProperty(value = "用户序号") - private Long userId; - - // ....................... - - /** - * 用户性别 - */ - @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "sys_user_sex") - private String sex; - - /** - * 帐号状态(0正常 1停用) - */ - @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "sys_normal_disable") - private String status; -``` - -> 说明:
-> 1. 使用 `@ExcelProperty` 注解标注需要导入的属性。 -> 2. 注解 `@ExcelProperty` 中 `value` 属性代表表格头部标题字段,`converter` 代表使用的转换器,后面会详细说明。 -> 3. 注解 `@ExcelDictFormat` 为自定义注解,与自定义转换器结合使用,同样在后面进行详细说明。 -> 4. 对象禁止使用链式注解 `@Accessors(chain = true)`,会找不到set方法。 - -### 步骤二:使用导入方法 - -以框架中 `SysUserController#importData` 方法为例: - -```Java - /** - * 导入数据 - * - * @param file 导入文件 - * @param updateSupport 是否更新已存在数据 - */ - @Log(title = "用户管理", businessType = BusinessType.IMPORT) - @SaCheckPermission("system:user:import") - @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public R importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception { - // 导入方法 - ExcelResult result = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class, new SysUserImportListener(updateSupport)); - return R.ok(result.getAnalysis()); - } -``` -> 说明:
-> 使用 `ExcelUtil.importExcel` 方法完成导出功能,上述 Demo 传入参数分别是:导入文件流,导入对象类型,导入监听器 `SysUserImportListener`。 - -## 框架工具使用说明 - -### 1:字典转换器 - -字典转换器 `ExcelDictConvert` 与自定义注解 `@ExcelDictFormat` 结合使用,标注在需要转换的属性上。 - -使用方式一: - -```Java - /** - * 用户性别 - */ - @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "sys_user_sex") - private String sex; -``` - -使用方式二: - -```Java - /** - * 用户性别 - */ - @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) - @ExcelDictFormat(readConverterExp="0=男,1=女,2=未知", separator=",") - private String sex; -``` - -`@ExcelDictFormat` 注解属性说明: - -| 属性名称 | 属性类型 | 默认值 | 说明 | -|------------------|--------|-----|-----------------------------------| -| dictType | String | "" | 字典的type值 (如: sys_user_sex) | -| readConverterExp | String | "" | 读取内容转表达式 (如: 0=男,1=女,2=未知) | -| separator | String | "," | 与 readConverterExp 属性结合使用,表达式的分隔符 | - -### 2:枚举转换器 - -字典转换器 `ExcelEnumConvert` 与自定义注解 `@ExcelEnumFormat` 结合使用,标注在需要转换的属性上。 - -使用方式: - -```Java - /** - * 用户类型 - *

- * 使用ExcelEnumFormat注解需要进行下拉选的部分 - */ - @ExcelProperty(value = "用户类型", index = 1, converter = ExcelEnumConvert.class) - @ExcelEnumFormat(enumClass = UserStatus.class, textField = "info") - private String userStatus; -``` - -`@ExcelEnumFormat` 注解属性说明: - -| 属性名称 | 属性类型 | 默认值 | 说明 | -|-----------|------------|------|------------------------------| -| enumClass | Enum Class | - | 字典枚举类型 | -| codeField | String | code | 字典枚举类中对应的 code 属性名称,默认为 code | -| textField | String | text | 字典枚举类中对应的 text 属性名称,默认为 text | - - -### 3:导入监听器 - -#### 3.1:ExcelListener 监听器接口 - -`ExcelListener` 扩展了 `ReadListener` 接口,增加了获取结果方法。 - -![输入图片说明](https://foruda.gitee.com/images/1700181723794469524/99bf83c9_4959041.png "屏幕截图") - -#### 3.2:DefaultExcelListener 默认监听器 - -`DefaultExcelListener` 默认监听器在读 Excel 时调用,主要对数据进行校验、解析、异常处理、返回结果等。导入操作时如果没有特别指定则使用该监听器。 - -#### 3.3:SysUserImportListener 用户导入监听器 - -`SysUserImportListener` 用户导入监听器是在用户导入时调用的监听器。 - -该监听器重写了 `invoke` 反射接口,对导入的用户数据进行了校验;重写了 `getExcelResult` 获取结果接口,返回结果数据。 - -#### 3.4:ExportDemoListener 带下拉框的导入监听器 - -`ExportDemoListener` 是对带有下拉框的 Excel 进行处理的导入监听器。 - -## Easy Excel 常用注解 - -`Easy Excel` 提供了丰富的注解可以对导出对象进行定制化操作,这里的注解说明针对的是原生注解。 - -| 类型 | 注解名称 | 使用举例 | 说明 | -|-------|-------------------------|------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------| -| 格式化注解 | @DateTimeFormat | @DateTimeFormat(value=格式化值) | 对字符串进行日期格式化 (参照 `java.text.SimpleDateFormat` 书写即可) | -| 格式化注解 | @NumberFormat | @NumberFormat(value=格式化值, roundingMode=舍入模式) | 对字符串进行数值格式化 (参照 `java.text.DecimalFormat` 书写即可, `roundingMode` 默认 `RoundingMode.HALF_UP`) | -| 属性注解 | @ExcelIgnore | @ExcelIgnore | 导出忽略该字段 | -| 属性注解 | @ExcelIgnoreUnannotated | @ExcelIgnoreUnannotated | 默认不管加不加 `@ExcelProperty` 的注解的所有字段都会参与读写,加了 `@ExcelIgnoreUnannotated` 注解以后,不加 `@ExcelProperty` 注解的字段就不会参与 | -| 属性注解 | @ExcelProperty | @ExcelProperty(value=值, order=排序值, index=下标, converter=转换器) | 默认按照对象属性顺序导出,如果设置了 `order` 以及 `index`,优先级 `index` > `order` > 默认;converter 可以自定义 | - -## 扩展使用 - -### 扩展一:自定义转换器实现 - -由于业务需要,原生注解不一定能够符合需要,因而衍生出了自定义转换器。能够实现定制化的内容转换需要。 -以下以框架中的字典转换器 `ExcelDictConvert` 为例进行说明。 - -字典转换器 `ExcelDictConvert`,字典转换器使用了自定义注解 `@ExcelDictFormat` 配合使用。 - -_**注:自定义转换器并非一定需要自定义注解,也可以针对已有的注解进行自定义转换实现。**_ - -#### 实现方式 - -自定义转换器需要实现 `com.alibaba.excel.converters.Converter` 接口,实现接口中的方法。 - -![输入图片说明](https://foruda.gitee.com/images/1700104014304819918/33eb0c42_4959041.png "屏幕截图") - -转换方法 `ExcelDictConvert#convertToJavaData` : - -![输入图片说明](https://foruda.gitee.com/images/1700182975516396213/d3c020f9_4959041.png "屏幕截图") - -### 扩展二:自定义监听器实现 - -自定义监听器主要用于在读取解析 Excel 数据时进行自定义操作。 -以下以框架中的用户导入监听器 `SysUserImportListener` 为例进行说明。 - -#### 实现方式 -1. 继承分析事件监听器 `AnalysisEventListener` 以及实现 Excel 监听器 `ExcelListener`。 - -![输入图片说明](https://foruda.gitee.com/images/1700184652693497753/09333dac_4959041.png "屏幕截图") - -2. 显示使用构造函数,否则将导致空指针。 - -![输入图片说明](https://foruda.gitee.com/images/1700184759075616584/cf05b0ed_4959041.png "屏幕截图") - -3. 实现 `invoke` 方法,对数据进行解析操作,可以在此方法对数据进行合法性判断。 - -4. 实现 `getExcelResult` 方法,对结果进行操作,例如返回成功、失败的统计数据。 - -## 更多功能 - -更多导入功能使用可以参照 `Easy Excel` [官方文档](https://easyexcel.opensource.alibaba.com/docs/current/quickstart/read)。 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/interface_release.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/interface_release.md deleted file mode 100644 index a3e6e6b6..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/interface_release.md +++ /dev/null @@ -1,25 +0,0 @@ -# 接口放行 -- - - -## 使用方式 - -在配置文件填写路径放行
-![输入图片说明](https://foruda.gitee.com/images/1678979039071447990/8b272aba_1766278.png "屏幕截图") - -### 注解放行 -版本 4.3.1 以上 建议使用 `@SaIgnore` 忽略注解
- -支持在类或方法上放行
-**注意: 动态路径会解析成通配符 请设计好接口路径避免问题** - -**例如: `/get/{userId}` 会解析成 `/get/*`**
-![输入图片说明](https://foruda.gitee.com/images/1666595109409104199/5b7d75c7_1766278.png "屏幕截图") - -## 注意事项 - -接口放行后不需要token即可访问
-但是没有token也就无法获取用户信息与鉴权 - -### 解决方案 -删除接口上的鉴权注解
-删除接口内获取用户信息功能
-删除数据库实体类 自动注入 `createBy` `updateBy` 因为会获取用户数据 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/oss.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/oss.md deleted file mode 100644 index 47484ab2..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/oss.md +++ /dev/null @@ -1,124 +0,0 @@ -# 关于OSS模块使用 -- - - -## 重点注意事项 - -`桶/存储区域` 系统会根据配置自行创建分配权限
-~~如手动配置需要设置 `公有读` 权限 否则文件无法访问~~(`aliyun` 还需开通跨域配置)
-4.4.0 版本支持配置`公有/私有`权限(`aliyun` 还需开通跨域配置)
-访问站点 后严禁携带其他 `url` 例如: `/`, `/ruoyi` 等
-**阿里云与腾讯云SDK访问站点中不能包含桶名 系统会自动处理**
-**minio 站点不允许使用 localhost 请使用 127.0.0.1**
-**访问站点与自定义域名 都不要包含 `http` `https` 前缀 设置`https`请使用选项处理** - -## 代码使用 - -> 参考 `SysOssService.upload` 用法
-> 使用 `OssFactory.instance()` 获取当前启用的 `OssClient` 实例
-> 进行功能调用 获取返回值后 存储到对应的业务表 - -![输入图片说明](https://foruda.gitee.com/images/1678978345529639839/d350ec0b_1766278.png "屏幕截图") - - -## 功能配置 - -### 配置OSS - -> 进入 `系统管理 -> 文件管理 -> 配置管理` 填写对应的OSS服务相关配置
- -![输入图片说明](https://foruda.gitee.com/images/1678978349820700551/1f91a237_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678978354387669856/3a91a3a9_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678978358019307086/0c2523e4_1766278.png "屏幕截图") - -**重点说明** - -> 云厂商只需修改 `访问站点`对应的域 切勿乱改(云厂商强烈建议绑定自定义域名使用 七牛云必须绑定[官方规定])
- -![输入图片说明](https://foruda.gitee.com/images/1678978362358100362/5c2c4d20_1766278.png "屏幕截图") - -> 七牛云 访问站点
- - -![输入图片说明](https://foruda.gitee.com/images/1678978366254745764/e93a65ff_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678978369853348732/79e8950e_1766278.png "屏幕截图") - -> 阿里云 访问站点 - -![输入图片说明](https://foruda.gitee.com/images/1678978373981462025/56a70398_1766278.png "屏幕截图") - -> 腾讯云 访问站点 - -![输入图片说明](https://foruda.gitee.com/images/1678978378697093134/785517f3_1766278.png "屏幕截图") - -### MinIO 使用 https访问站点 - -**注意:S3 API 签名计算算法不支持托管 MinIO Server API 的代理方案** - -[ minio https 配置方式](https://blog.csdn.net/Michelle_Zhong/article/details/126484358) - -### 切换OSS - -> 再配置列表点击 `状态` 按钮开启即可(注意: 只能开启一个OSS默认配置)
-> 手动使用 `OssFactory.instance("configKey")`
- -![输入图片说明](https://foruda.gitee.com/images/1678978383700118702/7f3fa0c5_1766278.png "屏幕截图") - -### 扩展分类 - -> 如有文件分类 建议创建多个 oss配置 进行切换存储
- -例如: 创建一个 图片存储的 oss配置
-指定唯一的 `configKey` 与 `前缀目录` 或 直接使用独立的`桶`
-独立桶的特点 可以自定义访问权限
-例如: 创建一个私有文件存储桶 不对外开放
- -![输入图片说明](https://foruda.gitee.com/images/1678978389139754119/140be1df_1766278.png "屏幕截图") - -> 指定需要使用的配置
-> 使用 `OssFactory.instance("image")` 获取的 `OssClient` 会加载上图的配置 从而达到上传不同的目录或桶 - - -![输入图片说明](https://foruda.gitee.com/images/1678978397550123641/1b536881_1766278.png "屏幕截图") - - -### 上传图片或文件 - -> 进入 `系统管理 -> 文件管理` 点击 `上传文件` 或 `上传图片` 根据选项选择即可 会对应上传到配置开启的OSS内
- -![输入图片说明](https://foruda.gitee.com/images/1678978401028132972/445d058e_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678978404388284503/5459da29_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678978408761764835/c81651fc_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678978412748494539/7bae621f_1766278.png "屏幕截图") - -### 列表展示 - -> 默认展示图片(可预览) 文件会展示路径
- -![输入图片说明](https://foruda.gitee.com/images/1678978416327601385/af1ecb3b_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678978422249633007/19d68eaa_1766278.png "屏幕截图") - -> 可以点击 `预览禁用启用` 按钮对是否展示进行更改 - -![输入图片说明](https://foruda.gitee.com/images/1678978426017014926/4f7fa3f3_1766278.png "屏幕截图") - -> 点击禁用后 图片会变成路径展示 - -![输入图片说明](https://foruda.gitee.com/images/1678978429692592556/0231d778_1766278.png "屏幕截图") - -> 也可再 `参数设置` 更改预览状态 将 `OSS预览列表资源` 改为 `false` 即可关闭预览 - -![输入图片说明](https://foruda.gitee.com/images/1678978433769403801/7d480e76_1766278.png "屏幕截图") - -### 删除功能 - -> 点击列表上方或后方 `删除` 按钮 会根据OSS服务商类型 调用对应的删除(注意: 需确保对应的服务商配置正确)
-> 可勾选多服务商类型的文件进行删除 系统会自动判断 - -![输入图片说明](https://foruda.gitee.com/images/1678978438265941745/f32edc72_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1678978441938542080/43ed7c3d_1766278.png "屏幕截图") - -### 下载功能 - -> 点击列表后方对应资源的 `下载` 按钮 根据需求填写文件名 点击确认即可完成下载 - -![输入图片说明](https://foruda.gitee.com/images/1678978448927336261/409af888_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1678978452761792483/ed0a4a72_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/page.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/page.md deleted file mode 100644 index 97b6c525..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/page.md +++ /dev/null @@ -1,32 +0,0 @@ -# 分页功能 -- - - -## 对应版本 - -> 3.5.0 版本 - -## 重点说明 - -> 项目使用 `mybatis-plus` 分页插件 实现分页功能 大致用法与 MP 一致 [MP分页文档](https://baomidou.com/pages/97710a/)
-> 项目已配置分页合理化 页数溢出 例如: 一共5页 查了第6页 默认返回第一页
- -![输入图片说明](https://foruda.gitee.com/images/1678977804058241635/b5cb362d_1766278.png "屏幕截图") - -## 代码用法 - -> `Controller` 使用 `PageQuery` 接收分页参数 具体参数参考 `PageQuery` - -![输入图片说明](https://foruda.gitee.com/images/1678977844048821356/1f994221_1766278.png "屏幕截图") - -> 构建 `Mybatis-Plus` 分页对象
-> 使用 `PageQuery#build()` 方法 可快速(基于当前对象数据)构建 `MP` 分页对象 - -![输入图片说明](https://foruda.gitee.com/images/1678977862816976499/b82c1638_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678977876194578744/eaa7b854_1766278.png "屏幕截图")
- -具体用法与 `MP` 一致 - -> 自定义 `SQL` 方法分页
-> 只需在 `Mapper` 方法第一个参数和返回值 重点: 第一个参数 标注分页对象 - -![输入图片说明](https://foruda.gitee.com/images/1678977898181729571/6e102731_1766278.png "屏幕截图")
-![输入图片说明](https://foruda.gitee.com/images/1678977906788451483/70979292_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/param_check.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/param_check.md deleted file mode 100644 index 95ee19d8..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/param_check.md +++ /dev/null @@ -1,158 +0,0 @@ -# 参数校验 -- - - - -参数校验在日常开发中十分常见,在本框架中引入了 `spring-boot-starter-validation` 依赖,底层基于 `hibernate-validator`,可以对参数进行校验。 - -## 参数校验使用 - -### 方法一:使用 `@Validated` 注解 - -#### 步骤一:标注 `@Validated` - -`@Validated` 可以标注在类上,或者是参数前。 - -```Java -/** 标注在类上 **/ -@Validated -@RestController -@RequestMapping("/auth") -public class AuthController { - - @PostMapping("/login") - public R login(@RequestBody LoginBody body) { - // ... - } - -} -``` - -```Java -/** 标注在参数前 **/ -@PostMapping -public R add(@Validated @RequestBody SysUserBo user) { - // ... -} -``` - -#### 步骤二:标注校验注解 - -在参数中加入校验注解。 - -```Java -public class SysUserBo { - - @NotBlank(message = "用户账号不能为空") - @Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符") - private String userName; - - @NotBlank(message = "用户昵称不能为空") - @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符") - private String nickName; - - @Email(message = "邮箱格式不正确") - @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") - private String email; - -} -``` - -常见校验注解见文末附表。 - -_注:message 支持 EL 表达式,{max} 直接读取前面的参数值。_ - -### 方法二:使用校验工具类 `ValidatorUtils` - -`org.dromara.common.core.utils.ValidatorUtils` - -![输入图片说明](https://foruda.gitee.com/images/1700050047426137432/206bd032_4959041.png "屏幕截图") - -使用方式 1:校验所有带有校验注解的属性 - -```Java -// 校验所有带有校验注解的属性 -ValidatorUtils.validate(object); -``` - -使用方式 2:按照分组校验属性(可以传多个分组) - -```Java -// 按照分组校验属性(可以传多个分组) -ValidatorUtils.validate(object, group); -``` - -## 扩展使用 - -### 扩展一:自定义校验注解 - -除了已有的校验注解以外,可以结合业务进行自定义。 - -以框架中的 `@Xss` 注解为例进行说明。 - -```Java -@Xss(message = "用户账号不能包含脚本字符") -@NotBlank(message = "用户账号不能为空") -@Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符") -private String userName; -``` - -#### 1:新增 `@Xss` 注解 - -`org.dromara.common.core.xss.Xss` - -![输入图片说明](https://foruda.gitee.com/images/1700048074014527096/b4e230c2_4959041.png "屏幕截图") - -#### 2:自定义校验器 - -自定义校验器实现 `jakarta.validation.ConstraintValidator` 接口。 - -`org.dromara.common.core.xss.XssValidator` - -![输入图片说明](https://foruda.gitee.com/images/1700048474563719650/f9172bdc_4959041.png "屏幕截图") - -### 扩展二:自定义分组校验 - -同一个对象在不同的请求中需要校验的参数不同,则可以使用分组校验。 - -#### 1:自定义分组 - -![输入图片说明](https://foruda.gitee.com/images/1700049439236073123/9e0d2e16_4959041.png "屏幕截图") - -#### 2:`@Validated` 注解指定分组 - -![输入图片说明](https://foruda.gitee.com/images/1700049302803077030/c2a985aa_4959041.png "屏幕截图") - -#### 3:校验注解中指定分组 - -![输入图片说明](https://foruda.gitee.com/images/1700049205699437759/96babbd6_4959041.png "屏幕截图") - -## 附录:常用校验注解 - -| 注解 | 使用(只列举特殊参数值) | 参数类型 | 说明 | -|------------------|--------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------| -| @AssertFalse | @AssertFalse | boolean / Boolean | 元素值必须为 false | -| @AssertTrue | @AssertTrue | boolean / Boolean | 元素值必须为 true | -| @DecimalMax | @DecimalMax(value=值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须小于或等于指定的最大值 | -| @DecimalMin | @DecimalMin(value=值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须大于或等于指定的最小值 | -| @Digits | @Digits(integer=整数位值, fraction=小数位值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 元素必须符合整数位以及小数位范围值 | -| @Email | @Email(regexp=正则表达式, flags=标志) | CharSequence | 元素是否符合正则表达式(正则表达式非必传) | -| @Future | @Future | - java.util.Date
- java.util.Calendar
- java.time.Instant
- java.time.LocalDate
- java.time.LocalDateTime
- java.time.LocalTime
- java.time.MonthDay
- java.time.OffsetDateTime
- java.time.OffsetTime
- java.time.Year
- java.time.YearMonth
- java.time.ZonedDateTime
- java.time.chrono.HijrahDate
- java.time.chrono.JapaneseDate
- java.time.chrono.MinguoDate
- java.time.chrono.ThaiBuddhistDate | 元素必须是未来的时刻、日期或时间 | -| @FutureOrPresent | @FutureOrPresent | 同 @Future | 元素必须是当前或未来的时刻、日期或时间 | -| @Length | @Length(min=最小值, max=最大值) | - CharSequence | 验证字符串是否在包含的 min 和 max 之间 | -| @Max | @Max(value=值) | - BigDecimal
- BigInteger
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须小于或等于指定的最大值 | -| @Min | @Min(value=值) | - BigDecimal
- BigInteger
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须大于或等于指定的最小值 | -| @Negative | @Negative | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须是一个严格的负数(即 0 被视为无效值) | -| @NegativeOrZero | @NegativeOrZero | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须为负数或 0 | -| @NotBlank | @NotBlank | CharSequence | 元素不能为 null,并且必须至少包含一个非空白字符 | -| @NotEmpty | @NotEmpty | - CharSequence
- Collection
- Map
- Array | 元素不能为 null 或空集合 | -| @NotNull | @NotNull | 不限类型 | 元素不能为 null | -| @Null | @Null | 不限类型 | 元素必须为 null | -| @Past | @Past | 同 @Future | 元素必须是过去的瞬间、日期或时间 | -| @PastOrPresent | @PastOrPresent | 同 @Future | 元素必须是过去或现在的瞬间、日期或时间 | -| @Pattern | @Pattern(regexp=正则表达式, flags=标志) | CharSequence | 元素必须与指定的正则表达式匹配(正则表达式遵循 Java 正则表达式约定) | -| @Positive | @Positive | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须是一个严格的正数(即 0 被视为无效值) | -| @PositiveOrZero | @PositiveOrZero | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须为正数或 0 | -| @Range | @Range(min=最小值, max=最大值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 验证元素是否在包含的 min 和 max 之间 | -| @Size | @Size(min=最小值, max=最大值) | - CharSequence
- Collection
- Map
- Array | 验证元素是否在包含的 min 和 max 之间 | -| @Valid | @Valid | 对象 | 级联验证 | - -更多注解可参考包: `org.hibernate.validator` \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/permissions.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/permissions.md deleted file mode 100644 index 384b7749..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/permissions.md +++ /dev/null @@ -1,144 +0,0 @@ -# 关于数据权限 -- - - -* 参考 demo 模块用法(需导入 test.sql 文件) - -### 新版数据权限功能: -1.支持自动注入 sql 数据过滤
-2.查询、更新、删除 限制
-3.支持自定义数据字段过滤
-4.模板支持 spel 语法实现动态 Bean 处理
-5.支持与菜单权限标识符联合使用(5.2.X新功能) - -### 数据权限相关代码 - -| 类 | 说明 | 功能 | -|-------------------------------|-----------------|----------------------------------------| -| DataScopeType | 数据权限模板定义 | 用于定义数据权限模板 | -| DataPermission | 数据权限组注解 | 用于标注开启数据权限 (默认过滤部门权限) | -| DataColumn | 具体的数据权限字段标注 | 用于替换数据权限模板内的 key 变量 | -| PlusDataPermissionInterceptor | 数据权限 sql 拦截器 | 用于拦截所有 sql 检查是否标注了 `DataPermission` 注解 | -| PlusDataPermissionHandler | 数据权限处理器 | 用于处理被拦截到的 sql 为其添加数据权限过滤条件 | -| DataPermissionHelper | 数据权限助手 | 操作数据权限上下文变量 | -| SysDataScopeService | 自定义 Bean 处理数据权限 | 用于自定义扩展 | - -## 忽略数据权限 - -1.如果需要指定单独 SQL 不开启过滤,可在对应的 Mapper 接口添加如下忽略注解: -``` -@InterceptorIgnore(dataPermission = "true") -``` - -2.如果需要在业务层忽略数据权限,可调用以下方法: -``` -# 无返回值 -DataPermissionHelper.ignore(() -> { 业务代码 }); -# 有返回值 -Class result = DataPermissionHelper.ignore(() -> { return 业务代码 }); -``` - -### 使用方式 `参考demo模块` -数据权限体系 `用户 -> 多角色 => 角色 -> 单数据权限` -> 例子: 用户A 拥有两个角色
-> 角色A 部门经理 可查看 本部门及以下部门的数据
-> 角色B 兼职开发 可查看 仅自己的数据 - -> 创建角色 test1 为 本部门及以下 - -![输入图片说明](https://foruda.gitee.com/images/1678978669666831574/b51ed0a3_1766278.png "屏幕截图") - -> 创建角色 test2 为 仅本人 - -![输入图片说明](https://foruda.gitee.com/images/1678978674159035056/69cf32ad_1766278.png "屏幕截图") - -> 将其分配给用户 test - -![输入图片说明](https://foruda.gitee.com/images/1678978680492570269/a47b6afc_1766278.png "屏幕截图") - -### 编写列表查询(注意: 数据权限注解只能在 Mapper 层使用) - -> 标注数据权限注解 `dept_id` 为过滤部门字段 `user_id` 为过滤创建用户 - -![输入图片说明](https://foruda.gitee.com/images/1678978687179608427/d6b83c30_1766278.png "屏幕截图") - -### 重点注意: 如下情况不生效 - -> 有自定义实现方法 最终执行的mapper不是这个方法 所以无法生效 -> -> 解决方案: 一直往下点 找到最终的执行mapper重写即可 - -![输入图片说明](https://foruda.gitee.com/images/1678978692558777291/78b0a3dd_1766278.png "屏幕截图") - -### 编写数据权限模板 - -![输入图片说明](https://foruda.gitee.com/images/1678978697141183499/cfc1cb6a_1766278.png "屏幕截图") - -1.`code` 为关联角色的数据权限 `code`
-2.`sqlTemplate` 为 sql 模板
-`#{#deptName}` 为模板变量 对应权限注解的 `key`
-`#{@sdss}` 为模板 Bean 调用 调用其 Bean 的处理方法
-3.`elseSql` 为兜底 sql 处理当前角色与标注的注解 无对应的情况
-例如 数据权限为仅本人 且 方法并未标注具体过滤注解 则 填充 `1 = 0` 使条件不满足 不允许查看
-更详细用法可以参考 `DataScopeType` 注释 - -### 测试代码 - -> 使用 `管理员` 用户优先测试 - -![输入图片说明](https://foruda.gitee.com/images/1678978703250082481/e93a68a5_1766278.png "屏幕截图") - -> 使用 `test` 用户测试 - -![输入图片说明](https://foruda.gitee.com/images/1678978710644676604/d7f80487_1766278.png "屏幕截图") - -> 使用 `test` 删除一条不属于自己的数据 -> sql执行为不满足条件 不允许删除 - -![输入图片说明](https://foruda.gitee.com/images/1678978715711122947/441d61f7_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1678978720298532619/a35b1147_1766278.png "屏幕截图") - - -> 使用 `test` 修改与删除同理
-> 具体实现为 更新和删除方法 标注数据权限注解 - -![输入图片说明](https://foruda.gitee.com/images/1678978725329242504/a70491a1_1766278.png "屏幕截图") - -### 自定义SQL模板 - -> 1.首先在角色管理 数据权限下拉框 添加自定义模板
-> 为什么不放置到系统字典问题: 因数据权限与模板绑定 不应随意改动 最好事先定义好 - -![输入图片说明](https://foruda.gitee.com/images/1678978730563169865/3459ee17_1766278.png "屏幕截图") - -> 2.代码 `DataScopeType` 自定义一个SQL模板 - -![输入图片说明](https://foruda.gitee.com/images/1678978735588305505/3f030c67_1766278.png "屏幕截图") - -> 3.标注权限注解 - -![输入图片说明](https://foruda.gitee.com/images/1678978742259837391/eabe5caa_1766278.png "屏幕截图") - -> 4.设置数据权限变量 - -![输入图片说明](https://foruda.gitee.com/images/1678978746778429543/e211201f_1766278.png "屏幕截图") - -> 5.测试 - -![输入图片说明](https://foruda.gitee.com/images/1678978751875467640/7d210cf4_1766278.png "屏幕截图") - -### mybatis-plus 原生方法 增加数据权限过滤 - -> 首先查看需要重写的方法源码 重点`方法源码` `方法源码` `方法源码`
-> 例如重写 `selectPage` 方法
- -![输入图片说明](https://foruda.gitee.com/images/1678978757955000897/8315695c_1766278.png "屏幕截图") - -> 复制源码到自己的 `Mapper` 并增加数据权限注解 注意左边出现重写图标 即为重写成功
- -![输入图片说明](https://foruda.gitee.com/images/1678978763224011694/bbea25a1_1766278.png "屏幕截图") - -### 支持类标注 - -> 获取规则 `方法 > 类` 注意: 类标注后 所有方法(包括父类方法) 都会进行数据权限过滤 - -![输入图片说明](https://foruda.gitee.com/images/1678978767336534896/fb13ee99_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/permissions_control.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/permissions_control.md deleted file mode 100644 index fa3a079c..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/permissions_control.md +++ /dev/null @@ -1,180 +0,0 @@ -# 权限控制 -- - - - -本文采用 `Sa-Token` 框架实现权限控制。[官方文档传送门](https://sa-token.cc/doc.html#/) - -## 权限校验 -权限校验指的是校验用户是否拥有访问某个 API 的能力。 - -通常情况下,一个 API 对应一个权限码,如果用户具备当前 API 的权限码,即代表有能力访问该 API。 - -### 1:权限标识 -在本系统中,每一个菜单功能都有对应的权限标识,可以在菜单管理中进行设置。 - -> 注: -> 1. 前后端的权限标识要保持一致。 -> 2. 权限标识可以使用通配符`*`。 - -![输入图片说明](https://foruda.gitee.com/images/1701086497939145368/133fb327_4959041.png "屏幕截图") - - -### 2:校验方法 -#### 2.1:使用 `@SaCheckPermission` 注解进行校验 -`@SaCheckPermission` 注解是由 `Sa-Token` 框架提供的角色校验注解,可以标注在方法上或类上。 - -- 单个权限校验: - -```Java -@SaCheckPermission("system:user:list") -``` - -- 多个权限校验(或模式,满足任意一个权限即可): - -```Java -@SaCheckPermission( - value = { - "system:user:list", - "system:user:query" - }, - mode = SaMode.OR -) -``` - -- 多个权限校验(与模式,必须满足所有权限): - -```Java -@SaCheckPermission( - value = { - "system:user:list", - "system:user:query" - }, - mode = SaMode.AND -) -``` - -#### 2.2:使用 `StpUtil` 工具类校验 -`StpUtil` 工具类是由 `Sa-Token` 框架提供的权限工具类,提供了常用的校验方法。 - -- 判断当前用户是否拥有某个权限(返回 `boolean`): - -```Java -StpUtil.hasPermission("system:user:list"); -``` - -- 单个权限校验: - -```Java -StpUtil.checkPermission("system:user:list"); -``` -如果验证未通过,则抛出异常: `NotPermissionException` - -- 多个权限校验(或模式,满足任意一个权限即可): - -```Java -StpUtil.checkPermissionOr("system:user:list", "system:user:query"); -``` -如果验证未通过,则抛出异常: `NotPermissionException` - -- 多个权限校验(与模式,必须满足所有权限): - -```Java -StpUtil.checkPermissionAnd("system:user:list", "system:user:query"); -``` -如果验证未通过,则抛出异常: `NotPermissionException` - -## 角色校验 -角色校验指的是校验用户是否拥有某个指定角色。 - -### 1:权限标识 -在本系统中,每个角色都拥有唯一的权限字符。 - -除了超级管理员角色外,其他角色的权限字符可以通过角色管理进行设置。 - -![输入图片说明](https://foruda.gitee.com/images/1701085080527279823/3255961d_4959041.png "屏幕截图") - -### 2:校验方法 -#### 2.1:使用 `@SaCheckRole` 注解校验 -`@SaCheckRole` 注解是由 `Sa-Token` 框架提供的角色校验注解,可以标注在方法上或类上。 - -- 单个角色校验 - -```Java -@SaCheckRole("superadmin") -``` - -- 多个角色校验(或模式,满足任意一个角色即可): - -```Java -@SaCheckRole( - value = { - "superadmin", - "admin" - }, - mode = SaMode.OR -) -``` - -- 多个角色校验(与模式,必须满足所有角色): - -```Java -@SaCheckRole( - value = { - "superadmin", - "admin" - }, - mode = SaMode.AND -) -``` - -#### 2.2:使用 `StpUtil` 工具类校验 -`StpUtil` 工具类是由 `Sa-Token` 框架提供的权限工具类,提供了常用的校验方法。 - -- 判断当前用户是否拥有某个角色(返回 `boolean`): - -```Java -StpUtil.hasRole("superadmin") -``` - -- 单个权限校验: - -```Java -StpUtil.checkRole("system:user:list"); -``` -如果验证未通过,则抛出异常: `NotRoleException` - -- 多个权限校验(或模式,满足任意一个角色即可): - -```Java -StpUtil.checkRoleOr("system:user:list", "system:user:query"); -``` -如果验证未通过,则抛出异常: `NotRoleException` - -- 多个权限校验(与模式,必须满足所有角色): - -```Java -StpUtil.checkRoleAnd("system:user:list", "system:user:query"); -``` -如果验证未通过,则抛出异常: `NotRoleException` - -## 角色权限双重 `OR` 校验 -除了分开校验以外,权限和角色也可以进行组合,表示备选校验。 - -简单举个例子: - -假设某个 API 的权限码为 `system:user:list`,角色 `admin` 可以调用,则可以这样写: - -```Java -@SaCheckPermission(value = "system:user:list", orRole = "admin") -``` - -以上权限只需要满足任意一项即可。更多写法可以参考 `Sa-Token` [官方文档](https://sa-token.cc/doc.html#/use/at-check?id=_4%e3%80%81%e8%a7%92%e8%89%b2%e6%9d%83%e9%99%90%e5%8f%8c%e9%87%8d-or%e6%a0%a1%e9%aa%8c)。 - -## 当前用户的所有权限 -本系统中实现了 `StpInterface` 接口,可以对用户的权限以及角色进行管理,并且可以根据不同的用户类型进行设置。 - -具体参考类:`org.dromara.common.satoken.core.service.SaPermissionImpl` - -## 忽略权限校验 -请参考文档:[接口放行](/ruoyi-vue-plus/framework/basic/interface_release?id=接口放行) - - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/social.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/social.md deleted file mode 100644 index a004434b..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/social.md +++ /dev/null @@ -1,68 +0,0 @@ -# 第三方授权功能 -- - - -## 版本 >= 5.X - -## 前置说明 -1. 该功能基于 `JustAuth` 实现,支持多家平台实现第三方授权登录。 -2. 以 `Gitee` 授权登录为例进行本功能的使用说明。 -3. 其他第三方授权配置信息获取方式可参考 `JustAuth` [官方文档](https://www.justauth.cn/guide/)。
- - ![输入图片说明](https://foruda.gitee.com/images/1690937097426867003/91d80587_4959041.png "屏幕截图") - -## 第三方授权配置 - -### 申请三方应用(以gitee为例) - -![输入图片说明](https://foruda.gitee.com/images/1700641775779304627/1cf1b56f_1766278.png "屏幕截图") - -### 更改后端配置 `application-dev.yml` - -![输入图片说明](https://foruda.gitee.com/images/1690936741844431943/580f8998_4959041.png "屏幕截图") - -**注:内网地址无法回调,请使用外网可以访问的地址。** - -![输入图片说明](https://foruda.gitee.com/images/1690940457570856867/ce22df18_4959041.png "屏幕截图") - -### 更改前端配置 `login.vue` - -![输入图片说明](https://foruda.gitee.com/images/1690937306197173754/5c1ece29_4959041.png "屏幕截图") - -## 授权登录(未绑定第三方平台) - -### 步骤一:个人中心授权第三方应用 - -![输入图片说明](https://foruda.gitee.com/images/1690938449386201097/ea375106_4959041.png "屏幕截图") - -### 步骤二:同意授权 - -![输入图片说明](https://foruda.gitee.com/images/1690938522418523183/81b327bf_4959041.png "屏幕截图") - -顶部出现授权成功,并跳转到系统首页。
- -![输入图片说明](https://foruda.gitee.com/images/1690938559178527841/563168e4_4959041.png "屏幕截图")
- -![输入图片说明](https://foruda.gitee.com/images/1690938636375977741/8ceb77cf_4959041.png "屏幕截图") - -查看第三方应用可看到授权成功的个人信息。
- -![输入图片说明](https://foruda.gitee.com/images/1690938725512311321/5532a2a9_4959041.png "屏幕截图") - -## 授权登录(已绑定第三方平台) - -### 步骤一:点击登录页面图标 - -![输入图片说明](https://foruda.gitee.com/images/1690938908352243992/fd044381_4959041.png "屏幕截图") - -### 步骤二:同意授权 - -![输入图片说明](https://foruda.gitee.com/images/1690938522418523183/81b327bf_4959041.png "屏幕截图") - -## 解除授权绑定 - -### 步骤一:个人中心点击解绑第三方应用 - -![输入图片说明](https://foruda.gitee.com/images/1690939087877969002/4ef324e7_4959041.png "屏幕截图") - -### 步骤二:点击确定完成解绑 - -![输入图片说明](https://foruda.gitee.com/images/1690939108017661775/7236088d_4959041.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/tenant.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/tenant.md deleted file mode 100644 index 33953086..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/tenant.md +++ /dev/null @@ -1,121 +0,0 @@ -# 多租户功能 -- - - -## 版本 >= 5.X - -## 前置说明(重要) -1. 本框架多租户功能的实现是基于 [MyBatis-Plus 多租户插件](https://baomidou.com/pages/aef2f2/#tenantlineinnerinterceptor) 的,只支持最简单的隔离。 -2. 本系统默认开启多租户功能。 -3. 多租户业务表建表需要加上租户id `tenant_id`,可参考其他系统表。 -4. 非多租户表可在配置文件进行配置排除。 -5. 只有超级管理员支持切换租户。 - -## 多租户使用流程(先说结论再展开!) -0. 开启多租户配置(系统默认已经开启) -1. 登录界面(可以选择不同租户) -> 注:如果为租户设置了绑定域名,则只能选择当前域名相关的租户列表。 -2. 设置多租户套餐 -3. 新增/修改租户(需要选择套餐) -4. 切换租户(仅超级管理员可操作) - -## 多租户配置 -`application.yml`
- -> 开关 `enable` 节点不用废话。
-> 如果不需要过滤租户的表可在 `excludes` 节点下添加。 - -**注意: 如果已经基于租户模式启动了程序 关闭租户必须删除mysql与redis内的相关数据重新导入sql** - -![输入图片说明](https://foruda.gitee.com/images/1680168468127690787/2cd3279e_4959041.png "屏幕截图") - -## 忽略租户 - -1.如果需要指定单独 SQL 不开启过滤,可在对应的 Mapper 接口添加如下忽略注解: -``` -@InterceptorIgnore(tenantLine = "true", dataPermission = "false") -``` -**此处注意事项 使用此注解如果需要开启数据权限 dataPermission = "false" 必须添加 mp的注解默认是忽略数据权限的 会导致数据权限失效** - -2.如果需要在业务层忽略多租户,可调用以下方法(推荐使用): -``` -# 无返回值 -TenantHelper.ignore(() -> { 业务代码 }); -# 有返回值 -Class result = TenantHelper.ignore(() -> { return 业务代码 }); -``` - -## 动态切换租户 - -**仅适用于特殊需求业务(例如: 创建租户时, 对该租户操作一些数据, 或者需要去其他租户查一些数据等) 禁止乱用后果自负** - -``` -# 无返回值 -TenantHelper.dynamic(租户id, () -> { 业务代码 }); -# 有返回值 -Class result = TenantHelper.dynamic(租户id, () -> { return 业务代码 }); -``` - -## 登录界面 - -![输入图片说明](https://foruda.gitee.com/images/1680173982933030545/bca146d7_4959041.png "屏幕截图") - -> 注:如果为租户设置了绑定域名,则只能选择当前域名相关的租户列表。 - -## 租户套餐管理 -### 租户套餐新增 -![输入图片说明](https://foruda.gitee.com/images/1680174317475230288/352957a1_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1680174602877523112/fc194f17_4959041.png "屏幕截图") - -> 注: -> 1、先新增套餐再新增租户,因为租户新增之后无法修改所选套餐。 -> 2、租户所关联的套餐如果后续有修改可以进行同步。 - - -## 租户管理 -### 默认租户 -> 注:默认租户无法修改 - -![输入图片说明](https://foruda.gitee.com/images/1680174738913576400/b6aca11a_4959041.png "屏幕截图") - -### 新增租户 -#### 填写表单 -![输入图片说明](https://foruda.gitee.com/images/1680174945220618443/f7181b51_4959041.png "屏幕截图") - -#### 选择新增的租户套餐 -![输入图片说明](https://foruda.gitee.com/images/1680174991869792688/0dbaadd6_4959041.png "屏幕截图") - -#### 新增完成 -![输入图片说明](https://foruda.gitee.com/images/1680175033853525725/42e64b4d_4959041.png "屏幕截图") - -#### 登录租户 -![输入图片说明](https://foruda.gitee.com/images/1680176145378931134/e05f347e_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1680176208161104366/44a935f1_4959041.png "屏幕截图") - -### 修改租户 -#### 配置域名 -![输入图片说明](https://foruda.gitee.com/images/1680175251192690133/141fa6a6_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1680175431036971650/db522d39_4959041.png "屏幕截图") - -#### 没有配置域名 -![输入图片说明](https://foruda.gitee.com/images/1680175541165540240/95e211f7_4959041.png "屏幕截图") - -#### 强调一下:这不是bug! -> 注:域名的配置就是为了绑定特定租户! - -### 同步套餐 -应用场景:租户套餐进行了修改,配置的菜单需要同步到特定租户。 -(不是所有租户都有更新套餐的权利, 这是跟钱挂钩的) - -> 点一下按钮的事,图略。 - -## 切换租户(仅超级管理员) -> 注:管理员切换租户不是切换用户,切换的只是数据,管理员拥有所有权限。 - -![输入图片说明](https://foruda.gitee.com/images/1680176324802967804/5c5d6fc3_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1680176431031189788/0c3f924c_4959041.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1680176496555243569/624ec677_4959041.png "屏幕截图") - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/user.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/user.md deleted file mode 100644 index b665ac5a..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/user.md +++ /dev/null @@ -1,85 +0,0 @@ -# 系统用户相关 -- - - - -> 框架采用sa-token控制权限 并对sa-token的api做了一定的业务封装
- -## 用户登录 - -> 参考自带多种登录实现 不限制用户数据来源 只需要构建 LoginUser 即可完成登录
-> 例如: `同表不同类型` `不同表` `同表+扩展表`
- -![输入图片说明](https://foruda.gitee.com/images/1699590555824776931/63d493fc_1766278.png "屏幕截图") - -## 获取用户信息 - -> 完成登录后会生成登录token返回给前端 前端需要再请求头携带token 后端方可获取到对应的用户信息 - -请求头传递格式: `Authorization: Bearer token` - -后端获取用户信息: -```java -LoginUser user = LoginHelper.getLoginUser(); -``` - -## 获取用户信息(基于token) -```java -LoginUser user = LoginHelper.getLoginUser(token); -``` - -## 获取登录用户id -```java -Long userId = LoginHelper.getUserId(); -``` - -## 获取登录用户账户名 -```java -String username = LoginHelper.getUsername(); -``` - -## 获取登录用户所属租户id -```java -String tenantId = LoginHelper.getTenantId(); -``` - -## 获取登录用户所属部门id -```java -Long deptId = LoginHelper.getDeptId(); -``` - -## 获取登录用户类型 -```java -UserType userType = LoginHelper.getUserType(); -``` - -## 获取登录用户其他扩展属性 -```java -Object obj = LoginHelper.getExtra(key); -``` - -## 设置登录用户其他扩展属性 - -参考登录设置 `clientId` 属性 - -![输入图片说明](https://foruda.gitee.com/images/1699591164562734430/42730add_1766278.png "屏幕截图") - -## 判断用户是否为超级管理员 - -```java -// 判断当前登录用户 -boolean b = LoginHelper.isSuperAdmin(); -// 判断用户基于id -boolean b = LoginHelper.isSuperAdmin(userId); -``` - -## 判断用户是否为租户管理员 - -```java -// 判断当前登录用户 -boolean b = LoginHelper.isTenantAdmin(); -// 判断用户基于角色组 -boolean b = LoginHelper.isSuperAdmin(rolePermission); -``` - -## 其他更多操作 -[Sa-Token 官方文档 - 登录认证](https://sa-token.cc/doc.html#/use/login-auth) - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/about_join.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/about_join.md deleted file mode 100644 index 593129e8..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/about_join.md +++ /dev/null @@ -1,14 +0,0 @@ -# 关于多表查询 -- - - -## 建议单表查询 - -文章连接: [大连接查询分解好处](https://java.isture.com/db/mysql/mysql-x-optimize-decompose-connection.html) -文章连接: [如何用mp多表查询性能测试](https://developer.aliyun.com/article/858927) - -![输入图片说明](https://foruda.gitee.com/images/1678979482724037085/1e74f3e1_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1666336728402711844/52788205_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1666336945935088277/f60e3288_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1666336954686520161/c6c83adc_1766278.png "屏幕截图") - -**(上图出自 <高性能MySql>)** \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/key.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/key.md deleted file mode 100644 index 3ec55fec..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/key.md +++ /dev/null @@ -1,19 +0,0 @@ -# 主键使用说明 -- - - -## 关于如何使用分布式id或雪花id - -参考 `MybatisPlusConfig` 如需自定义 修改 `Bean` 实现即可 - -![输入图片说明](https://foruda.gitee.com/images/1678979401707903546/e25f6c06_1766278.png "屏幕截图") - -框架默认集成 雪花ID 只需全局更改 主键类型即可 - -![输入图片说明](https://foruda.gitee.com/images/1678979411517764918/1470df04_1766278.png "屏幕截图") - -如单表使用 可单独配置注解 - -![输入图片说明](https://foruda.gitee.com/images/1678979416033986923/2a4c3736_1766278.png "屏幕截图") - -### 重点说明 -* 由于雪花id位数过长 `Long` 类型在前端会失真 -* 框架已配置序列化方案 超越 `JS` 最大值自动转字符串 参考 `BigNumberSerializer` 类 (3.0.0 及以上新增) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/test.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/test.md deleted file mode 100644 index c6dbfe99..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/test.md +++ /dev/null @@ -1,6 +0,0 @@ -# 单元测试 -- - - -## 参考文章 -[SpringBoot 2.X 整合 JUnit5 及全方位使用手册](https://lionli.blog.csdn.net/article/details/127576604) -## 参考代码(4.4.0新增) -![输入图片说明](https://foruda.gitee.com/images/1666973091281055549/6e8f58c3_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/transaction.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/transaction.md deleted file mode 100644 index dfad76f8..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/transaction.md +++ /dev/null @@ -1,45 +0,0 @@ -# 事务相关 -- - - -若依文档对事务注解的描述 [关于事务](https://doc.ruoyi.vip/ruoyi/document/htsc.html#%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86) 以下对多数据源事务做补充: - -## 多后端多数据源事务 - -框架支持对接 `seata` 保证分布式多数据源事务
-详情参考多数据源框架文档连接: https://www.kancloud.cn/tracy5546/dynamic-datasource/2268607 - -## 本地多数据源事务 -请使用 `@DSTransactional` 注解 会代理 `@DS` 注解切换后的数据源事务做回滚处理
-只要 `@DSTransactional` 注解下任一环节发生异常,则全局多数据源事务回滚。
-如果BC上也有 `@DSTransactional` 会有影响吗?答:没有影响的。 - -```java -//如AService调用BService和CService的方法,A,B,C分别对应不同数据源。 - -public class AService { - - @DS("a")//如果a是默认数据源则不需要DS注解。 - @DSTransactional - public void dosomething(){ - BService.dosomething(); - CService.dosomething(); - } -} - -public class BService { - - @DS("b") - public void dosomething(){ - //dosomething - } -} - -public class CService { - - @DS("c") - public void dosomething(){ - //dosomething - } -} -``` - - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/api_encrypt.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/api_encrypt.md deleted file mode 100644 index fc56df31..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/api_encrypt.md +++ /dev/null @@ -1,38 +0,0 @@ -# 数据加解密 -- - - - -## 1:API 加密注解 `@ApiEncrypt` -1. 对于标注了 `@ApiEncrypt` 注解的接口,请求参数都必须进行加密。 -2. 注解的参数 `response` 为响应加密标识,默认 `false` 不加密,为 `true` 表示响应加密。 -3. 加密解密逻辑由过滤器实现,详情可参考 `org.dromara.common.encrypt.filter.CryptoFilter`。 - -## 2:API 加密配置 -`application.yml` - -![输入图片说明](https://foruda.gitee.com/images/1701131796468961065/83c464cd_4959041.png "屏幕截图") - -`.env.development` / `.env.production` - -![输入图片说明](https://foruda.gitee.com/images/1709533252413969800/1d0dff25_1766278.png "屏幕截图") - -> 注: -> 1. 公私钥与前端配置文件互为配对,如果需要更换请一同更换。 -> 2. 后端公钥对应前端私钥;后端私钥对应前端公钥。 - -## 3:前端开启加密 -如果需要开启 API 加密,则需要修改 `request` 的 `headers` 内容: -```Javascript -headers: { - isEncrypt: true -} -``` - -![输入图片说明](https://foruda.gitee.com/images/1701137141916998346/5e839bbe_4959041.png "屏幕截图") - -## 4.关于请求响应参数加解密说明 - -如何加解密请求响应参数看这里 -> [关于请求响应参数解密](/questions/api_encrypt.md) - -## 密钥生成说明 - -![输入图片说明](https://foruda.gitee.com/images/1675577852271308699/9b30258e_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/dynamic_datasource.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/dynamic_datasource.md deleted file mode 100644 index 1e81b5e0..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/dynamic_datasource.md +++ /dev/null @@ -1,45 +0,0 @@ -# 多数据源 -- - - - -### 框架默认 mysql 其他数据库使用说明 - -找到 `ruoyi-admin` 模块在 pom 文件内增加对应的jdbc依赖 - -![输入图片说明](https://foruda.gitee.com/images/1721098535176969987/d42870ca_1766278.png "屏幕截图") - - -### 关于多数据源事务 具体参考 `事务相关` 文档说明 - -### 多数据源框架功能介绍 -多数据源框架官方文档: [dynamic-datasource文档](https://www.kancloud.cn/tracy5546/dynamic-datasource/2264611) - -* 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。 -* 支持数据库敏感配置信息 加密 ENC()。 -* 支持每个数据库独立初始化表结构schema和数据库database。 -* 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。 -* 支持 自定义注解 ,需继承DS(3.2.0+)。 -* 提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。 -* 提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。 -* 提供 自定义数据源来源 方案(如全从数据库加载)。 -* 提供项目启动后 动态增加移除数据源 方案。 -* 提供Mybatis环境下的 纯读写分离 方案。 -* 提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。 -* 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。 -* 提供 基于seata的分布式事务方案。 -* 提供 本地多数据源事务方案。 附:不能和原生spring事务混用。 - -### 用法说明 - -> 加载顺序 `方法 => 类 => 默认`
- -![输入图片说明](https://foruda.gitee.com/images/1678979069737596299/abe8ae7f_1766278.png "屏幕截图") - -### 配置方式 - -![输入图片说明](https://foruda.gitee.com/images/1678979074000345758/b9238f0b_1766278.png "屏幕截图") - -### 数据库异构 - -例如: `mysql + oracle` 参考对应多数据源框架文档 [dynamic-ds文档](https://www.kancloud.cn/tracy5546/dynamic-datasource) - -![输入图片说明](https://foruda.gitee.com/images/1678979078387192317/2de94a78_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/encrypt.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/encrypt.md deleted file mode 100644 index 19d726cd..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/encrypt.md +++ /dev/null @@ -1,28 +0,0 @@ -# 数据加解密 -- - - -## 框架版本 >= 4.6.0 -## 功能说明 - -数据库 数据存储加密 查询解密功能
-支持加密算法: `BASE64` `AES` `RSA` `SM2` `SM4` - -## 注解 `@EncryptField` - -![输入图片说明](https://foruda.gitee.com/images/1675577493013639395/cd920f15_1766278.png "屏幕截图") - -## 用法说明 - -**详细用法可参考案例 TestEncryptController 测试数据库加解密功能** - -全局默认加密配置(如果注解不配置则使用全局配置) - -![输入图片说明](https://foruda.gitee.com/images/1675577674063566357/dee94786_1766278.png "屏幕截图") - -注解可自定义算法与配置 - -![输入图片说明](https://foruda.gitee.com/images/1675577725117970708/7ee7a833_1766278.png "屏幕截图") - -## 密钥生成说明 - -![输入图片说明](https://foruda.gitee.com/images/1675577852271308699/9b30258e_1766278.png "屏幕截图") - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/idempotent.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/idempotent.md deleted file mode 100644 index 46c7f423..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/idempotent.md +++ /dev/null @@ -1,29 +0,0 @@ -# 防重幂等 -- - - -### 功能介绍 - -防重功能为防止两条相同的数据重复提交导致脏数据或业务错乱
-**注意: 重复提交属于小概率事件 请不要拿并发压测与之相提并论**
-框架防重功能参考 `美团GTIS防重系统` 使用 请求参数与用户Token或URL 生成全局业务ID
-有效防止 `同一个用户` 在 `限制时间` 内对 `同一个业务` 提交 `相同的数据` - -框架防重处理 `支持业务失败或异常` 快速释放限制
-业务处理成功后 会在设置时间内 限制同一条数据的提交
-**注意: 只对同一个用户的同一个接口提交相同的数据有效** - - - - -### 美团GTIS系统流程图 - -[美团 分布式系统互斥性与幂等性问题的分析与解决](https://tech.meituan.com/2016/09/29/distributed-system-mutually-exclusive-idempotence-cerberus-gtis.html) - -![输入图片说明](https://foruda.gitee.com/images/1678979231862359032/34f030c5_1766278.png "屏幕截图") - -### 使用方法 - -在Controller标注 `@RepeatSubmit` 注解即可 - -![输入图片说明](https://foruda.gitee.com/images/1678979236772683145/9fa27e5b_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1678979240831458322/8e1fac4b_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/mail.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/mail.md deleted file mode 100644 index 6e7413ed..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/mail.md +++ /dev/null @@ -1,17 +0,0 @@ -# 邮件功能 -- - - -## 配置功能 - -版本: v4.2.0 提供邮件功能 - -修改配置文件 - -![输入图片说明](https://foruda.gitee.com/images/1663555260932007318/fabb2bfa_1766278.png "屏幕截图") - -* `enabled` 为邮件功能开关 - -## 功能使用 - -参考 `demo` 模块 `MailController` 邮件演示案例 - -![输入图片说明](https://foruda.gitee.com/images/1663555374113593089/885b4db2_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/maxkey.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/maxkey.md deleted file mode 100644 index a0b51d24..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/maxkey.md +++ /dev/null @@ -1,20 +0,0 @@ -# 对接 MaxKey 单点登录 -- - - - -# 安装 MaxKey 应用服务 - -参考 MaxKey 官方文档安装 [MaxKey安装部署](http://www.maxkey.top/doc/docs/intro/) - -# 配置应用 OAuth2.0 认证注册 - -![输入图片说明](https://foruda.gitee.com/images/1693377802128677240/0927270a_1766278.png "屏幕截图") - -# 配置后端服务 - -找到框架 `application-环境.yml` 配置文件 - -修改 `maxkey` 对应的 `client-id` 与 `client-secret` - -![输入图片说明](https://foruda.gitee.com/images/1693378118762354596/2f02c8a3_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1693378168538263792/24476d2a_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sensitive.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sensitive.md deleted file mode 100644 index 3e2d92ba..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sensitive.md +++ /dev/null @@ -1,33 +0,0 @@ -# 数据脱敏 -- - - -## 功能说明 - -系统使用 `Jackson` 序列化策略 对标注了 `Sensitive` 注解的属性进行脱敏处理 - -## 使用教程 - -> 使用注解标注需要脱敏的字段 选择对应的策略 - -![输入图片说明](https://foruda.gitee.com/images/1699523591703893602/ffd6dba2_1766278.png "屏幕截图") - -* strategy 脱敏策略 -* roleKey 角色code(判断用户是否拥有角色权限) -* perms 权限code(判断用户是否拥有标识符权限) - -![输入图片说明](https://foruda.gitee.com/images/1678979315796014155/614adf91_1766278.png "屏幕截图") - -> 可再 `SensitiveStrategy` 内自定义策略 - -![输入图片说明](https://foruda.gitee.com/images/1678979319996224858/3b3e3c8b_1766278.png "屏幕截图") - -## 脱敏逻辑修改 - -> 系统使用通用接口处理是否需要脱敏 多个系统可以自定义不同的脱敏逻辑实现 - -![输入图片说明](https://foruda.gitee.com/images/1678979325448998856/b262e425_1766278.png "屏幕截图") - -> 系统默认处理逻辑为 根据角色与标识符或非管理员脱敏 可自行修改默认实现 - -![输入图片说明](https://foruda.gitee.com/images/1699523752627488891/f82f2f50_1766278.png "屏幕截图") - - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/skywalking.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/skywalking.md deleted file mode 100644 index 283eb221..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/skywalking.md +++ /dev/null @@ -1,20 +0,0 @@ -# Skywalking链路监控 -- - - -## skywalking服务搭建 - -参考文章: https://lionli.blog.csdn.net/article/details/127656534
-多种搭建方式 也可以参考百度 - -## 代码改动 - -https://gitee.com/dromara/RuoYi-Vue-Plus/commit/4d02466fed4f3ea012a80c3359cde9af0737141f
-根据上方commit提交记录 开启注释掉的代码 - -## 本地使用 - -参考文章: https://lionli.blog.csdn.net/article/details/127656534 - -## docker部署使用 - -完成上方代码改动 将下载好的 `agent` 探针 放入服务器 `/docker/skywalking/agent/` 目录下 赋予所有权限即可
-![输入图片说明](https://foruda.gitee.com/images/1669032573170837535/d9901f53_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sms.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sms.md deleted file mode 100644 index a2308ecd..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sms.md +++ /dev/null @@ -1,51 +0,0 @@ -# 短信模块 -- - - - -# 配置功能 - -### 版本: >= v5.1.0 - -已完成 sms4j 项目整合 文档地址: https://sms4j.com/doc3 - -配置方式 具体厂商配置扩展 可以查看sms4j文档 - -![输入图片说明](https://foruda.gitee.com/images/1705573035997239848/2ca8512d_1766278.png "屏幕截图") - -使用方式 参考文档各种写法 下方为 demo 模块提供示例 - -![输入图片说明](https://foruda.gitee.com/images/1705573001447394180/2bd726d0_1766278.png "屏幕截图") - -### 版本: v4.2.0 提供短信模块 - -短信模块采用SPI加载
-使用哪家的短信 引入哪家的依赖 即可动态加载
-目前支持: `阿里云` `腾讯云` 欢迎扩展PR其他 - -> 参考 `ruoyi-demo` pom文件写法 - -![输入图片说明](https://foruda.gitee.com/images/1678979157797419426/cc9b7444_1766278.png "屏幕截图") - -> 修改配置文件 - -![输入图片说明](https://foruda.gitee.com/images/1678979163029635375/e5fd6e20_1766278.png "屏幕截图") - -* `enabled` 为短信功能开关 -* `endpoint` 为域名 各厂家域名固定 按照文档配置即可 -* `accessKeyId` 密钥id -* `accessKeySecret` 密钥密匙 -* `signName` 签名 -* `sdkAppId` 应用id 腾讯专用 - -## 功能使用 - -参考 `demo` 模块 `SmsController` 短信演示案例
-功能采用 `模板模式` 动态加载对应厂家的工具模板
-引入 `SmsTemplate` 即可使用 - -![输入图片说明](https://foruda.gitee.com/images/1678979168699323982/e9301e84_1766278.png "屏幕截图") - -## 重点须知 - -由于各厂家参数解析不一致 请遵守以下规则 - -![输入图片说明](https://foruda.gitee.com/images/1678979172581090456/ac1f10e8_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sse.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sse.md deleted file mode 100644 index 8a738329..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sse.md +++ /dev/null @@ -1,22 +0,0 @@ -# SSE功能 -- - - - -## 框架版本 >= 5.2.2 - -## 配置说明 - -![输入图片说明](https://foruda.gitee.com/images/1721986820599622433/1abe5d60_1766278.png "屏幕截图") - -* enabled 是否开启此功能 -* path 应用路径 - -## 使用方法 - -前端连接方式: `http://后端ip:端口/resource/sse?clientid=import.meta.env.VITE_APP_CLIENT_ID&Authorization=Bearer eyJ0eXAiO......` - -其中 `Authorization` 为请求token需要登录后获取 连接成功之后 与框架内其他获取登录用户方式一致 - -`SseMessageUtils.sendMessage` 推送单机消息(特殊需求使用)
-`SseMessageUtils.subscribeMessage` 订阅分布式消息(框架初始化已订阅)
-`SseMessageUtils.publishMessage` 发布分布式消息(推荐使用 所有集群内寻找到接收人)
-`SseMessageUtils.publishAll` 群发消息给所有连接人
\ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/topiam.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/topiam.md deleted file mode 100644 index 4778d0f9..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/topiam.md +++ /dev/null @@ -1,30 +0,0 @@ -# 对接 TOPIAM 单点登录 -- - - - -# 安装 TOPIAM 应用服务 - -参考 TOPIAM 官方文档安装 [TOPIAM安装部署](https://eiam.topiam.cn/docs/deployment/) - -# 配置 OIDC 应用 - -在 `登录 Redirect URI` 中填写 `http://localhost:80/oauth/callback?source=topiam` - -# 配置后端服务 - -找到框架 `application-环境.yml` 配置文件 - -修改 `topiam` 对应的 `client-id` 与 `client-secret` - -```yaml -justauth: - # 前端外网访问地址 - address: http://localhost:80 - type: - topiam: - # topiam 服务器地址,可在【应用配置信息】中找到 - server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol - client-id: 449c4*********937************759 - client-secret: ac7***********1e0************28d - redirect-uri: ${justauth.address}/social-callback?source=topiam - scopes: [openid] -``` \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/translation.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/translation.md deleted file mode 100644 index 547b15ff..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/translation.md +++ /dev/null @@ -1,34 +0,0 @@ -# 翻译功能 -- - - -## 框架版本 >= 4.6.0 -## 注解 - -![输入图片说明](https://foruda.gitee.com/images/1675575648043199227/d04b3e21_1766278.png "屏幕截图") - -`@Translation` 翻译注解 用于实体类字段上
-`@TranslationType` 翻译类别注解 用于实现类上标注与 `@Translation` 注解相同的 `type` 类型 实现翻译功能 - - -## 用法说明 - -默认提供功能 `用户id转账号(用户名)` `部门id转名称` `字典type转label` `ossId转url` - -![输入图片说明](https://foruda.gitee.com/images/1675575977860232549/143b74f8_1766278.png "屏幕截图") - -用户名翻译(映射翻译) 根据另一个映射字段 翻译保存到此字段 - -![输入图片说明](https://foruda.gitee.com/images/1675576044011477847/13eb9f57_1766278.png "屏幕截图") - -ossUrl翻译(直接翻译) 直接根据此字段值翻译后替换此字段值 - -![输入图片说明](https://foruda.gitee.com/images/1675576265894720924/70792f66_1766278.png "屏幕截图") - -字典翻译(其他扩展条件翻译) 根据`other`条件 自行定义如何使用 例如字典翻译`other`条件就是字典的唯一值 - -![输入图片说明](https://foruda.gitee.com/images/1675576391012282823/f95c5d78_1766278.png "屏幕截图") - -## 自定义扩展 - -实现接口 `TranslationInterface` 标注注解 `@TranslationType` 可参考框架默认实现 - -![输入图片说明](https://foruda.gitee.com/images/1676735436673932715/c3caa8d7_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/websocket.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/websocket.md deleted file mode 100644 index 9e74e1e3..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/websocket.md +++ /dev/null @@ -1,37 +0,0 @@ -# WebSocket功能 -- - - - -## 框架版本 >= 5.1.0 - -## 配置说明(默认关闭 推送建议使用SSE) - -![输入图片说明](https://foruda.gitee.com/images/1688356273985385949/5e4d1de8_1766278.png "屏幕截图") - -* enabled 是否开启此功能 -* path 应用路径 -* allowedOrigins 设置访问源地址 - -**重点: 如关闭ws功能需连同前端ws开关一同关闭 不然前端启动会报错** - -![输入图片说明](https://foruda.gitee.com/images/1700644877512019497/052d2f46_1766278.png "屏幕截图") - -## 使用方法 - -前端连接方式: `ws://后端ip:端口/resource/websocket?clientid=import.meta.env.VITE_APP_CLIENT_ID&Authorization=Bearer eyJ0eXAiO......` - -**由于js不支持请求头传输故而采用参数传输 如支持请求头传输建议使用请求头传输** - -传输方式: -```js -headers: { - Authorization: "Bearer " + getToken(), - clientid: import.meta.env.VITE_APP_CLIENT_ID -} -``` - -其中 `Authorization` 为请求token需要登录后获取 连接成功之后 与框架内其他获取登录用户方式一致 - -`WebSocketUtils.sendMessage` 推送单机消息(特殊需求使用)
-`WebSocketUtils.subscribeMessage` 订阅分布式消息(框架初始化已订阅)
-`WebSocketUtils.publishMessage` 发布分布式消息(推荐使用 所有集群内寻找到接收人)
-`WebSocketUtils.publishAll` 群发消息给所有连接人
\ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/tree.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/tree.md deleted file mode 100644 index 329cce21..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/tree.md +++ /dev/null @@ -1,61 +0,0 @@ -# 目录结构 -- - - -v5.2.2 -~~~ -RuoYi-Vue-Plus -├─ ruoyi-admin // 管理模块 [8080,28080] -│ └─ RuoYiApplication // 启动类 -│ └─ RuoYiServletInitializer // 容器部署初始化类 -│ └─ resources // 资源文件 -│ └─ i18n/messages.properties // 国际化配置文件 -│ └─ application.yml // 框架总配置文件 -│ └─ application-dev.yml // 开发环境配置文件 -│ └─ application-prod.yml // 生产环境配置文件 -│ └─ banner.txt // 框架启动图标 -│ └─ logback-plus.xml // 日志配置文件 -│ └─ ip2region.xdb // IP区域地址库 -├─ ruoyi-extend // 扩展模块 -│ └─ ruoyi-monitor-admin // admin监控模块 [9090] -│ └─ ruoyi-snailjob-server // 任务调度中心模块 [8800,17888] -├─ ruoyi-common // 通用模块 -│ └─ ruoyi-common-bom // common依赖包管理 -│ └─ ruoyi-common-core // 核心模块 -│ └─ ruoyi-common-doc // 系统接口模块 -│ └─ ruoyi-common-encrypt // 数据加解密模块 -│ └─ ruoyi-common-excel // excel模块 -│ └─ ruoyi-common-idempotent // 幂等功能模块 -│ └─ ruoyi-common-job // 定时任务模块 -│ └─ ruoyi-common-json // 序列化模块 -│ └─ ruoyi-common-log // 日志模块 -│ └─ ruoyi-common-mail // 邮件模块 -│ └─ ruoyi-common-mybatis // 数据库模块 -│ └─ ruoyi-common-oss // oss服务模块 -│ └─ ruoyi-common-ratelimiter // 限流功能模块 -│ └─ ruoyi-common-redis // 缓存服务模块 -│ └─ ruoyi-common-satoken // satoken模块 -│ └─ ruoyi-common-security // 安全模块 -│ └─ ruoyi-common-sensitive // 脱敏模块 -│ └─ ruoyi-common-sms // 短信模块 -│ └─ ruoyi-common-social // 社交三方模块 -│ └─ ruoyi-common-sse // sse流推送模块 -│ └─ ruoyi-common-tenant // 租户模块 -│ └─ ruoyi-common-translation // 通用翻译模块 -│ └─ ruoyi-common-web // web模块 -│ └─ ruoyi-common-websocket // websocket服务集成模块 -├─ ruoyi-modules // 模块组 -│ └─ ruoyi-demo // 演示模块 -│ └─ ruoyi-generator // 代码生成模块 -│ └─ ruoyi-job // 任务调度服务 -│ └─ ruoyi-system // 业务模块 -│ └─ ruoyi-workflow // 工作流模块 -├─ plus-ui // 前端框架 [80] -├─ script // 系统脚本包 -│ └─ bin // 运行脚本包 -│ └─ docker // docker相关脚本 -│ └─ sql // sql脚本 -├─ .run // 执行脚本文件 -├─ .editorconfig // 编辑器编码格式配置 -├─ LICENSE // 开源协议 -├─ pom.xml // 公共依赖 -├─ README.md // 框架说明文件 -~~~ \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/home.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/home.md deleted file mode 100644 index ff4de9ef..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/home.md +++ /dev/null @@ -1,127 +0,0 @@ - -
- -- - - -# 平台简介 -
- -[![码云Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus/badge/star.svg?theme=blue)](https://gitee.com/dromara/RuoYi-Vue-Plus) -[![GitHub](https://img.shields.io/github/stars/dromara/RuoYi-Vue-Plus.svg?style=social&label=Stars)](https://github.com/dromara/RuoYi-Vue-Plus) -[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE) -[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus) -
-[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.2.2-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus) -[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.2-blue.svg)]() -[![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]() -[![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]() - -> RuoYi-Vue-Plus 是重写 RuoYi-Vue 针对 `分布式集群与多租户` 场景全方位升级(不兼容原框架) - -> 项目代码、文档 均开源免费可商用 遵循开源协议在项目中保留开源协议文件即可
-活到老写到老 为兴趣而开源 为学习而开源 为让大家真正可以学到技术而开源 - -# 本框架与RuoYi的功能差异 - -| 功能 | 本框架 | RuoYi | -|-------------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------| -| 前端项目 | 采用 Vue3 + TS + ElementPlus 重写 | 基于Vue2/Vue3 + JS | -| 后端项目结构 | 采用插件化 + 扩展包形式 结构解耦 易于扩展 | 模块相互注入耦合严重难以扩展 | -| 后端代码风格 | 严格遵守Alibaba规范与项目统一配置的代码格式化 | 代码书写与常规结构不同阅读障碍大 | -| Web容器 | 采用 Undertow 基于 XNIO 的高性能容器 | 采用 Tomcat | -| 权限认证 | 采用 Sa-Token、Jwt 静态使用功能齐全 低耦合 高扩展 | Spring Security 配置繁琐扩展性极差 | -| 权限注解 | 采用 Sa-Token 支持注解 登录校验、角色校验、权限校验、二级认证校验、HttpBasic校验、忽略校验
角色与权限校验支持多种条件 如 `AND` `OR` 或 `权限 OR 角色` 等复杂表达式 | 只支持是否存在匹配 | -| 三方鉴权 | 采用 JustAuth 第三方登录组件 支持微信、钉钉等数十种三方认证 | 无 | -| 关系数据库支持 | 原生支持 MySQL、Oracle、PostgreSQL、SQLServer
可同时使用异构切换(支持其他 mybatis-plus 支持的所有数据库 只需要增加jdbc依赖即可使用 达梦金仓等均有成功案例) | 支持 Mysql、Oracle 不支持同时使用、不支持异构切换 | -| 缓存数据库 | 支持 Redis 5-7 支持大部分新功能特性 如 分布式限流、分布式队列 | Redis 简单 get set 支持 | -| Redis客户端 | 采用 Redisson Redis官方推荐 基于Netty的客户端工具
支持Redis 90%以上的命令 底层优化规避很多不正确的用法 例如: keys被转换为scan
支持单机、哨兵、单主集群、多主集群等模式 | Lettuce + RedisTemplate 支持模式少 工具使用繁琐
连接池采用 common-pool Bug多经常性出问题 | -| 缓存注解 | 采用 Spring-Cache 注解 对其扩展了实现支持了更多功能
例如 过期时间 最大空闲时间 组最大长度等 只需一个注解即可完成数据自动缓存 | 需手动编写Redis代码逻辑 | -| ORM框架 | 采用 Mybatis-Plus 基于对象几乎不用写SQL全java操作 功能强大插件众多
例如多租户插件 分页插件 乐观锁插件等等 | 采用 Mybatis 基于XML需要手写SQL | -| SQL监控 | 采用 p6spy 可输出完整SQL与执行时间监控 | log输出 需手动拼接sql与参数无法快速查看调试问题 | -| 数据分页 | 采用 Mybatis-Plus 分页插件
框架对其进行了扩展 对象化分页对象 支持多种方式传参 支持前端多排序 复杂排序 | 采用 PageHelper 仅支持单查询分页 参数只能从param传 只能单排序 功能扩展性差 体验不好 | -| 数据权限 | 采用 Mybatis-Plus 插件 自行分析拼接SQL 无感式过滤
只需为Mapper设置好注解条件 支持多种自定义 不限于部门角色 | 采用 注解+aop 实现 基于部门角色 生成的sql兼容性差 不支持其他业务扩展
生成sql后需手动拼接到具体业务sql上 对于多个Mapper查询不起作用 | -| 数据脱敏 | 采用 注解 + jackson 序列化期间脱敏 支持不同模块不同的脱敏条件
支持多种策略 如身份证、手机号、地址、邮箱、银行卡等 可自行扩展 | 无 | -| 数据加解密 | 采用 注解 + mybatis 拦截器 对存取数据期间自动加解密
支持多种策略 如BASE64、AES、RSA、SM2、SM4等 | 无 | -| 接口传输加密 | 采用 动态 AES + RSA 加密请求 body 每一次请求秘钥都不同大幅度降低可破解性 | 无 | -| 数据翻译 | 采用 注解 + jackson 序列化期间动态修改数据 数据进行翻译
支持多种模式: `映射翻译` `直接翻译` `其他扩展条件翻译` 接口化两步即可完成自定义扩展 内置多种翻译实现 | 无 | -| 多数据源框架 | 采用 dynamic-datasource 支持市面大部分数据库
通过yml配置即可动态管理异构不同种类的数据库 也可通过前端页面添加数据源
支持spel表达式从请求头参数等条件切换数据源 | 基于 druid 手动编写代码配置数据源 配置繁琐 支持性差 | -| 多数据源事务 | 采用 dynamic-datasource 支持多数据源不同种类的数据库事务回滚 | 不支持 | -| 数据库连接池 | 采用 HikariCP Spring官方内置连接池 配置简单 以性能与稳定性闻名天下 | 采用 druid bug众多 社区维护差 活跃度低 配置众多繁琐性能一般 | -| 数据库主键 | 采用 雪花ID 基于时间戳的 有序增长 唯一ID 再也不用为分库分表 数据合并主键冲突重复而发愁 | 采用 数据库自增ID 支持数据量有限 不支持多数据源主键唯一 | -| WebSocket协议 | 基于 Spring 封装的 WebSocket 协议 扩展了Token鉴权与分布式会话同步 不再只是基于单机的废物 | 无 | -| SSE推送 | 采用 Spring SSE 实现 扩展了Token鉴权与分布式会话同步 | 无 | -| 序列化 | 采用 Jackson Spring官方内置序列化 靠谱!!! | 采用 fastjson bugjson 远近闻名 | -| 分布式幂等 | 参考美团GTIS防重系统简化实现(细节可看文档) | 手动编写注解基于aop实现 | -| 分布式锁 | 采用 Lock4j 底层基于 Redisson | 无 | -| 分布式任务调度 | 采用 SnailJob 天生支持分布式 统一的管理中心 支持多种数据库 支持分片重试DAG任务流等 | 采用 Quartz 基于数据库锁性能差 集群需要做很多配置与改造 | -| 文件存储 | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储
支持权限管理 安全可靠 文件可加密存储 | 采用 本机文件存储 文件裸漏 易丢失泄漏 不支持集群有单点效应 | -| 云存储 | 采用 AWS S3 协议客户端 支持 七牛、阿里、腾讯 等一切支持S3协议的厂家 | 不支持 | -| 短信 | 采用 sms4j 短信融合包 支持数十种短信厂家 只需在yml配置好厂家密钥即可使用 可多厂家共用 | 不支持 | -| 邮件 | 采用 mail-api 通用协议支持大部分邮件厂商 | 不支持 | -| 接口文档 | 采用 SpringDoc、javadoc 无注解零入侵基于java注释
只需把注释写好 无需再写一大堆的文档注解了 | 采用 Springfox 已停止维护 需要编写大量的注解来支持文档生成 | -| 校验框架 | 采用 Validation 支持注解与工具类校验 注解支持国际化 | 仅支持注解 且注解不支持国际化 | -| Excel框架 | 采用 Alibaba EasyExcel 基于插件化
框架对其增加了很多功能 例如 自动合并相同内容 自动排列布局 字典翻译等 | 基于 POI 手写实现 功能有限 复杂 扩展性差 | -| 工作流支持 | 支持各种复杂审批 转办 委派 加减签 会签 或签 票签 等功能 | 无 | -| 工具类框架 | 采用 Hutool、Lombok 上百种工具覆盖90%的使用需求 基于注解自动生成 get set 等简化框架大量代码 | 手写工具稳定性差易出问题 工具数量有限 代码臃肿需自己手写 get set 等 | -| 监控框架 | 采用 SpringBoot-Admin 基于SpringBoot官方 actuator 探针机制
实时监控服务状态 框架还为其扩展了在线日志查看监控 | 无 | -| 链路追踪 | 采用 Apache SkyWalking 还在为请求不知道去哪了 到哪出了问题而烦恼吗
用了它即可实时查看请求经过的每一处每一个节点 | 无 | -| 代码生成器 | 只需设计好表结构 一键生成所有crud代码与页面
降低80%的开发量 把精力都投入到业务设计上
框架为其适配MP、SpringDoc规范化代码 同时支持动态多数据源代码生成 | 代码生成原生结构 只支持单数据源生成 | -| 部署方式 | 支持 Docker 编排 一键搭建所有环境 让开发人员从此不再为搭建环境而烦恼 | 原生jar部署 其他环境需手动下载安装 自行搭建 | -| 项目路径修改 | 提供详细的修改方案文档 并为其做了一些改动 非常简单即可修改成自己想要的 | 需要做很多改造 文档说明有限 | -| 国际化 | 基于请求头动态返回不同语种的文本内容 开发难度低 有对应的工具类 支持大部分注解内容国际化 | 只提供基础功能 其他需自行编写扩展 | -| 代码单例测试 | 提供单例测试 使用方式编写方法与maven多环境单测插件 | 只提供基础功能 其他需自行编写扩展 | -| Demo案例 | 提供框架功能的实际使用案例 单独一个模块提供了很多很全 | 无 | - - -## 本框架与RuoYi的业务差异 - -| 业务 | 功能说明 | 本框架 | RuoYi | -|--------|----------------------------------------------------------------------|-----|------------------| -| 租户管理 | 系统内租户的管理 如:租户套餐、过期时间、用户数量、企业信息等 | 支持 | 无 | -| 租户套餐管理 | 系统内租户所能使用的套餐管理 如:套餐内所包含的菜单等 | 支持 | 无 | -| 客户端管理 | 系统内对接的所有客户端管理 如: pc端、小程序端等
支持动态授权登录方式 如: 短信登录、密码登录等 支持动态控制token时效 | 支持 | 无 | -| 用户管理 | 用户的管理配置 如:新增用户、分配用户所属部门、角色、岗位等 | 支持 | 支持 | -| 部门管理 | 配置系统组织机构(公司、部门、小组) 树结构展现支持数据权限 | 支持 | 支持 | -| 岗位管理 | 配置系统用户所属担任职务 | 支持 | 支持 | -| 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等 | 支持 | 支持 | -| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 | 支持 | 支持 | -| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 | 支持 | 支持 | -| 参数管理 | 对系统动态配置常用参数 | 支持 | 支持 | -| 通知公告 | 系统通知公告信息发布维护 | 支持 | 支持 | -| 操作日志 | 系统正常操作日志记录和查询 系统异常信息日志记录和查询 | 支持 | 支持 | -| 登录日志 | 系统登录日志记录查询包含登录异常 | 支持 | 支持 | -| 文件管理 | 系统文件展示、上传、下载、删除等管理 | 支持 | 无 | -| 文件配置管理 | 系统文件上传、下载所需要的配置信息动态添加、修改、删除等管理 | 支持 | 无 | -| 在线用户管理 | 已登录系统的在线用户信息监控与强制踢出操作 | 支持 | 支持 | -| 定时任务 | 运行报表、任务管理(添加、修改、删除)、日志管理、执行器管理等 | 支持 | 仅支持任务与日志管理 | -| 代码生成 | 多数据源前后端代码的生成(java、html、xml、sql)支持CRUD下载 | 支持 | 仅支持单数据源 | -| 系统接口 | 根据业务代码自动生成相关的api接口文档 | 支持 | 支持 | -| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等 | 支持 | 仅支持单机CPU、内存、磁盘监控 | -| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | 支持 | 支持 | -| 在线构建器 | 拖动表单元素生成相应的HTML代码。 | 支持 | 支持 | -| 使用案例 | 系统的一些功能案例 | 支持 | 不支持 | - - -## 演示图例 - -| | | -|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| -| ![输入图片说明](https://foruda.gitee.com/images/1680077524361362822/270bb429_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077619939771291/989bf9b6_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680077681751513929/1c27c5bd_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077721559267315/74d63e23_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680077765638904515/1b75d4a6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078026375951297/eded7a4b_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078237104531207/0eb1b6a7_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078254306078709/5931e22f_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078287971528493/0b9af60a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078308138770249/8d3b6696_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078352553634393/db5ef880_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078378238393374/601e4357_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078414983206024/2aae27c1_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078446738419874/ecce7d59_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078475971341775/149e8634_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078491666717143/3fadece7_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078558863188826/fb8ced2a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078574561685461/ae68a0b2_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078594932772013/9d8bfec6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078626493093532/fcfe4ff6_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078643608812515/0295bd4f_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078685196286463/d7612c81_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078703877318597/56fce0bc_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078716586545643/b6dbd68f_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078734103217688/eb1e6aa6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078759131415480/73c525d8_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078779416197879/75e3ed02_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078802329118061/77e10915_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078893627848351/34a1c342_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078928175016986/f126ec4a_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078941718318363/b68a0f72_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078963175518631/3bb769a1_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680078982294090567/b31c343d_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079000642440444/77ca82a9_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680079020995074177/03b7d52e_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079039367822173/76811806_1766278.png "屏幕截图") | -| ![输入图片说明](https://foruda.gitee.com/images/1680079274333484664/4dfdc7c0_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079290467458224/d6715fcf_1766278.png "屏幕截图") | - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/4.Xinit.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/4.Xinit.md deleted file mode 100644 index 73a6dbc4..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/4.Xinit.md +++ /dev/null @@ -1,67 +0,0 @@ -# 4.X项目初始化 -- - - -### 项目分支说明 -`4.X` 主分支 4.X版本 稳定发布分支
-`fast` 单体分支 功能与主分支相同 结构为单模块
-`dev` 开发分支 代码随时更新 不推荐使用 经测试后会发布到主分支
-`future/*` 新功能预览分支
- -### 项目必备环境 -> 推荐使用 `docker` 安装 项目内置 `docker` 编排文件 -* oracle jdk 8 11 (暂时不支持 17 不支持大于 jdk8_202 因为202是最后一个免费版本) -* mysql 5.7 8.0 (5.6未适配可能会有问题) -* oracle 11g 12c -* postgres 13 14 -* sqlserver 2017 2019 -* redis 5.X 6.X 由于框架大量使用了redis特性 版本必须 >= 5.X ([win redis 下载地址](https://github.com/tporadowski/redis)) -* minio 本地文件存储 或 阿里云 腾讯云 七牛云等一切支持S3协议的云存储 -* maven 3.6.3 3.8.X -* nodejs >= 12 < 18 -* npm 6.X 8.X (7.X确认有问题) - -### 3.2.0及以上 只需勾选对应环境即可 -![输入图片说明](https://foruda.gitee.com/images/1678976284045210056/a2f28d33_1766278.png "屏幕截图") - -### 默认 `JDK1.8` 如有变动 需更改以下配置 - -![输入图片说明](https://foruda.gitee.com/images/1681017282888708602/09da902f_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1681017287160367631/3a033268_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1681017292933832275/0bdf875e_1766278.png "屏幕截图") - -### sql导入 - -请按照以下顺序依次导入 - -![输入图片说明](https://foruda.gitee.com/images/1681017239000759855/ad43a5b2_1766278.png "屏幕截图") - -默认为 `mysql` 其他数据库需导入对应的sql文件 - -![输入图片说明](https://foruda.gitee.com/images/1681017245687923510/1b444bc4_1766278.png "屏幕截图") - -**多数据库仅支持主应用 扩展应用需自行适配(例如: xxl-job仅支持mysql)** - -### 服务启动顺序说明 - -1. 必须启动基础建设: mysql redis admin
-2. 可选启动基础建设: minio(影响文件上传) monitor(影响监控) xxljob(影响定时任务)
- -![输入图片说明](https://foruda.gitee.com/images/1678976302776168895/7333341c_1766278.png "屏幕截图") - -* `MonitorAdminApplication` 为 Admin监控服务(非必要 可参考对应文档关闭) -* `XxlJobAdminApplication` 为 任务调度中心服务(非必要 可参考对应文档关闭) -* `RuoYiApplication` 为 主应用服务 -> 需优先启动 `MonitorAdminApplication` 与 `XxlJobAdminApplication` 具体配置方式参考对应文档 -> 最后启动 主服务 `RuoYiApplication` - -### 主服务配置方式 - -在勾选对应环境的配置文件内 填写 mysql 与 redis 配置信息 - -![输入图片说明](https://foruda.gitee.com/images/1678941357316005626/70559736_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1681017185596156350/d4607b5b_1766278.png "屏幕截图") - -其他数据库配置 按照系统自带的配置更改即可 - -![输入图片说明](https://foruda.gitee.com/images/1678941444707120259/b274592a_1766278.png "屏幕截图") - - diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/5.Xnew.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/5.Xnew.md deleted file mode 100644 index a966adad..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/5.Xnew.md +++ /dev/null @@ -1,5 +0,0 @@ -### 视频讲解 - -[RuoYi-Vue-Plus 5.0.0 新功能与变更介绍](https://www.bilibili.com/video/BV1Us4y1m7ky/) - -[RuoYi-Vue-Plus 5.1.0 新功能与变更介绍](https://www.bilibili.com/video/BV1fj411y71X/) diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/admin_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/admin_init.md deleted file mode 100644 index 0a317a83..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/admin_init.md +++ /dev/null @@ -1,32 +0,0 @@ -# 搭建Admin监控 -- - - -### 配置监控客户端 - -> 修改主服务配置文件 - -![输入图片说明](https://foruda.gitee.com/images/1678941504260707700/68ab99e5_1766278.png "屏幕截图") - -* `enabled` 可启用或关闭客户端注册 -* `url` 为监控中心地址 -* `username 与 password` 为监控中心的账号密码 - -### 启用监控中心 -在 `扩展项目 -> 监控模块` 启动 - -![输入图片说明](https://foruda.gitee.com/images/1678976327174539378/df97e36e_1766278.png "屏幕截图") - -在监控模块对应的 `yml` 配置文件 可设置登录的账号密码与访问路径 - -![输入图片说明](https://foruda.gitee.com/images/1678941572583282843/28117457_1766278.png "屏幕截图") - -### 前端修改admin监控访问路径 -`dev`环境 默认使用 `.env.development` 配置文件内地址 - -![输入图片说明](https://foruda.gitee.com/images/1678941607472644388/460e8eea_1766278.png "屏幕截图") - -`prod`环境 使用 `.env.production` 本机路由 - -![输入图片说明](https://foruda.gitee.com/images/1678941644784144830/6293ab1c_1766278.png "屏幕截图") -故而 `prod` 环境只需更改 `nginx` 反向代理路径即可 - -![输入图片说明](https://foruda.gitee.com/images/1678981483900657668/31fd1aad_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/deploy.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/deploy.md deleted file mode 100644 index 37e184c4..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/deploy.md +++ /dev/null @@ -1,126 +0,0 @@ -# 应用部署 -- - - -## 版本 >= 4.3.0 - -### 请优先阅读 [idea环境配置](/ruoyi-vue-plus/quickstart/idea_environment.md) - -## 手动部署 - -在服务器安装 `mysql` `redis` `nginx` `minio` - -将项目内 `script/docker/nginx/nginx.conf` 配置文件 复制到 `nginx` 配置内
-将项目内 `script/docker/redis/redis.conf` 配置文件 复制到 `redis` 配置内 - -并修改相关参数如 `前端页面存放位置` `后端Ip地址` 等使其生效 - -jar包部署后端服务 打包命令如下 - -3.2.0及以上 -```mvn -mvn clean package -D maven.test.skip=true -P prod -``` -服务器需创建临时文件存储目录与配置文件对应(无此目录上传文件会报错) - -![输入图片说明](https://foruda.gitee.com/images/1659951373949149804/屏幕截图.png "屏幕截图.png") - -前端参考下方前端部署章节 - -## 部署视频 - -[RuoYi-Vue-Plus 5.0 生产环境搭建部署](https://www.bilibili.com/video/BV1mL411e7ha/) - -## docker 后端部署 - -### 请优先阅读 [idea环境配置](/ruoyi-vue-plus/quickstart/idea_environment.md) - -**重点: 一知半解的必看** -> [docker安装](https://lionli.blog.csdn.net/article/details/83153029)
-> [docker-compose安装](https://lionli.blog.csdn.net/article/details/111220320)
-> [docker网络模式讲解](https://lionli.blog.csdn.net/article/details/109603785)
-> [docker 开启端口 2375 供外部程序访问](https://lionli.blog.csdn.net/article/details/92627962) - -### 将配置使用FTP上传到根目录 -idea拖拽文件到远程目录即可上传 - -![输入图片说明](https://foruda.gitee.com/images/1662109450908169859/eaac9299_1766278.png "屏幕截图") - -### 给docker分配文件夹权限 -**重点注意: 一定要确保目录 `/docker` 及其所有子目录 具有写权限 如果后续出现权限异常问题 重新执行一遍分配权限** - -![输入图片说明](https://foruda.gitee.com/images/1662109847279259882/3a2202c1_1766278.png "屏幕截图") -```shell -chmod -R 777 /docker -``` -### 构建应用镜像 - -**1.需要先使用maven打包成jar包** - -![输入图片说明](https://foruda.gitee.com/images/1662110477410977621/c6931c42_1766278.png "屏幕截图") - -**2.执行构建** -> 项目初始化后会自动生成构建镜像的运行配置
-> 配置好docker连接之后 运行如下即可构建对应的应用镜像 - -**重点注意: idea2024及以上版本要求必须在本地安装docker才可以执行如下操作** - -![输入图片说明](https://foruda.gitee.com/images/1662110192257483752/0f754b47_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1662120004773449909/9fdef59c_1766278.png "屏幕截图") - -**3.结构讲解** -右键编辑 即可看到内部配置 - -![输入图片说明](https://foruda.gitee.com/images/1662458355500139498/eaa26036_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1662458446794722159/32c086a7_1766278.png "屏幕截图") - - -### 创建基础服务 - -```shell -docker-compose up -d mysql nginx-web redis minio -``` - -### 创建业务服务(需要先构建服务镜像) - -4.X -```shell -docker-compose up -d ruoyi-monitor-admin ruoyi-xxl-job-admin ruoyi-server1 ruoyi-server2 -``` - -5.X -```shell -docker-compose up -d ruoyi-monitor-admin ruoyi-snailjob-server ruoyi-server1 ruoyi-server2 -``` - -### docker其他操作(idea的docker插件 推荐使用) -![输入图片说明](https://foruda.gitee.com/images/1662458271941863770/cd180a04_1766278.png "屏幕截图") - -## 前端部署 - -执行打包命令 -```shell -# 打包正式环境 -npm run build:prod -``` -打包后生成打包文件在 `ruoyi-ui/dist` 目录 -将 `dist` 目录下文件(不包含 `dist` 目录) 上传到部署服务器 `docker/nginx/html` 目录下(手动部署放入自己配置的路径即可) - -![输入图片说明](https://foruda.gitee.com/images/1662110914769648699/07f344c4_1766278.png "屏幕截图") - -重启 `nginx` 服务即可 - - -### 如需更改后端代理路径或者后端ip地址的话往下看 - -更改`nginx.conf`配置文件代理路径(注意: /开头/结尾) - -![输入图片说明](https://foruda.gitee.com/images/1660185698211067202/屏幕截图.png "屏幕截图.png") - -更改前端`.env.环境` 文件内的 `VITE_APP_BASE_API` - -![输入图片说明](https://foruda.gitee.com/images/1724318035232137124/5d035a09_1766278.png "屏幕截图") - -更改`nginx.conf`配置文件后端ip地址 - -![输入图片说明](https://foruda.gitee.com/images/1660185711265558730/屏幕截图.png "屏幕截图.png") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/extend_project.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/extend_project.md deleted file mode 100644 index 0c6f33ac..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/extend_project.md +++ /dev/null @@ -1,49 +0,0 @@ -# 基于 RuoYi-Vue-Plus 的扩展项目列表 -- - - -### 精品PR 欢迎投稿 -| 功能介绍 | PR地址 | -|-------------------------------------|------------------------------------------------------| -| 拖拽图片调整显示顺序 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/173 | -| 增加Jasypt加密库对配置文件加密 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/177 | -| 使用富文本wangeditor5替换Quill | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/213 | -| 集成screw数据库文档功能模块 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/42 | -| Excel导入模板增加批注支持 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/222 | -| 压缩包处理工具 支持本地文件/目录+oss文件/网络文件混合 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/44 | -| 添加websocket模块 支持satoken鉴权 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/65 | -| 数据库字段加解密(支持 base64 aes rsa sm2 sm4) | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/274 | -| 增加liquibase迁移数据库 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/299 | -| 增加OSS模块支持本地环境 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/353 | -| 扩展模块独立集成flyway | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/439 | -| 扩展模块独立集成go-view大屏看板 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/445 | -| 基于AmazonS3协议的分片上传 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/130 | -| 扩展forest http客户端 声明式http请求 二次封装像工具类 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/547 | -| 增加短链接生成工具 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/515 | -| 新增oss预签名上传工具组合使用异步客户端分片 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/522 | -| 新增规则引擎LiteFlow,SQL持久化接入,支持可视化页面 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/552 | -| 一键部署到私有Nexus仓库 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/181 | -| 服务状态监控发送邮件钉钉等 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/568 | -| 登录验证支持2FA验证 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/578 | - -### 项目介绍+项目地址 欢迎投稿 - - -| 项目介绍 | 项目地址 | -|--------------------------------|---------------------------------------------------------------------------| -| 微服务扩展 | https://gitee.com/dromara/RuoYi-Cloud-Plus | -| Plus学习笔记 | https://zhonglingyuxiu1028.github.io/zlyx-space/#/ruoyi-vue-plus/home | -| 基于uniapp+TmUI从0开发 支持H5/小程序/安卓 | https://gitee.com/dapppp/ruoyi-plus-miniapp | -| 基于RuoYi-App框架二次修改使用Uniapp+Vue3 | https://gitee.com/wangying110166/ruo-yi-uni-app-plus | -| 基于RuoYi-App框架对接Plus后端 | https://gitee.com/FnTop/RuoYi-App-Plus | -| 基于vben(ant-design-vue)前端项目 | https://gitee.com/dapppp/ruoyi-plus-vben | -| 基于vue-next-admin的vue3+ts前端 | https://gitee.com/thiszhc/RuoYi-Vue3-UI | -| 集成GoView版本 | https://gitee.com/kdwqjwgqxx/RuoYi-Vue-Plus-GoView | -| mybatis-flex版本 | https://gitee.com/dataprince/ruoyi-flex | -| blog博客系统 | https://gitee.com/kalashok-pan/zhi-blog-plus | -| tdengine时序数据库扩展 | https://gitee.com/zhangbg/ruoyi-plus-tdengine | -| 重构项目结构(参考springboot源码) | https://gitee.com/denghuafeng/ruoyi-boot-plus | -| Activiti扩展 | https://gitee.com/sgs98/RuoYi-Vue-Plus-Activiti | -| flowable扩展 | https://gitee.com/sgs98/RuoYi-Vue-Plus-Flowable | -| flowable扩展 | https://gitee.com/KonBAI-Q/ruoyi-flowable-plus | -| mybatis-flex版本 | https://gitee.com/yhan219/ruoyi-vue-flex | -| weblog博客系统 | https://gitee.com/fu-zhanshuai/fzshuai-weblog | -| Annlcc博客 | https://gitee.com/ahcode/ann-blog-plus | \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/idea_environment.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/idea_environment.md deleted file mode 100644 index 5995e0ff..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/idea_environment.md +++ /dev/null @@ -1,50 +0,0 @@ -# idea环境配置 -- - - -## 配置项目编码 -![输入图片说明](https://foruda.gitee.com/images/1662107706295343419/e27065a9_1766278.png "屏幕截图") - -## 配置运行看板 -![输入图片说明](https://foruda.gitee.com/images/1662108673306567278/8af97b47_1766278.png "屏幕截图") -### 配置spring与docker看板 -![输入图片说明](https://foruda.gitee.com/images/1662111392476935892/6b6760fb_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1662108865191892425/3c045999_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1662108877322329668/ddb6d93d_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1662108894122798039/6a53a38c_1766278.png "屏幕截图") - -## 配置服务器SSH连接 -进入 `Settings -> Tools -> SSH Configurations` 点击加号创建SSH连接配置
-填写 服务器IP 用户名 密码 端口号 点击 Test Connection 测试连接 - -![输入图片说明](https://foruda.gitee.com/images/1662107776533098115/bd78467b_1766278.png "屏幕截图") - -使用Terminal 工具 点击箭头找到上方创建的SSH连接配置
-选择即可进入SSH连接界面 在这里可以对服务器进行命令操作 - -![输入图片说明](https://foruda.gitee.com/images/1662108010120640495/c70f9f9a_1766278.png "屏幕截图") - -## 配置服务器FTP连接 -进入 `Settings -> Build-> Deployment` 点击加号 选择SFTP 创建 FTP 连接配置
-选择之前创建好的SSH配置 点击 Test Connection 测试连接 - -![输入图片说明](https://foruda.gitee.com/images/1662107899553257979/e2eeb7fd_1766278.png "屏幕截图") - -在IDEA上方工具栏 找到 `Tools -> Deployment -> Browse Remote Host` 打开远程界面
-点击箭头找到我们上方配置的SFTP连接配置 即可连接到服务器的文件目录 - -![输入图片说明](https://foruda.gitee.com/images/1662107974682787233/b8a601fd_1766278.png "屏幕截图") - -## 配置Docker连接 -### 可操作远程docker与构建上传docker镜像(代替原来maven docker插件) -tcp连接需要开放服务器2375端口
-ssh需要使用上方的SSH连接配置
-建议使用SSH连接 - -![输入图片说明](https://foruda.gitee.com/images/1662108188005932060/75872bf8_1766278.png "屏幕截图") - -配置好之后 在运行窗口会多出一个Docker图标 双击即可连接远程docker
-可以查看容器实时日志 启动 重启 停止 等操作 - -![输入图片说明](https://foruda.gitee.com/images/1662108250902891875/b82d022b_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/init.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/init.md deleted file mode 100644 index dba09058..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/init.md +++ /dev/null @@ -1,73 +0,0 @@ -# 5.X项目初始化 -- - - -### 项目分支说明 - -`5.X` 主分支 5.X版本 稳定发布分支
-`dev` 开发分支 代码随时更新 不推荐使用 经测试后会发布到主分支
-`future/*` 新功能预览分支
- -### 项目必备环境 -> 推荐使用 `docker` 安装 项目内置 `docker` 编排文件 - -**注意: 禁止使用 `oraclejdk`(由于spring的bug导致打包运行会报错)** - -**Spring官方推荐使用JDK https://bell-sw.com/pages/downloads/** - -![输入图片说明](https://foruda.gitee.com/images/1720080025744223375/0213a652_1766278.png "屏幕截图") - -* openjdk-17/21 或 graalvm-community-jdk-17/21 [下载地址](https://github.com/graalvm/graalvm-ce-builds/releases) 版本 -* mysql 5.7 8.0 (其他版本未测试 如其他版本没问题 可以告知咱们) -* oracle >= 12c (其他版本未测试 如其他版本没问题 可以告知咱们) -* postgres 13 14 (其他版本未测试 如其他版本没问题 可以告知咱们) -* sqlserver 2017 2019 (其他版本未测试 如其他版本没问题 可以告知咱们) -* redis 5.X 6.X 7.X 由于框架大量使用了redis特性 版本必须 >= 5.X ([win redis 下载地址](https://github.com/zkteco-home/redis-windows)) -* minio 本地文件存储 或 阿里云 腾讯云 七牛云等一切支持S3协议的云存储 -* maven >= 3.8.X -* nodejs >= 18.18 (其他版本未测试 如其他版本没问题 可以告知咱们) -* npm >= 8.X (7.X确认有问题) -* idea 2022 2024 (一定不要使用2023后果自负 bug太多影响项目开发) - -### 搭建视频 - -[RuoYi-Vue-Plus 5.0 搭建与运行](https://www.bilibili.com/video/BV1Fg4y137JK/) - -### 勾选maven对应环境 -![输入图片说明](https://foruda.gitee.com/images/1678976284045210056/a2f28d33_1766278.png "屏幕截图") - -### 默认 `JDK17` 如有变动 需更改以下配置 - -![输入图片说明](https://foruda.gitee.com/images/1678941027820943505/c688e01e_1766278.png "屏幕截图") -![输入图片说明](https://foruda.gitee.com/images/1678941120518807034/4d56fcc9_1766278.png "屏幕截图") - -### sql导入 - -请按照以下顺序依次导入 默认为 `mysql` 其他数据库需导入对应的sql文件
-如需使用其他数据库 看这里 => [多数据库数据源](../framework/extend/dynamic_datasource.md)
- -![输入图片说明](https://foruda.gitee.com/images/1725853192789853346/a0d3f0b7_1766278.png "屏幕截图") - -### 服务启动顺序说明 - -1. 必须启动基础建设: mysql redis admin
-2. 可选启动基础建设: minio(影响文件上传) monitor(影响监控) snailjob(影响定时任务)
- -![输入图片说明](https://foruda.gitee.com/images/1716175484919688429/8b9a79b7_1766278.png "屏幕截图") - -* `MonitorAdminApplication` 为 Admin监控服务(非必要 可参考对应文档关闭 [搭建Admin监控](/ruoyi-vue-plus/quickstart/admin_init.md)) -* `SnailJobServerApplication` 为 任务调度中心服务(非必要 可参考对应文档关闭 [搭建调度中心](/ruoyi-vue-plus/quickstart/snail_job_init.md)) -* `DromaraApplication` 为 主应用服务 -> 需优先启动 `MonitorAdminApplication` 与 `SnailJobServerApplication` 具体配置方式参考对应文档
-> 最后启动 主服务 `DromaraApplication`
-> 工作流相关初始化使用 [工作流初始化](/ruoyi-vue-plus/quickstart/worker_init.md) - -### 主服务配置方式 - -在勾选对应环境的配置文件内 填写 mysql 与 redis 配置信息 - -![输入图片说明](https://foruda.gitee.com/images/1678941357316005626/70559736_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1678941405169571070/0d06a955_1766278.png "屏幕截图") - -其他数据库配置 按照系统自带的配置更改即可 - -![输入图片说明](https://foruda.gitee.com/images/1678941444707120259/b274592a_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/power_job_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/power_job_init.md deleted file mode 100644 index 863971b1..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/power_job_init.md +++ /dev/null @@ -1,48 +0,0 @@ -# 搭建PowerJob任务调度中心(5.X分支已废弃) -- - - -### 废弃原因 - -接到大量投诉 使用困难 用法诡异 各种问题等 - -### 配置调度中心客户端 -> 修改主服务配置文件 -> - -![输入图片说明](https://foruda.gitee.com/images/1687656939847353725/951c1af7_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1687335574708412835/41d6c9d7_1766278.png "屏幕截图") - -* `enabled` 可启用或关闭客户端注册 -* `server-address` 为调度中心地址 -* `app-name` 为执行器组账户名(需在调度中心注册方可登录查看) - -### 启用调度中心 -**需执行 powerjob.sql 默认账号密码 `ruoyi-worker` `123456` 账号在数据库里 可以在页面修改密码** -
- -![输入图片说明](https://foruda.gitee.com/images/1688634469876143273/c89455c0_1766278.png "屏幕截图") - -> 在 `扩展项目 -> powerjob-server模块` 启动 -> -![输入图片说明](https://foruda.gitee.com/images/1687335752250147336/17abe410_1766278.png "屏幕截图") - -> 需修改配置文件数据库连接地址(**注意: 此处为ruoyi-powerjob-server服务的配置文件**) -> -![输入图片说明](https://foruda.gitee.com/images/1687335802095066722/569d92be_1766278.png "屏幕截图") - -> 也可配置邮件发送 钉钉推送 和 mongodb存储 -> -![输入图片说明](https://foruda.gitee.com/images/1687335842722317559/f875c07a_1766278.png "屏幕截图") - -### 前端修改任务调度中心访问路径 -`dev`环境 默认使用 `.env.development` 配置文件内地址 - -![输入图片说明](https://foruda.gitee.com/images/1687335909698376722/7efa7539_1766278.png "屏幕截图") - -`prod`环境 使用 `.env.production` 本机路由 - -![输入图片说明](https://foruda.gitee.com/images/1687335937599399056/dd769ef5_1766278.png "屏幕截图") - -故而 `prod` 环境只需更改 `nginx` 反向代理路径即可 - -![输入图片说明](https://foruda.gitee.com/images/1687335979933648639/6a43b749_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/snail_job_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/snail_job_init.md deleted file mode 100644 index 4c6d353b..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/snail_job_init.md +++ /dev/null @@ -1,52 +0,0 @@ -# 搭建SnailJob任务调度中心(5.2.0新功能) -- - - - -### 视频介绍 - -[Snail job任务调度中心:轻松掌握任务管理、重试机制和任务编排](https://www.bilibili.com/video/BV19i421m7GL/) - -### 配置调度中心客户端 -> 修改主服务配置文件 -> - -![输入图片说明](https://foruda.gitee.com/images/1687656939847353725/951c1af7_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1716174758437043952/de28db71_1766278.png "屏幕截图") - -* `enabled` 可启用或关闭客户端注册 -* `server.address` 为调度中心地址 -* `server.port` 为调度中心通信端口 -* `token` 为组通信校验token(可在调度中心组配置更换) -* `group-name` 为执行器组 -* `namespace` 作用域(不同作用域相互隔离请勿填错) - -### 启用调度中心 -**需执行 snail_job.sql 默认账号密码 `admin` `admin` 账号在数据库里 可以在页面修改密码** -
- -![输入图片说明](https://foruda.gitee.com/images/1714355875395308961/adc21668_1766278.png "屏幕截图") - -> 在 `ruoyi-extend -> ruoyi-snailjob-server` 模块启动 -> -![输入图片说明](https://foruda.gitee.com/images/1716174842485474283/78cec86d_1766278.png "屏幕截图") - -> 需修改配置文件数据库连接地址(**注意: 此处为ruoyi-snailjob-server服务的配置文件 支持多种不同数据库**) -> -![输入图片说明](https://foruda.gitee.com/images/1714356048711590477/13289085_1766278.png "屏幕截图") - -### 快速入门 - -[Snailjob快速入门 基本使用介绍](https://juejin.cn/post/7412955032092442675) - -### 前端修改任务调度中心访问路径 -`dev`环境 默认使用 `.env.development` 配置文件内地址 - -![输入图片说明](https://foruda.gitee.com/images/1716174933143893408/58d47bbc_1766278.png "屏幕截图") - -`prod`环境 使用 `.env.production` 本机路由 - -![输入图片说明](https://foruda.gitee.com/images/1716174973454805690/0d6f20fb_1766278.png "屏幕截图") - -故而 `prod` 环境只需更改 `nginx` 反向代理路径即可 - -![输入图片说明](https://foruda.gitee.com/images/1716174998979181179/2f9e4e4a_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/worker_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/worker_init.md deleted file mode 100644 index da09117a..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/worker_init.md +++ /dev/null @@ -1,43 +0,0 @@ -# 工作流初始化 -- - - - -### 工作流使用及配置方式 - -1.找到项目中script下bpmn文件夹 - -![输入图片说明](https://foruda.gitee.com/images/1714211764058540441/5c8b97af_5363069.png "屏幕截图") - -2.启动项目找到流程定义通过**部署流程文件**将bpmn文件夹下**模型.zip**上传 - -![输入图片说明](https://foruda.gitee.com/images/1714211950485333575/1e2b3ff4_5363069.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1714212113004821592/96586e69_5363069.png "屏幕截图") - -3.导入**模型.zip**后将会出现以下列表,默认使用**leave1**,test_leave为请假申请表名称 - -![输入图片说明](https://foruda.gitee.com/images/1714212222766335759/1227bbd6_5363069.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1714212493602552742/9e0258b1_5363069.png "屏幕截图") - -**此处表名由来与表单源码内编写的表名保持一致方可互相绑定** - -![输入图片说明](https://foruda.gitee.com/images/1716447357161482917/2c9b1639_1766278.png "屏幕截图") - - -4.新增一条请假申请,提交后将会得到如下信息 - -![输入图片说明](https://foruda.gitee.com/images/1714212617432902105/3609f6ef_5363069.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1714212630860787365/2922d38e_5363069.png "屏幕截图") - -5.关于如何切换一个新的流程使用,当前默认使用得KEY为leave1 ,我们切换到leave2使用,我们只需点击绑定业务将表名绑定,重新发起一个新的请假申请就可以得到一个新的流程信息 - -![输入图片说明](https://foruda.gitee.com/images/1714212876442323110/4554ea95_5363069.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1714213037864274694/613149f5_5363069.png "屏幕截图") - -**此处表名由来与表单源码内编写的表名保持一致方可互相绑定** - -![输入图片说明](https://foruda.gitee.com/images/1716447357161482917/2c9b1639_1766278.png "屏幕截图") - -![输入图片说明](https://foruda.gitee.com/images/1714212963457174382/add768db_5363069.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/xxl_job_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/xxl_job_init.md deleted file mode 100644 index f2751e9f..00000000 --- a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/xxl_job_init.md +++ /dev/null @@ -1,43 +0,0 @@ -# 搭建Xxl-Job任务调度中心(5.X分支已废弃) -- - - -### 废弃原因 - -长时间不维护 社区冰点 不支持jdk17 不支持boot3 不支持其他数据库等 - -### 配置调度中心客户端 -> 修改主服务配置文件 -> -![输入图片说明](https://foruda.gitee.com/images/1678941760168414366/b81e023b_1766278.png "屏幕截图") - -* `enabled` 可启用或关闭客户端注册 -* `admin-addresses` 为调度中心地址 -* `access-token` 为调度中心交互鉴权token -* `executor` 为执行器配置 一个客户端为一个执行器 可配置执行器集群 使用分片任务处理 - -### 启用调度中心 -**默认账号密码 `admin` `123456` 账号在数据库里 可以在页面修改密码** - -> 在 `扩展项目 -> xxl-job-admin模块` 启动 -> -![输入图片说明](https://foruda.gitee.com/images/1678976353500205883/058fef13_1766278.png "屏幕截图") - -> 需修改配置文件数据库连接地址(**注意: 此处为xxl-job-admin服务的配置文件**) -> -![输入图片说明](https://foruda.gitee.com/images/1678941813423551656/04c32a5b_1766278.png "屏幕截图") - -> 也可配置邮件发送 -> -![输入图片说明](https://foruda.gitee.com/images/1678941825447455298/1baa5e43_1766278.png "屏幕截图") - -### 前端修改任务调度中心访问路径 -`dev`环境 默认使用 `.env.development` 配置文件内地址 - -![输入图片说明](https://foruda.gitee.com/images/1678976378255854583/8cdbf4e3_1766278.png "屏幕截图") - -`prod`环境 使用 `.env.production` 本机路由 - -![输入图片说明](https://foruda.gitee.com/images/1678976382819019066/96288331_1766278.png "屏幕截图") - -故而 `prod` 环境只需更改 `nginx` 反向代理路径即可 - -![输入图片说明](https://foruda.gitee.com/images/1678976386764602366/55894f85_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/static/css/vue.css b/ruoyi-admin/src/main/resources/static/static/css/vue.css deleted file mode 100644 index 847f385a..00000000 --- a/ruoyi-admin/src/main/resources/static/static/css/vue.css +++ /dev/null @@ -1 +0,0 @@ -@import url("https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600");*{-webkit-font-smoothing:antialiased;-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:none;-webkit-touch-callout:none;box-sizing:border-box}body:not(.ready){overflow:hidden}body:not(.ready) .app-nav,body:not(.ready)>nav,body:not(.ready) [data-cloak]{display:none}div#app{font-size:30px;font-weight:lighter;margin:40vh auto;text-align:center}div#app:empty:before{content:"Loading..."}img.emoji{height:1.2em}img.emoji,span.emoji{vertical-align:middle}span.emoji{font-family:Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-size:1.2em}.progress{background-color:#42b983;background-color:var(--theme-color,#42b983);height:2px;left:0;position:fixed;right:0;top:0;transition:width .2s,opacity .4s;width:0;z-index:999999}.search .search-keyword,.search a:hover{color:#42b983;color:var(--theme-color,#42b983)}.search .search-keyword{font-style:normal;font-weight:700}body,html{height:100%}body{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;color:#34495e;font-family:Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:15px;letter-spacing:0;margin:0;overflow-x:hidden}img{max-width:100%}a[disabled]{cursor:not-allowed;opacity:.6}kbd{border:1px solid #ccc;border-radius:3px;display:inline-block;font-size:12px!important;line-height:12px;margin-bottom:3px;padding:3px 5px;vertical-align:middle}li input[type=checkbox]{margin:0 .2em .25em 0;vertical-align:middle}.app-nav{margin:25px 60px 0 0;position:absolute;right:0;text-align:right;z-index:10}.app-nav.no-badge{margin-right:25px}.app-nav p{margin:0}.app-nav>a{margin:0 1rem;padding:5px 0}.app-nav li,.app-nav ul{display:inline-block;list-style:none;margin:0}.app-nav a{color:inherit;font-size:16px;text-decoration:none;transition:color .3s}.app-nav a.active,.app-nav a:hover{color:#42b983;color:var(--theme-color,#42b983)}.app-nav a.active{border-bottom:2px solid #42b983;border-bottom:2px solid var(--theme-color,#42b983)}.app-nav li{display:inline-block;margin:0 1rem;padding:5px 0;position:relative;cursor:pointer}.app-nav li ul{background-color:#fff;border:1px solid;border-color:#ddd #ddd #ccc;border-radius:4px;box-sizing:border-box;display:none;max-height:calc(100vh - 61px);overflow-y:auto;padding:10px 0;position:absolute;right:-15px;text-align:left;top:100%;white-space:nowrap}.app-nav li ul li{display:block;font-size:14px;line-height:1rem;margin:8px 14px;white-space:nowrap}.app-nav li ul a{display:block;font-size:inherit;margin:0;padding:0}.app-nav li ul a.active{border-bottom:0}.app-nav li:hover ul{display:block}.github-corner{border-bottom:0;position:fixed;right:0;text-decoration:none;top:0;z-index:1}.github-corner:hover .octo-arm{animation:octocat-wave .56s ease-in-out}.github-corner svg{color:#fff;fill:#42b983;fill:var(--theme-color,#42b983);height:80px;width:80px}main{display:block;position:relative;width:100vw;height:100%;z-index:0}main.hidden{display:none}.anchor{display:inline-block;text-decoration:none;transition:all .3s}.anchor span{color:#34495e}.anchor:hover{text-decoration:underline}.sidebar{border-right:1px solid rgba(0,0,0,.07);overflow-y:auto;padding:40px 0 0;position:absolute;top:0;bottom:0;left:0;transition:transform .25s ease-out;width:300px;z-index:20}.sidebar>h1{margin:0 auto 1rem;font-size:1.5rem;font-weight:300;text-align:center}.sidebar>h1 a{color:inherit;text-decoration:none}.sidebar>h1 .app-nav{display:block;position:static}.sidebar .sidebar-nav{line-height:2em;padding-bottom:40px}.sidebar li.collapse .app-sub-sidebar{display:none}.sidebar ul{margin:0 0 0 15px;padding:0}.sidebar li>p{font-weight:700;margin:0}.sidebar ul,.sidebar ul li{list-style:none}.sidebar ul li a{border-bottom:none;display:block}.sidebar ul li ul{padding-left:20px}.sidebar::-webkit-scrollbar{width:4px}.sidebar::-webkit-scrollbar-thumb{background:transparent;border-radius:4px}.sidebar:hover::-webkit-scrollbar-thumb{background:hsla(0,0%,53.3%,.4)}.sidebar:hover::-webkit-scrollbar-track{background:hsla(0,0%,53.3%,.1)}.sidebar-toggle{background-color:transparent;background-color:hsla(0,0%,100%,.8);border:0;outline:none;padding:10px;position:absolute;bottom:0;left:0;text-align:center;transition:opacity .3s;width:284px;z-index:30;cursor:pointer}.sidebar-toggle:hover .sidebar-toggle-button{opacity:.4}.sidebar-toggle span{background-color:#42b983;background-color:var(--theme-color,#42b983);display:block;margin-bottom:4px;width:16px;height:2px}body.sticky .sidebar,body.sticky .sidebar-toggle{position:fixed}.content{padding-top:60px;position:absolute;top:0;right:0;bottom:0;left:300px;transition:left .25s ease}.markdown-section{margin:0 auto;max-width:80%;padding:30px 15px 40px;position:relative}.markdown-section>*{box-sizing:border-box;font-size:inherit}.markdown-section>:first-child{margin-top:0!important}.markdown-section hr{border:none;border-bottom:1px solid #eee;margin:2em 0}.markdown-section iframe{border:1px solid #eee;width:1px;min-width:100%}.markdown-section table{border-collapse:collapse;border-spacing:0;display:block;margin-bottom:1rem;overflow:auto;width:100%}.markdown-section th{font-weight:700}.markdown-section td,.markdown-section th{border:1px solid #ddd;padding:6px 13px}.markdown-section tr{border-top:1px solid #ccc}.markdown-section p.tip,.markdown-section tr:nth-child(2n){background-color:#f8f8f8}.markdown-section p.tip{border-bottom-right-radius:2px;border-left:4px solid #f66;border-top-right-radius:2px;margin:2em 0;padding:12px 24px 12px 30px;position:relative}.markdown-section p.tip:before{background-color:#f66;border-radius:100%;color:#fff;content:"!";font-family:Dosis,Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:14px;font-weight:700;left:-12px;line-height:20px;position:absolute;height:20px;width:20px;text-align:center;top:14px}.markdown-section p.tip code{background-color:#efefef}.markdown-section p.tip em{color:#34495e}.markdown-section p.warn{background:rgba(66,185,131,.1);border-radius:2px;padding:1rem}.markdown-section ul.task-list>li{list-style-type:none}body.close .sidebar{transform:translateX(-300px)}body.close .sidebar-toggle{width:auto}body.close .content{left:0}@media print{.app-nav,.github-corner,.sidebar,.sidebar-toggle{display:none}}@media screen and (max-width:768px){.github-corner,.sidebar,.sidebar-toggle{position:fixed}.app-nav{margin-top:16px}.app-nav li ul{top:30px}main{height:auto;min-height:100vh;overflow-x:hidden}.sidebar{left:-300px;transition:transform .25s ease-out}.content{left:0;max-width:100vw;position:static;padding-top:20px;transition:transform .25s ease}.app-nav,.github-corner{transition:transform .25s ease-out}.sidebar-toggle{background-color:transparent;width:auto;padding:30px 30px 10px 10px}body.close .sidebar{transform:translateX(300px)}body.close .sidebar-toggle{background-color:hsla(0,0%,100%,.8);transition:background-color 1s;width:284px;padding:10px}body.close .content{transform:translateX(300px)}body.close .app-nav,body.close .github-corner{display:none}.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave .56s ease-in-out}}@keyframes octocat-wave{0%,to{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}section.cover{position:relative;align-items:center;background-position:50%;background-repeat:no-repeat;background-size:cover;min-height:100vh;width:100%;display:none}section.cover.show{display:flex}section.cover.has-mask .mask{background-color:#fff;opacity:.8;position:absolute;top:0;bottom:0;width:100%}section.cover .cover-main{flex:1;margin:0 16px;text-align:center;position:relative}section.cover a{color:inherit}section.cover a,section.cover a:hover{text-decoration:none}section.cover p{line-height:1.5rem;margin:1em 0}section.cover h1{color:inherit;font-size:2.5rem;font-weight:300;margin:.625rem 0 2.5rem;position:relative;text-align:center}section.cover h1 a{display:block}section.cover h1 small{bottom:-.4375rem;font-size:1rem;position:absolute}section.cover blockquote{font-size:1.5rem;text-align:center}section.cover ul{line-height:1.8;list-style-type:none;margin:1em auto;max-width:500px;padding:0}section.cover .cover-main>p:last-child a{border-radius:2rem;border:1px solid #42b983;border-color:var(--theme-color,#42b983);box-sizing:border-box;color:#42b983;color:var(--theme-color,#42b983);display:inline-block;font-size:1.05rem;letter-spacing:.1rem;margin:.5rem 1rem;padding:.75em 2rem;text-decoration:none;transition:all .15s ease}section.cover .cover-main>p:last-child a:last-child{background-color:#42b983;background-color:var(--theme-color,#42b983);color:#fff}section.cover .cover-main>p:last-child a:last-child:hover{color:inherit;opacity:.8}section.cover .cover-main>p:last-child a:hover{color:inherit}section.cover blockquote>p>a{border-bottom:2px solid #42b983;border-bottom:2px solid var(--theme-color,#42b983);transition:color .3s}section.cover blockquote>p>a:hover{color:#42b983;color:var(--theme-color,#42b983)}.sidebar,body{background-color:#fff}.sidebar{color:#364149}.sidebar li{margin:6px 0}.sidebar ul li a{color:#505d6b;font-size:14px;font-weight:400;overflow:hidden;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.sidebar ul li a:hover{text-decoration:underline}.sidebar ul li ul{padding:0}.sidebar ul li.active>a{border-right:2px solid;color:#42b983;color:var(--theme-color,#42b983);font-weight:600}.app-sub-sidebar li:before{content:"-";padding-right:4px;float:left}.markdown-section h1,.markdown-section h2,.markdown-section h3,.markdown-section h4,.markdown-section strong{color:#2c3e50;font-weight:600}.markdown-section a{color:#42b983;color:var(--theme-color,#42b983);font-weight:600}.markdown-section h1{font-size:2rem;margin:0 0 1rem}.markdown-section h2{font-size:1.75rem;margin:45px 0 .8rem}.markdown-section h3{font-size:1.5rem;margin:40px 0 .6rem}.markdown-section h4{font-size:1.25rem}.markdown-section h5{font-size:1rem}.markdown-section h6{color:#777;font-size:1rem}.markdown-section figure,.markdown-section p{margin:1.2em 0}.markdown-section ol,.markdown-section p,.markdown-section ul{line-height:1.6rem;word-spacing:.05rem}.markdown-section ol,.markdown-section ul{padding-left:1.5rem}.markdown-section blockquote{border-left:4px solid #42b983;border-left:4px solid var(--theme-color,#42b983);color:#858585;margin:2em 0;padding-left:20px}.markdown-section blockquote p{font-weight:600;margin-left:0}.markdown-section iframe{margin:1em 0}.markdown-section em{color:#7f8c8d}.markdown-section code,.markdown-section output:after,.markdown-section pre{font-family:Roboto Mono,Monaco,courier,monospace}.markdown-section code,.markdown-section pre{background-color:#f8f8f8}.markdown-section output,.markdown-section pre{margin:1.2em 0;position:relative}.markdown-section output,.markdown-section pre>code{border-radius:2px;display:block}.markdown-section output:after,.markdown-section pre>code{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial}.markdown-section code{border-radius:2px;color:#e96900;margin:0 2px;padding:3px 5px;white-space:pre-wrap}.markdown-section>:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) code{font-size:.8rem}.markdown-section pre{padding:0 1.4rem;line-height:1.5rem;overflow:auto;word-wrap:normal}.markdown-section pre>code{color:#525252;font-size:.8rem;padding:2.2em 5px;line-height:inherit;margin:0 2px;max-width:inherit;overflow:inherit;white-space:inherit}.markdown-section output{padding:1.7rem 1.4rem;border:1px dotted #ccc}.markdown-section output>:first-child{margin-top:0}.markdown-section output>:last-child{margin-bottom:0}.markdown-section code:after,.markdown-section code:before,.markdown-section output:after,.markdown-section output:before{letter-spacing:.05rem}.markdown-section output:after,.markdown-section pre:after{color:#ccc;font-size:.6rem;font-weight:600;height:15px;line-height:15px;padding:5px 10px 0;position:absolute;right:0;text-align:right;top:0;content:attr(data-lang)}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8e908c}.token.namespace{opacity:.7}.token.boolean,.token.number{color:#c76b29}.token.punctuation{color:#525252}.token.property{color:#c08b30}.token.tag{color:#2973b7}.token.string{color:#42b983;color:var(--theme-color,#42b983)}.token.selector{color:#6679cc}.token.attr-name{color:#2973b7}.language-css .token.string,.style .token.string,.token.entity,.token.url{color:#22a2c9}.token.attr-value,.token.control,.token.directive,.token.unit{color:#42b983;color:var(--theme-color,#42b983)}.token.function,.token.keyword{color:#e96900}.token.atrule,.token.regex,.token.statement{color:#22a2c9}.token.placeholder,.token.variable{color:#3d8fd1}.token.deleted{text-decoration:line-through}.token.inserted{border-bottom:1px dotted #202746;text-decoration:none}.token.italic{font-style:italic}.token.bold,.token.important{font-weight:700}.token.important{color:#c94922}.token.entity{cursor:help}code .token{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;min-height:1.5rem;position:relative;left:auto} \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/static/image/favicon.ico b/ruoyi-admin/src/main/resources/static/static/image/favicon.ico deleted file mode 100644 index 3f919d85..00000000 Binary files a/ruoyi-admin/src/main/resources/static/static/image/favicon.ico and /dev/null differ diff --git a/ruoyi-admin/src/main/resources/static/static/image/logo.png b/ruoyi-admin/src/main/resources/static/static/image/logo.png deleted file mode 100644 index 306851c1..00000000 Binary files a/ruoyi-admin/src/main/resources/static/static/image/logo.png and /dev/null differ diff --git a/ruoyi-admin/src/main/resources/static/static/image/ruoyicloudplus.png b/ruoyi-admin/src/main/resources/static/static/image/ruoyicloudplus.png deleted file mode 100644 index cc697e6d..00000000 Binary files a/ruoyi-admin/src/main/resources/static/static/image/ruoyicloudplus.png and /dev/null differ diff --git a/ruoyi-admin/src/main/resources/static/static/image/ruoyivueplus.png b/ruoyi-admin/src/main/resources/static/static/image/ruoyivueplus.png deleted file mode 100644 index d0eba10d..00000000 Binary files a/ruoyi-admin/src/main/resources/static/static/image/ruoyivueplus.png and /dev/null differ diff --git a/ruoyi-admin/src/main/resources/static/static/js/docsify-copy-code.min.js b/ruoyi-admin/src/main/resources/static/static/js/docsify-copy-code.min.js deleted file mode 100644 index 02a83a31..00000000 --- a/ruoyi-admin/src/main/resources/static/static/js/docsify-copy-code.min.js +++ /dev/null @@ -1,9 +0,0 @@ -/*! - * docsify-copy-code - * v3.0.0 - * https://github.com/jperasmus/docsify-copy-code - * (c) 2017-2023 JP Erasmus - * MIT license - */ -!function(){"use strict";function e(o){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e(o)}!function(e,o){void 0===o&&(o={});var t=o.insertAt;if(e&&"undefined"!=typeof document){var n=document.head||document.getElementsByTagName("head")[0],c=document.createElement("style");c.type="text/css","top"===t&&n.firstChild?n.insertBefore(c,n.firstChild):n.appendChild(c),c.styleSheet?c.styleSheet.cssText=e:c.appendChild(document.createTextNode(e))}}(".docsify-copy-code-button,.docsify-copy-code-button>span{cursor:pointer;transition:all .25s ease}.docsify-copy-code-button{background:grey;background:var(--theme-color,grey);border:0;border-radius:0;color:#fff;font-size:1em;opacity:0;outline:0;overflow:visible;padding:.65em .8em;position:absolute;right:0;top:0;z-index:1}.docsify-copy-code-button>span{background:inherit;border-radius:3px;pointer-events:none}.docsify-copy-code-button>.error,.docsify-copy-code-button>.success{font-size:.825em;opacity:0;padding:.5em .65em;position:absolute;right:0;top:50%;transform:translateY(-50%);z-index:-100}.docsify-copy-code-button.error>.error,.docsify-copy-code-button.success>.success{opacity:1;right:100%;transform:translate(-25%,-50%)}.docsify-copy-code-button:focus,pre:hover .docsify-copy-code-button{opacity:1}.docsify-copy-code-button>[aria-live]{height:1px;left:-10000px;overflow:hidden;position:absolute;top:auto;width:1px}"),document.querySelector('link[href*="docsify-copy-code"]')&&console.warn("[Deprecation] Link to external docsify-copy-code stylesheet is no longer necessary."),window.DocsifyCopyCodePlugin={init:function(){return function(e,o){e.ready((function(){console.warn("[Deprecation] Manually initializing docsify-copy-code using window.DocsifyCopyCodePlugin.init() is no longer necessary.")}))}}},window.$docsify=window.$docsify||{},window.$docsify.plugins=[function(o,t){var n={buttonText:"Copy to clipboard",errorText:"Error",successText:"Copied"};o.doneEach((function(){var o=Array.from(document.querySelectorAll("pre[data-lang]"));t.config.copyCode&&Object.keys(n).forEach((function(o){var c=t.config.copyCode[o];"string"==typeof c?n[o]=c:"object"===e(c)&&Object.keys(c).some((function(e){var t=location.href.indexOf(e)>-1;return n[o]=t?c[e]:n[o],t}))}));var c=['"].join("");o.forEach((function(e){e.insertAdjacentHTML("beforeend",c)}))})),o.mounted((function(){var e=document.querySelector(".content");e&&e.addEventListener("click",(function(e){if(e.target.classList.contains("docsify-copy-code-button")){var o="BUTTON"===e.target.tagName?e.target:e.target.parentNode,t=document.createRange(),c=o.parentNode.querySelector("code"),i=o.querySelector("[aria-live]"),r=window.getSelection();t.selectNode(c),r&&(r.removeAllRanges(),r.addRange(t));try{document.execCommand("copy")&&(o.classList.add("success"),i.innerText=n.successText,setTimeout((function(){o.classList.remove("success"),i.innerText=""}),1e3))}catch(e){console.error("docsify-copy-code: ".concat(e)),o.classList.add("error"),i.innerText=n.errorText,setTimeout((function(){o.classList.remove("error"),i.innerText=""}),1e3)}(r=window.getSelection())&&("function"==typeof r.removeRange?r.removeRange(t):"function"==typeof r.removeAllRanges&&r.removeAllRanges())}}))}))}].concat(window.$docsify.plugins||[])}(); -//# sourceMappingURL=docsify-copy-code.min.js.map \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/static/js/docsify-footer.min.js b/ruoyi-admin/src/main/resources/static/static/js/docsify-footer.min.js deleted file mode 100644 index b4262116..00000000 --- a/ruoyi-admin/src/main/resources/static/static/js/docsify-footer.min.js +++ /dev/null @@ -1,4 +0,0 @@ -parcelRequire=function(e,r,t,n){var i,o="function"==typeof parcelRequire&&parcelRequire,u="function"==typeof require&&require;function f(t,n){if(!r[t]){if(!e[t]){var i="function"==typeof parcelRequire&&parcelRequire;if(!n&&i)return i(t,!0);if(o)return o(t,!0);if(u&&"string"==typeof t)return u(t);var c=new Error("Cannot find module '"+t+"'");throw c.code="MODULE_NOT_FOUND",c}p.resolve=function(r){return e[t][1][r]||r},p.cache={};var l=r[t]=new f.Module(t);e[t][0].call(l.exports,p,l,l.exports,this)}return r[t].exports;function p(e){return f(p.resolve(e))}}f.isParcelRequire=!0,f.Module=function(e){this.id=e,this.bundle=f,this.exports={}},f.modules=e,f.cache=r,f.parent=o,f.register=function(r,t){e[r]=[function(e,r){r.exports=t},{}]};for(var c=0;c ul > li"),c("p",e)),this.hyperlink=m(t))}var b=function(){return'
'},k=function(t,e){a=e,r=t.route.path,o={},["previousText","nextText"].forEach(function(n){var i=a[n];"string"==typeof i?o[n]=i:Object.keys(i).some(function(t){var e=r&&-1\n \n
\n \n \n \n '+i+'\n
\n
'+t.prev.name+"
\n ",t.prev&&e.crossChapterText&&'
'+t.prev.chapterName+"
",t.prev&&"
\n \n ",t.next&&'\n \n "].filter(Boolean).join("")};window.$docsify=window.$docsify||{},window.$docsify.plugins=[function(t,e){var n=d({},(e.config,{previousText:"PREVIOUS",nextText:"NEXT",crossChapter:!1,crossChapterText:!1}),e.config.pagination||{});function i(){var t=c("."+h);t&&(t.innerHTML=k(function(t,e){e=e.crossChapter;try{var n=t.router.toURL(t.route.path),i=g(c.all(".sidebar-nav li a")).filter(function(t){return!s(t,".section-link")}),a=i.find(x(n)),r=g((p(a,"ul")||{}).children).filter(function(t){return"LI"===t.tagName.toUpperCase()}),o=e?i.findIndex(x(n)):r.findIndex(function(t){t=m(t);return t&&x(n,t)}),l=e?i:r;return{route:t.route,prev:new y(l[o-1]).toJSON(),next:new y(l[o+1]).toJSON()}}catch(t){return{route:{}}}}(e,n),n))}t.afterEach(function(t){return t+b()}),t.doneEach(i)}].concat(window.$docsify.plugins||[])}); \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/static/js/docsify-scroll-to-top.min.js b/ruoyi-admin/src/main/resources/static/static/js/docsify-scroll-to-top.min.js deleted file mode 100644 index c5ed3ca2..00000000 --- a/ruoyi-admin/src/main/resources/static/static/js/docsify-scroll-to-top.min.js +++ /dev/null @@ -1 +0,0 @@ -var CONFIG={auto:true,text:"Top",right:15,bottom:15,offset:500};var install=function(hook,vm){var opts=vm.config.scrollToTop||CONFIG;CONFIG.auto=opts.auto&&typeof opts.auto==="boolean"?opts.auto:CONFIG.auto;CONFIG.text=opts.text&&typeof opts.text==="string"?opts.text:CONFIG.text;CONFIG.right=opts.right&&typeof opts.right==="number"?opts.right:CONFIG.right;CONFIG.bottom=opts.bottom&&typeof opts.bottom==="number"?opts.bottom:CONFIG.bottom;CONFIG.offset=opts.offset&&typeof opts.offset==="number"?opts.offset:CONFIG.offset;var onScroll=function(e){if(!CONFIG.auto){return}var offset=window.document.documentElement.scrollTop;var $scrollBtn=Docsify.dom.find("span.scroll-to-top");$scrollBtn.style.display=offset>=CONFIG.offset?"block":"none"};hook.mounted(function(){var scrollBtn=document.createElement("span");scrollBtn.className="scroll-to-top";scrollBtn.style.display=CONFIG.auto?"none":"block";scrollBtn.style.overflow="hidden";scrollBtn.style.position="fixed";scrollBtn.style.right=CONFIG.right+"px";scrollBtn.style.bottom=CONFIG.bottom+"px";scrollBtn.style.width="50px";scrollBtn.style.height="50px";scrollBtn.style.background="white";scrollBtn.style.color="#666";scrollBtn.style.border="1px solid #ddd";scrollBtn.style.borderRadius="4px";scrollBtn.style.lineHeight="42px";scrollBtn.style.fontSize="16px";scrollBtn.style.textAlign="center";scrollBtn.style.boxShadow="0px 0px 6px #eee";scrollBtn.style.cursor="pointer";var textNode=document.createTextNode(CONFIG.text);scrollBtn.appendChild(textNode);document.body.appendChild(scrollBtn);window.addEventListener("scroll",onScroll);scrollBtn.onclick=function(e){e.stopPropagation();var step=window.scrollY/15;var scroll=function(){window.scrollTo(0,window.scrollY-step);if(window.scrollY>0){setTimeout(scroll,15)}};scroll()}})};$docsify.plugins=[].concat(install,$docsify.plugins); \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/static/js/docsify.min.js b/ruoyi-admin/src/main/resources/static/static/js/docsify.min.js deleted file mode 100644 index 18e85aa9..00000000 --- a/ruoyi-admin/src/main/resources/static/static/js/docsify.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(){function c(i){var o=Object.create(null);return function(e){var n=f(e)?e:JSON.stringify(e);return o[n]||(o[n]=i(e))}}var a=c(function(e){return e.replace(/([A-Z])/g,function(e){return"-"+e.toLowerCase()})}),u=Object.prototype.hasOwnProperty,m=Object.assign||function(e){for(var n=arguments,i=1;i=e||n.classList.contains("hidden")?S(h,"add","sticky"):S(h,"remove","sticky"))}function ee(e,n,o,i){var t=[];null!=(n=l(n))&&(t=k(n,"a"));var a,r=decodeURI(e.toURL(e.getCurrentPath()));return t.sort(function(e,n){return n.href.length-e.href.length}).forEach(function(e){var n=decodeURI(e.getAttribute("href")),i=o?e.parentNode:e;e.title=e.title||e.innerText,0!==r.indexOf(n)||a?S(i,"remove","active"):(a=e,S(i,"add","active"))}),i&&(v.title=a?a.title||a.innerText+" - "+J:J),a}function ne(e,n){for(var i=0;ithis.end&&e>=this.next}[this.direction]}},{key:"_defaultEase",value:function(e,n,i,o){return(e/=o/2)<1?i/2*e*e+n:-i/2*(--e*(e-2)-1)+n}}]),re);function re(){var e=0c){n=n||p;break}n=p}!n||(r=fe[ve(e,n.getAttribute("data-id"))])&&r!==a&&(a&&a.classList.remove("active"),r.classList.add("active"),a=r,!pe&&h.classList.contains("sticky")&&(e=i.clientHeight,r=a.offsetTop+a.clientHeight+40,a=a.offsetTop>=t.scrollTop&&r<=t.scrollTop+e,i.scrollTop=a?t.scrollTop:+r"']/),xe=/[&<>"']/g,Se=/[<>"']|&(?!#?\w+;)/,Ae=/[<>"']|&(?!#?\w+;)/g,$e={"&":"&","<":"<",">":">",'"':""","'":"'"};var ze=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function Fe(e){return e.replace(ze,function(e,n){return"colon"===(n=n.toLowerCase())?":":"#"===n.charAt(0)?"x"===n.charAt(1)?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1)):""})}var Ee=/(^|[^\[])\^/g;var Re=/[^\w:]/g,Te=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var Ce={},je=/^[^:]+:\/*[^/]*$/,Le=/^([^:]+:)[\s\S]*$/,Oe=/^([^:]+:\/*[^/]*)[\s\S]*$/;function qe(e,n){Ce[" "+e]||(je.test(e)?Ce[" "+e]=e+"/":Ce[" "+e]=Pe(e,"/",!0));var i=-1===(e=Ce[" "+e]).indexOf(":");return"//"===n.substring(0,2)?i?n:e.replace(Le,"$1")+n:"/"===n.charAt(0)?i?n:e.replace(Oe,"$1")+n:e+n}function Pe(e,n,i){var o=e.length;if(0===o)return"";for(var t=0;tn)i.splice(n);else for(;i.length>=1,e+=e;return i+e},We=we.defaults,Xe=Be,Qe=Ze,Je=Me,Ke=Ve;function en(e,n,i){var o=n.href,t=n.title?Je(n.title):null,n=e[1].replace(/\\([\[\]])/g,"$1");return"!"!==e[0].charAt(0)?{type:"link",raw:i,href:o,title:t,text:n}:{type:"image",raw:i,href:o,title:t,text:Je(n)}}var nn=function(){function e(e){this.options=e||We}return e.prototype.space=function(e){e=this.rules.block.newline.exec(e);if(e)return 1=i.length?e.slice(i.length):e}).join("\n")}(i,n[3]||"");return{type:"code",raw:i,lang:n[2]&&n[2].trim(),text:e}}},e.prototype.heading=function(e){var n=this.rules.block.heading.exec(e);if(n){var i=n[2].trim();return/#$/.test(i)&&(e=Xe(i,"#"),!this.options.pedantic&&e&&!/ $/.test(e)||(i=e.trim())),{type:"heading",raw:n[0],depth:n[1].length,text:i}}},e.prototype.nptable=function(e){e=this.rules.block.nptable.exec(e);if(e){var n={type:"table",header:Qe(e[1].replace(/^ *| *\| *$/g,"")),align:e[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:e[3]?e[3].replace(/\n$/,"").split("\n"):[],raw:e[0]};if(n.header.length===n.align.length){for(var i=n.align.length,o=0;o ?/gm,"");return{type:"blockquote",raw:n[0],text:e}}},e.prototype.list=function(e){e=this.rules.block.list.exec(e);if(e){for(var n,i,o,t,a,r=e[0],c=e[2],u=1s[1].length:o[1].length>s[0].length||3/i.test(e[0])&&(n=!1),!i&&/^<(pre|code|kbd|script)(\s|>)/i.test(e[0])?i=!0:i&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(e[0])&&(i=!1),{type:this.options.sanitize?"text":"html",raw:e[0],inLink:n,inRawBlock:i,text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(e[0]):Je(e[0]):e[0]}},e.prototype.link=function(e){var n=this.rules.inline.link.exec(e);if(n){e=n[2].trim();if(!this.options.pedantic&&/^$/.test(e))return;var i=Xe(e.slice(0,-1),"\\");if((e.length-i.length)%2==0)return}else{var o=Ke(n[2],"()");-1$/.test(e)?i.slice(1):i.slice(1,-1):i)&&i.replace(this.rules.inline._escapes,"$1"),title:o&&o.replace(this.rules.inline._escapes,"$1")},n[0])}},e.prototype.reflink=function(e,n){if((i=this.rules.inline.reflink.exec(e))||(i=this.rules.inline.nolink.exec(e))){var e=(i[2]||i[1]).replace(/\s+/g," ");if((e=n[e.toLowerCase()])&&e.href)return en(i,e,i[0]);var i=i[0].charAt(0);return{type:"text",raw:i,text:i}}},e.prototype.strong=function(e,n,i){void 0===i&&(i="");var o=this.rules.inline.strong.start.exec(e);if(o&&(!o[1]||o[1]&&(""===i||this.rules.inline.punctuation.exec(i)))){n=n.slice(-1*e.length);var t,a="**"===o[0]?this.rules.inline.strong.endAst:this.rules.inline.strong.endUnd;for(a.lastIndex=0;null!=(o=a.exec(n));)if(t=this.rules.inline.strong.middle.exec(n.slice(0,o.index+3)))return{type:"strong",raw:e.slice(0,t[0].length),text:e.slice(2,t[0].length-2)}}},e.prototype.em=function(e,n,i){void 0===i&&(i="");var o=this.rules.inline.em.start.exec(e);if(o&&(!o[1]||o[1]&&(""===i||this.rules.inline.punctuation.exec(i)))){n=n.slice(-1*e.length);var t,a="*"===o[0]?this.rules.inline.em.endAst:this.rules.inline.em.endUnd;for(a.lastIndex=0;null!=(o=a.exec(n));)if(t=this.rules.inline.em.middle.exec(n.slice(0,o.index+2)))return{type:"em",raw:e.slice(0,t[0].length),text:e.slice(1,t[0].length-1)}}},e.prototype.codespan=function(e){var n=this.rules.inline.code.exec(e);if(n){var i=n[2].replace(/\n/g," "),o=/[^ ]/.test(i),e=/^ /.test(i)&&/ $/.test(i);return o&&e&&(i=i.substring(1,i.length-1)),i=Je(i,!0),{type:"codespan",raw:n[0],text:i}}},e.prototype.br=function(e){e=this.rules.inline.br.exec(e);if(e)return{type:"br",raw:e[0]}},e.prototype.del=function(e){e=this.rules.inline.del.exec(e);if(e)return{type:"del",raw:e[0],text:e[2]}},e.prototype.autolink=function(e,n){e=this.rules.inline.autolink.exec(e);if(e){var i,n="@"===e[2]?"mailto:"+(i=Je(this.options.mangle?n(e[1]):e[1])):i=Je(e[1]);return{type:"link",raw:e[0],text:i,href:n,tokens:[{type:"text",raw:i,text:i}]}}},e.prototype.url=function(e,n){var i,o,t,a;if(i=this.rules.inline.url.exec(e)){if("@"===i[2])t="mailto:"+(o=Je(this.options.mangle?n(i[0]):i[0]));else{for(;a=i[0],i[0]=this.rules.inline._backpedal.exec(i[0])[0],a!==i[0];);o=Je(i[0]),t="www."===i[1]?"http://"+o:o}return{type:"link",raw:i[0],text:o,href:t,tokens:[{type:"text",raw:o,text:o}]}}},e.prototype.inlineText=function(e,n,i){e=this.rules.inline.text.exec(e);if(e){i=n?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(e[0]):Je(e[0]):e[0]:Je(this.options.smartypants?i(e[0]):e[0]);return{type:"text",raw:e[0],text:i}}},e}(),Ze=De,Ve=Ne,De=Ue,Ne={newline:/^(?: *(?:\n|$))+/,code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,fences:/^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?! {0,3}bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,nptable:Ze,table:Ze,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};Ne.def=Ve(Ne.def).replace("label",Ne._label).replace("title",Ne._title).getRegex(),Ne.bullet=/(?:[*+-]|\d{1,9}[.)])/,Ne.item=/^( *)(bull) ?[^\n]*(?:\n(?! *bull ?)[^\n]*)*/,Ne.item=Ve(Ne.item,"gm").replace(/bull/g,Ne.bullet).getRegex(),Ne.listItemStart=Ve(/^( *)(bull)/).replace("bull",Ne.bullet).getRegex(),Ne.list=Ve(Ne.list).replace(/bull/g,Ne.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+Ne.def.source+")").getRegex(),Ne._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",Ne._comment=/|$)/,Ne.html=Ve(Ne.html,"i").replace("comment",Ne._comment).replace("tag",Ne._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),Ne.paragraph=Ve(Ne._paragraph).replace("hr",Ne.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",Ne._tag).getRegex(),Ne.blockquote=Ve(Ne.blockquote).replace("paragraph",Ne.paragraph).getRegex(),Ne.normal=De({},Ne),Ne.gfm=De({},Ne.normal,{nptable:"^ *([^|\\n ].*\\|.*)\\n {0,3}([-:]+ *\\|[-| :]*)(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)",table:"^ *\\|(.+)\\n {0,3}\\|?( *[-:]+[-| :]*)(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),Ne.gfm.nptable=Ve(Ne.gfm.nptable).replace("hr",Ne.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",Ne._tag).getRegex(),Ne.gfm.table=Ve(Ne.gfm.table).replace("hr",Ne.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",Ne._tag).getRegex(),Ne.pedantic=De({},Ne.normal,{html:Ve("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",Ne._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:Ze,paragraph:Ve(Ne.normal._paragraph).replace("hr",Ne.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",Ne.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});Ze={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:Ze,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,reflinkSearch:"reflink|nolink(?!\\()",strong:{start:/^(?:(\*\*(?=[*punctuation]))|\*\*)(?![\s])|__/,middle:/^\*\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*\*$|^__(?![\s])((?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?)__$/,endAst:/[^punctuation\s]\*\*(?!\*)|[punctuation]\*\*(?!\*)(?:(?=[punctuation_\s]|$))/,endUnd:/[^\s]__(?!_)(?:(?=[punctuation*\s])|$)/},em:{start:/^(?:(\*(?=[punctuation]))|\*)(?![*\s])|_/,middle:/^\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*$|^_(?![_\s])(?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?_$/,endAst:/[^punctuation\s]\*(?!\*)|[punctuation]\*(?!\*)(?:(?=[punctuation_\s]|$))/,endUnd:/[^\s]_(?!_)(?:(?=[punctuation*\s])|$)/},code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:Ze,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\?@\\[\\]`^{|}~"};Ze.punctuation=Ve(Ze.punctuation).replace(/punctuation/g,Ze._punctuation).getRegex(),Ze._blockSkip="\\[[^\\]]*?\\]\\([^\\)]*?\\)|`[^`]*?`|<[^>]*?>",Ze._overlapSkip="__[^_]*?__|\\*\\*\\[^\\*\\]*?\\*\\*",Ze._comment=Ve(Ne._comment).replace("(?:--\x3e|$)","--\x3e").getRegex(),Ze.em.start=Ve(Ze.em.start).replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.em.middle=Ve(Ze.em.middle).replace(/punctuation/g,Ze._punctuation).replace(/overlapSkip/g,Ze._overlapSkip).getRegex(),Ze.em.endAst=Ve(Ze.em.endAst,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.em.endUnd=Ve(Ze.em.endUnd,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.strong.start=Ve(Ze.strong.start).replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.strong.middle=Ve(Ze.strong.middle).replace(/punctuation/g,Ze._punctuation).replace(/overlapSkip/g,Ze._overlapSkip).getRegex(),Ze.strong.endAst=Ve(Ze.strong.endAst,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.strong.endUnd=Ve(Ze.strong.endUnd,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.blockSkip=Ve(Ze._blockSkip,"g").getRegex(),Ze.overlapSkip=Ve(Ze._overlapSkip,"g").getRegex(),Ze._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,Ze._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,Ze._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,Ze.autolink=Ve(Ze.autolink).replace("scheme",Ze._scheme).replace("email",Ze._email).getRegex(),Ze._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,Ze.tag=Ve(Ze.tag).replace("comment",Ze._comment).replace("attribute",Ze._attribute).getRegex(),Ze._label=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,Ze._href=/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/,Ze._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,Ze.link=Ve(Ze.link).replace("label",Ze._label).replace("href",Ze._href).replace("title",Ze._title).getRegex(),Ze.reflink=Ve(Ze.reflink).replace("label",Ze._label).getRegex(),Ze.reflinkSearch=Ve(Ze.reflinkSearch,"g").replace("reflink",Ze.reflink).replace("nolink",Ze.nolink).getRegex(),Ze.normal=De({},Ze),Ze.pedantic=De({},Ze.normal,{strong:{start:/^__|\*\*/,middle:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,endAst:/\*\*(?!\*)/g,endUnd:/__(?!_)/g},em:{start:/^_|\*/,middle:/^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,endAst:/\*(?!\*)/g,endUnd:/_(?!_)/g},link:Ve(/^!?\[(label)\]\((.*?)\)/).replace("label",Ze._label).getRegex(),reflink:Ve(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",Ze._label).getRegex()}),Ze.gfm=De({},Ze.normal,{escape:Ve(Ze.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\'+(i?e:gn(e,!0))+"\n":"
"+(i?e:gn(e,!0))+"
\n"},e.prototype.blockquote=function(e){return"
\n"+e+"
\n"},e.prototype.html=function(e){return e},e.prototype.heading=function(e,n,i,o){return this.options.headerIds?"'+e+"\n":""+e+"\n"},e.prototype.hr=function(){return this.options.xhtml?"
\n":"
\n"},e.prototype.list=function(e,n,i){var o=n?"ol":"ul";return"<"+o+(n&&1!==i?' start="'+i+'"':"")+">\n"+e+"\n"},e.prototype.listitem=function(e){return"
  • "+e+"
  • \n"},e.prototype.checkbox=function(e){return" "},e.prototype.paragraph=function(e){return"

    "+e+"

    \n"},e.prototype.table=function(e,n){return"\n\n"+e+"\n"+(n=n&&""+n+"")+"
    \n"},e.prototype.tablerow=function(e){return"\n"+e+"\n"},e.prototype.tablecell=function(e,n){var i=n.header?"th":"td";return(n.align?"<"+i+' align="'+n.align+'">':"<"+i+">")+e+"\n"},e.prototype.strong=function(e){return""+e+""},e.prototype.em=function(e){return""+e+""},e.prototype.codespan=function(e){return""+e+""},e.prototype.br=function(){return this.options.xhtml?"
    ":"
    "},e.prototype.del=function(e){return""+e+""},e.prototype.link=function(e,n,i){if(null===(e=dn(this.options.sanitize,this.options.baseUrl,e)))return i;e='"},e.prototype.image=function(e,n,i){if(null===(e=dn(this.options.sanitize,this.options.baseUrl,e)))return i;i=''+i+'":">"},e.prototype.text=function(e){return e},e}(),ln=function(){function e(){}return e.prototype.strong=function(e){return e},e.prototype.em=function(e){return e},e.prototype.codespan=function(e){return e},e.prototype.del=function(e){return e},e.prototype.html=function(e){return e},e.prototype.text=function(e){return e},e.prototype.link=function(e,n,i){return""+i},e.prototype.image=function(e,n,i){return""+i},e.prototype.br=function(){return""},e}(),vn=function(){function e(){this.seen={}}return e.prototype.serialize=function(e){return e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-")},e.prototype.getNextSafeSlug=function(e,n){var i=e,o=0;if(this.seen.hasOwnProperty(i))for(o=this.seen[e];i=e+"-"+ ++o,this.seen.hasOwnProperty(i););return n||(this.seen[e]=o,this.seen[i]=0),i},e.prototype.slug=function(e,n){void 0===n&&(n={});e=this.serialize(e);return this.getNextSafeSlug(e,n.dryrun)},e}(),hn=we.defaults,_n=Ie,mn=function(){function i(e){this.options=e||hn,this.options.renderer=this.options.renderer||new sn,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new ln,this.slugger=new vn}return i.parse=function(e,n){return new i(n).parse(e)},i.parseInline=function(e,n){return new i(n).parseInline(e)},i.prototype.parse=function(e,n){void 0===n&&(n=!0);for(var i,o,t,a,r,c,u,f,p,d,g,s,l,v,h,_="",m=e.length,b=0;bAn error occurred:

    "+wn(e.message+"",!0)+"
    ";throw e}}xn.options=xn.setOptions=function(e){return bn(xn.defaults,e),yn(xn.defaults),xn},xn.getDefaults=Me,xn.defaults=we,xn.use=function(a){var n,e=bn({},a);if(a.renderer){var i,r=xn.defaults.renderer||new sn;for(i in a.renderer)!function(o){var t=r[o];r[o]=function(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];var i=a.renderer[o].apply(r,e);return i=!1===i?t.apply(r,e):i}}(i);e.renderer=r}if(a.tokenizer){var t,c=xn.defaults.tokenizer||new nn;for(t in a.tokenizer)!function(){var o=c[t];c[t]=function(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];var i=a.tokenizer[t].apply(c,e);return i=!1===i?o.apply(c,e):i}}();e.tokenizer=c}a.walkTokens&&(n=xn.defaults.walkTokens,e.walkTokens=function(e){a.walkTokens(e),n&&n(e)}),xn.setOptions(e)},xn.walkTokens=function(e,n){for(var i=0,o=e;iAn error occurred:

    "+wn(e.message+"",!0)+"
    ";throw e}},xn.Parser=mn,xn.parser=mn.parse,xn.Renderer=sn,xn.TextRenderer=ln,xn.Lexer=fn,xn.lexer=fn.lex,xn.Tokenizer=nn,xn.Slugger=vn;var Sn=xn.parse=xn;function An(e,i){if(void 0===i&&(i='
      {inner}
    '),!e||!e.length)return"";var o="";return e.forEach(function(e){var n=e.title.replace(/(<([^>]+)>)/g,"");o+='
  • '+e.title+"
  • ",e.children&&(o+=An(e.children,i))}),i.replace("{inner}",o)}function $n(e,n){return'

    '+n.slice(5).trim()+"

    "}function zn(e,o){var t=[],a={};return e.forEach(function(e){var n=e.level||1,i=n-1;o?@[\]^`{|}~]/g;function Rn(e){return e.toLowerCase()}function Tn(e){if("string"!=typeof e)return"";var n=e.trim().replace(/[A-Z]+/g,Rn).replace(/<[^>]+>/g,"").replace(En,"").replace(/\s/g,"-").replace(/-+/g,"-").replace(/^(\d)/,"_$1"),e=Fn[n],e=u.call(Fn,n)?e+1:0;return n=(Fn[n]=e)?n+"-"+e:n}Tn.clear=function(){Fn={}};var Cn={baseURL:"https://github.githubassets.com/images/icons/emoji/",data:{100:"unicode/1f4af.png?v8",1234:"unicode/1f522.png?v8","+1":"unicode/1f44d.png?v8","-1":"unicode/1f44e.png?v8","1st_place_medal":"unicode/1f947.png?v8","2nd_place_medal":"unicode/1f948.png?v8","3rd_place_medal":"unicode/1f949.png?v8","8ball":"unicode/1f3b1.png?v8",a:"unicode/1f170.png?v8",ab:"unicode/1f18e.png?v8",abacus:"unicode/1f9ee.png?v8",abc:"unicode/1f524.png?v8",abcd:"unicode/1f521.png?v8",accept:"unicode/1f251.png?v8",accessibility:"accessibility.png?v8",accordion:"unicode/1fa97.png?v8",adhesive_bandage:"unicode/1fa79.png?v8",adult:"unicode/1f9d1.png?v8",aerial_tramway:"unicode/1f6a1.png?v8",afghanistan:"unicode/1f1e6-1f1eb.png?v8",airplane:"unicode/2708.png?v8",aland_islands:"unicode/1f1e6-1f1fd.png?v8",alarm_clock:"unicode/23f0.png?v8",albania:"unicode/1f1e6-1f1f1.png?v8",alembic:"unicode/2697.png?v8",algeria:"unicode/1f1e9-1f1ff.png?v8",alien:"unicode/1f47d.png?v8",ambulance:"unicode/1f691.png?v8",american_samoa:"unicode/1f1e6-1f1f8.png?v8",amphora:"unicode/1f3fa.png?v8",anatomical_heart:"unicode/1fac0.png?v8",anchor:"unicode/2693.png?v8",andorra:"unicode/1f1e6-1f1e9.png?v8",angel:"unicode/1f47c.png?v8",anger:"unicode/1f4a2.png?v8",angola:"unicode/1f1e6-1f1f4.png?v8",angry:"unicode/1f620.png?v8",anguilla:"unicode/1f1e6-1f1ee.png?v8",anguished:"unicode/1f627.png?v8",ant:"unicode/1f41c.png?v8",antarctica:"unicode/1f1e6-1f1f6.png?v8",antigua_barbuda:"unicode/1f1e6-1f1ec.png?v8",apple:"unicode/1f34e.png?v8",aquarius:"unicode/2652.png?v8",argentina:"unicode/1f1e6-1f1f7.png?v8",aries:"unicode/2648.png?v8",armenia:"unicode/1f1e6-1f1f2.png?v8",arrow_backward:"unicode/25c0.png?v8",arrow_double_down:"unicode/23ec.png?v8",arrow_double_up:"unicode/23eb.png?v8",arrow_down:"unicode/2b07.png?v8",arrow_down_small:"unicode/1f53d.png?v8",arrow_forward:"unicode/25b6.png?v8",arrow_heading_down:"unicode/2935.png?v8",arrow_heading_up:"unicode/2934.png?v8",arrow_left:"unicode/2b05.png?v8",arrow_lower_left:"unicode/2199.png?v8",arrow_lower_right:"unicode/2198.png?v8",arrow_right:"unicode/27a1.png?v8",arrow_right_hook:"unicode/21aa.png?v8",arrow_up:"unicode/2b06.png?v8",arrow_up_down:"unicode/2195.png?v8",arrow_up_small:"unicode/1f53c.png?v8",arrow_upper_left:"unicode/2196.png?v8",arrow_upper_right:"unicode/2197.png?v8",arrows_clockwise:"unicode/1f503.png?v8",arrows_counterclockwise:"unicode/1f504.png?v8",art:"unicode/1f3a8.png?v8",articulated_lorry:"unicode/1f69b.png?v8",artificial_satellite:"unicode/1f6f0.png?v8",artist:"unicode/1f9d1-1f3a8.png?v8",aruba:"unicode/1f1e6-1f1fc.png?v8",ascension_island:"unicode/1f1e6-1f1e8.png?v8",asterisk:"unicode/002a-20e3.png?v8",astonished:"unicode/1f632.png?v8",astronaut:"unicode/1f9d1-1f680.png?v8",athletic_shoe:"unicode/1f45f.png?v8",atm:"unicode/1f3e7.png?v8",atom:"atom.png?v8",atom_symbol:"unicode/269b.png?v8",australia:"unicode/1f1e6-1f1fa.png?v8",austria:"unicode/1f1e6-1f1f9.png?v8",auto_rickshaw:"unicode/1f6fa.png?v8",avocado:"unicode/1f951.png?v8",axe:"unicode/1fa93.png?v8",azerbaijan:"unicode/1f1e6-1f1ff.png?v8",b:"unicode/1f171.png?v8",baby:"unicode/1f476.png?v8",baby_bottle:"unicode/1f37c.png?v8",baby_chick:"unicode/1f424.png?v8",baby_symbol:"unicode/1f6bc.png?v8",back:"unicode/1f519.png?v8",bacon:"unicode/1f953.png?v8",badger:"unicode/1f9a1.png?v8",badminton:"unicode/1f3f8.png?v8",bagel:"unicode/1f96f.png?v8",baggage_claim:"unicode/1f6c4.png?v8",baguette_bread:"unicode/1f956.png?v8",bahamas:"unicode/1f1e7-1f1f8.png?v8",bahrain:"unicode/1f1e7-1f1ed.png?v8",balance_scale:"unicode/2696.png?v8",bald_man:"unicode/1f468-1f9b2.png?v8",bald_woman:"unicode/1f469-1f9b2.png?v8",ballet_shoes:"unicode/1fa70.png?v8",balloon:"unicode/1f388.png?v8",ballot_box:"unicode/1f5f3.png?v8",ballot_box_with_check:"unicode/2611.png?v8",bamboo:"unicode/1f38d.png?v8",banana:"unicode/1f34c.png?v8",bangbang:"unicode/203c.png?v8",bangladesh:"unicode/1f1e7-1f1e9.png?v8",banjo:"unicode/1fa95.png?v8",bank:"unicode/1f3e6.png?v8",bar_chart:"unicode/1f4ca.png?v8",barbados:"unicode/1f1e7-1f1e7.png?v8",barber:"unicode/1f488.png?v8",baseball:"unicode/26be.png?v8",basecamp:"basecamp.png?v8",basecampy:"basecampy.png?v8",basket:"unicode/1f9fa.png?v8",basketball:"unicode/1f3c0.png?v8",basketball_man:"unicode/26f9-2642.png?v8",basketball_woman:"unicode/26f9-2640.png?v8",bat:"unicode/1f987.png?v8",bath:"unicode/1f6c0.png?v8",bathtub:"unicode/1f6c1.png?v8",battery:"unicode/1f50b.png?v8",beach_umbrella:"unicode/1f3d6.png?v8",bear:"unicode/1f43b.png?v8",bearded_person:"unicode/1f9d4.png?v8",beaver:"unicode/1f9ab.png?v8",bed:"unicode/1f6cf.png?v8",bee:"unicode/1f41d.png?v8",beer:"unicode/1f37a.png?v8",beers:"unicode/1f37b.png?v8",beetle:"unicode/1fab2.png?v8",beginner:"unicode/1f530.png?v8",belarus:"unicode/1f1e7-1f1fe.png?v8",belgium:"unicode/1f1e7-1f1ea.png?v8",belize:"unicode/1f1e7-1f1ff.png?v8",bell:"unicode/1f514.png?v8",bell_pepper:"unicode/1fad1.png?v8",bellhop_bell:"unicode/1f6ce.png?v8",benin:"unicode/1f1e7-1f1ef.png?v8",bento:"unicode/1f371.png?v8",bermuda:"unicode/1f1e7-1f1f2.png?v8",beverage_box:"unicode/1f9c3.png?v8",bhutan:"unicode/1f1e7-1f1f9.png?v8",bicyclist:"unicode/1f6b4.png?v8",bike:"unicode/1f6b2.png?v8",biking_man:"unicode/1f6b4-2642.png?v8",biking_woman:"unicode/1f6b4-2640.png?v8",bikini:"unicode/1f459.png?v8",billed_cap:"unicode/1f9e2.png?v8",biohazard:"unicode/2623.png?v8",bird:"unicode/1f426.png?v8",birthday:"unicode/1f382.png?v8",bison:"unicode/1f9ac.png?v8",black_cat:"unicode/1f408-2b1b.png?v8",black_circle:"unicode/26ab.png?v8",black_flag:"unicode/1f3f4.png?v8",black_heart:"unicode/1f5a4.png?v8",black_joker:"unicode/1f0cf.png?v8",black_large_square:"unicode/2b1b.png?v8",black_medium_small_square:"unicode/25fe.png?v8",black_medium_square:"unicode/25fc.png?v8",black_nib:"unicode/2712.png?v8",black_small_square:"unicode/25aa.png?v8",black_square_button:"unicode/1f532.png?v8",blond_haired_man:"unicode/1f471-2642.png?v8",blond_haired_person:"unicode/1f471.png?v8",blond_haired_woman:"unicode/1f471-2640.png?v8",blonde_woman:"unicode/1f471-2640.png?v8",blossom:"unicode/1f33c.png?v8",blowfish:"unicode/1f421.png?v8",blue_book:"unicode/1f4d8.png?v8",blue_car:"unicode/1f699.png?v8",blue_heart:"unicode/1f499.png?v8",blue_square:"unicode/1f7e6.png?v8",blueberries:"unicode/1fad0.png?v8",blush:"unicode/1f60a.png?v8",boar:"unicode/1f417.png?v8",boat:"unicode/26f5.png?v8",bolivia:"unicode/1f1e7-1f1f4.png?v8",bomb:"unicode/1f4a3.png?v8",bone:"unicode/1f9b4.png?v8",book:"unicode/1f4d6.png?v8",bookmark:"unicode/1f516.png?v8",bookmark_tabs:"unicode/1f4d1.png?v8",books:"unicode/1f4da.png?v8",boom:"unicode/1f4a5.png?v8",boomerang:"unicode/1fa83.png?v8",boot:"unicode/1f462.png?v8",bosnia_herzegovina:"unicode/1f1e7-1f1e6.png?v8",botswana:"unicode/1f1e7-1f1fc.png?v8",bouncing_ball_man:"unicode/26f9-2642.png?v8",bouncing_ball_person:"unicode/26f9.png?v8",bouncing_ball_woman:"unicode/26f9-2640.png?v8",bouquet:"unicode/1f490.png?v8",bouvet_island:"unicode/1f1e7-1f1fb.png?v8",bow:"unicode/1f647.png?v8",bow_and_arrow:"unicode/1f3f9.png?v8",bowing_man:"unicode/1f647-2642.png?v8",bowing_woman:"unicode/1f647-2640.png?v8",bowl_with_spoon:"unicode/1f963.png?v8",bowling:"unicode/1f3b3.png?v8",bowtie:"bowtie.png?v8",boxing_glove:"unicode/1f94a.png?v8",boy:"unicode/1f466.png?v8",brain:"unicode/1f9e0.png?v8",brazil:"unicode/1f1e7-1f1f7.png?v8",bread:"unicode/1f35e.png?v8",breast_feeding:"unicode/1f931.png?v8",bricks:"unicode/1f9f1.png?v8",bride_with_veil:"unicode/1f470-2640.png?v8",bridge_at_night:"unicode/1f309.png?v8",briefcase:"unicode/1f4bc.png?v8",british_indian_ocean_territory:"unicode/1f1ee-1f1f4.png?v8",british_virgin_islands:"unicode/1f1fb-1f1ec.png?v8",broccoli:"unicode/1f966.png?v8",broken_heart:"unicode/1f494.png?v8",broom:"unicode/1f9f9.png?v8",brown_circle:"unicode/1f7e4.png?v8",brown_heart:"unicode/1f90e.png?v8",brown_square:"unicode/1f7eb.png?v8",brunei:"unicode/1f1e7-1f1f3.png?v8",bubble_tea:"unicode/1f9cb.png?v8",bucket:"unicode/1faa3.png?v8",bug:"unicode/1f41b.png?v8",building_construction:"unicode/1f3d7.png?v8",bulb:"unicode/1f4a1.png?v8",bulgaria:"unicode/1f1e7-1f1ec.png?v8",bullettrain_front:"unicode/1f685.png?v8",bullettrain_side:"unicode/1f684.png?v8",burkina_faso:"unicode/1f1e7-1f1eb.png?v8",burrito:"unicode/1f32f.png?v8",burundi:"unicode/1f1e7-1f1ee.png?v8",bus:"unicode/1f68c.png?v8",business_suit_levitating:"unicode/1f574.png?v8",busstop:"unicode/1f68f.png?v8",bust_in_silhouette:"unicode/1f464.png?v8",busts_in_silhouette:"unicode/1f465.png?v8",butter:"unicode/1f9c8.png?v8",butterfly:"unicode/1f98b.png?v8",cactus:"unicode/1f335.png?v8",cake:"unicode/1f370.png?v8",calendar:"unicode/1f4c6.png?v8",call_me_hand:"unicode/1f919.png?v8",calling:"unicode/1f4f2.png?v8",cambodia:"unicode/1f1f0-1f1ed.png?v8",camel:"unicode/1f42b.png?v8",camera:"unicode/1f4f7.png?v8",camera_flash:"unicode/1f4f8.png?v8",cameroon:"unicode/1f1e8-1f1f2.png?v8",camping:"unicode/1f3d5.png?v8",canada:"unicode/1f1e8-1f1e6.png?v8",canary_islands:"unicode/1f1ee-1f1e8.png?v8",cancer:"unicode/264b.png?v8",candle:"unicode/1f56f.png?v8",candy:"unicode/1f36c.png?v8",canned_food:"unicode/1f96b.png?v8",canoe:"unicode/1f6f6.png?v8",cape_verde:"unicode/1f1e8-1f1fb.png?v8",capital_abcd:"unicode/1f520.png?v8",capricorn:"unicode/2651.png?v8",car:"unicode/1f697.png?v8",card_file_box:"unicode/1f5c3.png?v8",card_index:"unicode/1f4c7.png?v8",card_index_dividers:"unicode/1f5c2.png?v8",caribbean_netherlands:"unicode/1f1e7-1f1f6.png?v8",carousel_horse:"unicode/1f3a0.png?v8",carpentry_saw:"unicode/1fa9a.png?v8",carrot:"unicode/1f955.png?v8",cartwheeling:"unicode/1f938.png?v8",cat:"unicode/1f431.png?v8",cat2:"unicode/1f408.png?v8",cayman_islands:"unicode/1f1f0-1f1fe.png?v8",cd:"unicode/1f4bf.png?v8",central_african_republic:"unicode/1f1e8-1f1eb.png?v8",ceuta_melilla:"unicode/1f1ea-1f1e6.png?v8",chad:"unicode/1f1f9-1f1e9.png?v8",chains:"unicode/26d3.png?v8",chair:"unicode/1fa91.png?v8",champagne:"unicode/1f37e.png?v8",chart:"unicode/1f4b9.png?v8",chart_with_downwards_trend:"unicode/1f4c9.png?v8",chart_with_upwards_trend:"unicode/1f4c8.png?v8",checkered_flag:"unicode/1f3c1.png?v8",cheese:"unicode/1f9c0.png?v8",cherries:"unicode/1f352.png?v8",cherry_blossom:"unicode/1f338.png?v8",chess_pawn:"unicode/265f.png?v8",chestnut:"unicode/1f330.png?v8",chicken:"unicode/1f414.png?v8",child:"unicode/1f9d2.png?v8",children_crossing:"unicode/1f6b8.png?v8",chile:"unicode/1f1e8-1f1f1.png?v8",chipmunk:"unicode/1f43f.png?v8",chocolate_bar:"unicode/1f36b.png?v8",chopsticks:"unicode/1f962.png?v8",christmas_island:"unicode/1f1e8-1f1fd.png?v8",christmas_tree:"unicode/1f384.png?v8",church:"unicode/26ea.png?v8",cinema:"unicode/1f3a6.png?v8",circus_tent:"unicode/1f3aa.png?v8",city_sunrise:"unicode/1f307.png?v8",city_sunset:"unicode/1f306.png?v8",cityscape:"unicode/1f3d9.png?v8",cl:"unicode/1f191.png?v8",clamp:"unicode/1f5dc.png?v8",clap:"unicode/1f44f.png?v8",clapper:"unicode/1f3ac.png?v8",classical_building:"unicode/1f3db.png?v8",climbing:"unicode/1f9d7.png?v8",climbing_man:"unicode/1f9d7-2642.png?v8",climbing_woman:"unicode/1f9d7-2640.png?v8",clinking_glasses:"unicode/1f942.png?v8",clipboard:"unicode/1f4cb.png?v8",clipperton_island:"unicode/1f1e8-1f1f5.png?v8",clock1:"unicode/1f550.png?v8",clock10:"unicode/1f559.png?v8",clock1030:"unicode/1f565.png?v8",clock11:"unicode/1f55a.png?v8",clock1130:"unicode/1f566.png?v8",clock12:"unicode/1f55b.png?v8",clock1230:"unicode/1f567.png?v8",clock130:"unicode/1f55c.png?v8",clock2:"unicode/1f551.png?v8",clock230:"unicode/1f55d.png?v8",clock3:"unicode/1f552.png?v8",clock330:"unicode/1f55e.png?v8",clock4:"unicode/1f553.png?v8",clock430:"unicode/1f55f.png?v8",clock5:"unicode/1f554.png?v8",clock530:"unicode/1f560.png?v8",clock6:"unicode/1f555.png?v8",clock630:"unicode/1f561.png?v8",clock7:"unicode/1f556.png?v8",clock730:"unicode/1f562.png?v8",clock8:"unicode/1f557.png?v8",clock830:"unicode/1f563.png?v8",clock9:"unicode/1f558.png?v8",clock930:"unicode/1f564.png?v8",closed_book:"unicode/1f4d5.png?v8",closed_lock_with_key:"unicode/1f510.png?v8",closed_umbrella:"unicode/1f302.png?v8",cloud:"unicode/2601.png?v8",cloud_with_lightning:"unicode/1f329.png?v8",cloud_with_lightning_and_rain:"unicode/26c8.png?v8",cloud_with_rain:"unicode/1f327.png?v8",cloud_with_snow:"unicode/1f328.png?v8",clown_face:"unicode/1f921.png?v8",clubs:"unicode/2663.png?v8",cn:"unicode/1f1e8-1f1f3.png?v8",coat:"unicode/1f9e5.png?v8",cockroach:"unicode/1fab3.png?v8",cocktail:"unicode/1f378.png?v8",coconut:"unicode/1f965.png?v8",cocos_islands:"unicode/1f1e8-1f1e8.png?v8",coffee:"unicode/2615.png?v8",coffin:"unicode/26b0.png?v8",coin:"unicode/1fa99.png?v8",cold_face:"unicode/1f976.png?v8",cold_sweat:"unicode/1f630.png?v8",collision:"unicode/1f4a5.png?v8",colombia:"unicode/1f1e8-1f1f4.png?v8",comet:"unicode/2604.png?v8",comoros:"unicode/1f1f0-1f1f2.png?v8",compass:"unicode/1f9ed.png?v8",computer:"unicode/1f4bb.png?v8",computer_mouse:"unicode/1f5b1.png?v8",confetti_ball:"unicode/1f38a.png?v8",confounded:"unicode/1f616.png?v8",confused:"unicode/1f615.png?v8",congo_brazzaville:"unicode/1f1e8-1f1ec.png?v8",congo_kinshasa:"unicode/1f1e8-1f1e9.png?v8",congratulations:"unicode/3297.png?v8",construction:"unicode/1f6a7.png?v8",construction_worker:"unicode/1f477.png?v8",construction_worker_man:"unicode/1f477-2642.png?v8",construction_worker_woman:"unicode/1f477-2640.png?v8",control_knobs:"unicode/1f39b.png?v8",convenience_store:"unicode/1f3ea.png?v8",cook:"unicode/1f9d1-1f373.png?v8",cook_islands:"unicode/1f1e8-1f1f0.png?v8",cookie:"unicode/1f36a.png?v8",cool:"unicode/1f192.png?v8",cop:"unicode/1f46e.png?v8",copyright:"unicode/00a9.png?v8",corn:"unicode/1f33d.png?v8",costa_rica:"unicode/1f1e8-1f1f7.png?v8",cote_divoire:"unicode/1f1e8-1f1ee.png?v8",couch_and_lamp:"unicode/1f6cb.png?v8",couple:"unicode/1f46b.png?v8",couple_with_heart:"unicode/1f491.png?v8",couple_with_heart_man_man:"unicode/1f468-2764-1f468.png?v8",couple_with_heart_woman_man:"unicode/1f469-2764-1f468.png?v8",couple_with_heart_woman_woman:"unicode/1f469-2764-1f469.png?v8",couplekiss:"unicode/1f48f.png?v8",couplekiss_man_man:"unicode/1f468-2764-1f48b-1f468.png?v8",couplekiss_man_woman:"unicode/1f469-2764-1f48b-1f468.png?v8",couplekiss_woman_woman:"unicode/1f469-2764-1f48b-1f469.png?v8",cow:"unicode/1f42e.png?v8",cow2:"unicode/1f404.png?v8",cowboy_hat_face:"unicode/1f920.png?v8",crab:"unicode/1f980.png?v8",crayon:"unicode/1f58d.png?v8",credit_card:"unicode/1f4b3.png?v8",crescent_moon:"unicode/1f319.png?v8",cricket:"unicode/1f997.png?v8",cricket_game:"unicode/1f3cf.png?v8",croatia:"unicode/1f1ed-1f1f7.png?v8",crocodile:"unicode/1f40a.png?v8",croissant:"unicode/1f950.png?v8",crossed_fingers:"unicode/1f91e.png?v8",crossed_flags:"unicode/1f38c.png?v8",crossed_swords:"unicode/2694.png?v8",crown:"unicode/1f451.png?v8",cry:"unicode/1f622.png?v8",crying_cat_face:"unicode/1f63f.png?v8",crystal_ball:"unicode/1f52e.png?v8",cuba:"unicode/1f1e8-1f1fa.png?v8",cucumber:"unicode/1f952.png?v8",cup_with_straw:"unicode/1f964.png?v8",cupcake:"unicode/1f9c1.png?v8",cupid:"unicode/1f498.png?v8",curacao:"unicode/1f1e8-1f1fc.png?v8",curling_stone:"unicode/1f94c.png?v8",curly_haired_man:"unicode/1f468-1f9b1.png?v8",curly_haired_woman:"unicode/1f469-1f9b1.png?v8",curly_loop:"unicode/27b0.png?v8",currency_exchange:"unicode/1f4b1.png?v8",curry:"unicode/1f35b.png?v8",cursing_face:"unicode/1f92c.png?v8",custard:"unicode/1f36e.png?v8",customs:"unicode/1f6c3.png?v8",cut_of_meat:"unicode/1f969.png?v8",cyclone:"unicode/1f300.png?v8",cyprus:"unicode/1f1e8-1f1fe.png?v8",czech_republic:"unicode/1f1e8-1f1ff.png?v8",dagger:"unicode/1f5e1.png?v8",dancer:"unicode/1f483.png?v8",dancers:"unicode/1f46f.png?v8",dancing_men:"unicode/1f46f-2642.png?v8",dancing_women:"unicode/1f46f-2640.png?v8",dango:"unicode/1f361.png?v8",dark_sunglasses:"unicode/1f576.png?v8",dart:"unicode/1f3af.png?v8",dash:"unicode/1f4a8.png?v8",date:"unicode/1f4c5.png?v8",de:"unicode/1f1e9-1f1ea.png?v8",deaf_man:"unicode/1f9cf-2642.png?v8",deaf_person:"unicode/1f9cf.png?v8",deaf_woman:"unicode/1f9cf-2640.png?v8",deciduous_tree:"unicode/1f333.png?v8",deer:"unicode/1f98c.png?v8",denmark:"unicode/1f1e9-1f1f0.png?v8",department_store:"unicode/1f3ec.png?v8",dependabot:"dependabot.png?v8",derelict_house:"unicode/1f3da.png?v8",desert:"unicode/1f3dc.png?v8",desert_island:"unicode/1f3dd.png?v8",desktop_computer:"unicode/1f5a5.png?v8",detective:"unicode/1f575.png?v8",diamond_shape_with_a_dot_inside:"unicode/1f4a0.png?v8",diamonds:"unicode/2666.png?v8",diego_garcia:"unicode/1f1e9-1f1ec.png?v8",disappointed:"unicode/1f61e.png?v8",disappointed_relieved:"unicode/1f625.png?v8",disguised_face:"unicode/1f978.png?v8",diving_mask:"unicode/1f93f.png?v8",diya_lamp:"unicode/1fa94.png?v8",dizzy:"unicode/1f4ab.png?v8",dizzy_face:"unicode/1f635.png?v8",djibouti:"unicode/1f1e9-1f1ef.png?v8",dna:"unicode/1f9ec.png?v8",do_not_litter:"unicode/1f6af.png?v8",dodo:"unicode/1f9a4.png?v8",dog:"unicode/1f436.png?v8",dog2:"unicode/1f415.png?v8",dollar:"unicode/1f4b5.png?v8",dolls:"unicode/1f38e.png?v8",dolphin:"unicode/1f42c.png?v8",dominica:"unicode/1f1e9-1f1f2.png?v8",dominican_republic:"unicode/1f1e9-1f1f4.png?v8",door:"unicode/1f6aa.png?v8",doughnut:"unicode/1f369.png?v8",dove:"unicode/1f54a.png?v8",dragon:"unicode/1f409.png?v8",dragon_face:"unicode/1f432.png?v8",dress:"unicode/1f457.png?v8",dromedary_camel:"unicode/1f42a.png?v8",drooling_face:"unicode/1f924.png?v8",drop_of_blood:"unicode/1fa78.png?v8",droplet:"unicode/1f4a7.png?v8",drum:"unicode/1f941.png?v8",duck:"unicode/1f986.png?v8",dumpling:"unicode/1f95f.png?v8",dvd:"unicode/1f4c0.png?v8","e-mail":"unicode/1f4e7.png?v8",eagle:"unicode/1f985.png?v8",ear:"unicode/1f442.png?v8",ear_of_rice:"unicode/1f33e.png?v8",ear_with_hearing_aid:"unicode/1f9bb.png?v8",earth_africa:"unicode/1f30d.png?v8",earth_americas:"unicode/1f30e.png?v8",earth_asia:"unicode/1f30f.png?v8",ecuador:"unicode/1f1ea-1f1e8.png?v8",egg:"unicode/1f95a.png?v8",eggplant:"unicode/1f346.png?v8",egypt:"unicode/1f1ea-1f1ec.png?v8",eight:"unicode/0038-20e3.png?v8",eight_pointed_black_star:"unicode/2734.png?v8",eight_spoked_asterisk:"unicode/2733.png?v8",eject_button:"unicode/23cf.png?v8",el_salvador:"unicode/1f1f8-1f1fb.png?v8",electric_plug:"unicode/1f50c.png?v8",electron:"electron.png?v8",elephant:"unicode/1f418.png?v8",elevator:"unicode/1f6d7.png?v8",elf:"unicode/1f9dd.png?v8",elf_man:"unicode/1f9dd-2642.png?v8",elf_woman:"unicode/1f9dd-2640.png?v8",email:"unicode/1f4e7.png?v8",end:"unicode/1f51a.png?v8",england:"unicode/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png?v8",envelope:"unicode/2709.png?v8",envelope_with_arrow:"unicode/1f4e9.png?v8",equatorial_guinea:"unicode/1f1ec-1f1f6.png?v8",eritrea:"unicode/1f1ea-1f1f7.png?v8",es:"unicode/1f1ea-1f1f8.png?v8",estonia:"unicode/1f1ea-1f1ea.png?v8",ethiopia:"unicode/1f1ea-1f1f9.png?v8",eu:"unicode/1f1ea-1f1fa.png?v8",euro:"unicode/1f4b6.png?v8",european_castle:"unicode/1f3f0.png?v8",european_post_office:"unicode/1f3e4.png?v8",european_union:"unicode/1f1ea-1f1fa.png?v8",evergreen_tree:"unicode/1f332.png?v8",exclamation:"unicode/2757.png?v8",exploding_head:"unicode/1f92f.png?v8",expressionless:"unicode/1f611.png?v8",eye:"unicode/1f441.png?v8",eye_speech_bubble:"unicode/1f441-1f5e8.png?v8",eyeglasses:"unicode/1f453.png?v8",eyes:"unicode/1f440.png?v8",face_exhaling:"unicode/1f62e-1f4a8.png?v8",face_in_clouds:"unicode/1f636-1f32b.png?v8",face_with_head_bandage:"unicode/1f915.png?v8",face_with_spiral_eyes:"unicode/1f635-1f4ab.png?v8",face_with_thermometer:"unicode/1f912.png?v8",facepalm:"unicode/1f926.png?v8",facepunch:"unicode/1f44a.png?v8",factory:"unicode/1f3ed.png?v8",factory_worker:"unicode/1f9d1-1f3ed.png?v8",fairy:"unicode/1f9da.png?v8",fairy_man:"unicode/1f9da-2642.png?v8",fairy_woman:"unicode/1f9da-2640.png?v8",falafel:"unicode/1f9c6.png?v8",falkland_islands:"unicode/1f1eb-1f1f0.png?v8",fallen_leaf:"unicode/1f342.png?v8",family:"unicode/1f46a.png?v8",family_man_boy:"unicode/1f468-1f466.png?v8",family_man_boy_boy:"unicode/1f468-1f466-1f466.png?v8",family_man_girl:"unicode/1f468-1f467.png?v8",family_man_girl_boy:"unicode/1f468-1f467-1f466.png?v8",family_man_girl_girl:"unicode/1f468-1f467-1f467.png?v8",family_man_man_boy:"unicode/1f468-1f468-1f466.png?v8",family_man_man_boy_boy:"unicode/1f468-1f468-1f466-1f466.png?v8",family_man_man_girl:"unicode/1f468-1f468-1f467.png?v8",family_man_man_girl_boy:"unicode/1f468-1f468-1f467-1f466.png?v8",family_man_man_girl_girl:"unicode/1f468-1f468-1f467-1f467.png?v8",family_man_woman_boy:"unicode/1f468-1f469-1f466.png?v8",family_man_woman_boy_boy:"unicode/1f468-1f469-1f466-1f466.png?v8",family_man_woman_girl:"unicode/1f468-1f469-1f467.png?v8",family_man_woman_girl_boy:"unicode/1f468-1f469-1f467-1f466.png?v8",family_man_woman_girl_girl:"unicode/1f468-1f469-1f467-1f467.png?v8",family_woman_boy:"unicode/1f469-1f466.png?v8",family_woman_boy_boy:"unicode/1f469-1f466-1f466.png?v8",family_woman_girl:"unicode/1f469-1f467.png?v8",family_woman_girl_boy:"unicode/1f469-1f467-1f466.png?v8",family_woman_girl_girl:"unicode/1f469-1f467-1f467.png?v8",family_woman_woman_boy:"unicode/1f469-1f469-1f466.png?v8",family_woman_woman_boy_boy:"unicode/1f469-1f469-1f466-1f466.png?v8",family_woman_woman_girl:"unicode/1f469-1f469-1f467.png?v8",family_woman_woman_girl_boy:"unicode/1f469-1f469-1f467-1f466.png?v8",family_woman_woman_girl_girl:"unicode/1f469-1f469-1f467-1f467.png?v8",farmer:"unicode/1f9d1-1f33e.png?v8",faroe_islands:"unicode/1f1eb-1f1f4.png?v8",fast_forward:"unicode/23e9.png?v8",fax:"unicode/1f4e0.png?v8",fearful:"unicode/1f628.png?v8",feather:"unicode/1fab6.png?v8",feelsgood:"feelsgood.png?v8",feet:"unicode/1f43e.png?v8",female_detective:"unicode/1f575-2640.png?v8",female_sign:"unicode/2640.png?v8",ferris_wheel:"unicode/1f3a1.png?v8",ferry:"unicode/26f4.png?v8",field_hockey:"unicode/1f3d1.png?v8",fiji:"unicode/1f1eb-1f1ef.png?v8",file_cabinet:"unicode/1f5c4.png?v8",file_folder:"unicode/1f4c1.png?v8",film_projector:"unicode/1f4fd.png?v8",film_strip:"unicode/1f39e.png?v8",finland:"unicode/1f1eb-1f1ee.png?v8",finnadie:"finnadie.png?v8",fire:"unicode/1f525.png?v8",fire_engine:"unicode/1f692.png?v8",fire_extinguisher:"unicode/1f9ef.png?v8",firecracker:"unicode/1f9e8.png?v8",firefighter:"unicode/1f9d1-1f692.png?v8",fireworks:"unicode/1f386.png?v8",first_quarter_moon:"unicode/1f313.png?v8",first_quarter_moon_with_face:"unicode/1f31b.png?v8",fish:"unicode/1f41f.png?v8",fish_cake:"unicode/1f365.png?v8",fishing_pole_and_fish:"unicode/1f3a3.png?v8",fishsticks:"fishsticks.png?v8",fist:"unicode/270a.png?v8",fist_left:"unicode/1f91b.png?v8",fist_oncoming:"unicode/1f44a.png?v8",fist_raised:"unicode/270a.png?v8",fist_right:"unicode/1f91c.png?v8",five:"unicode/0035-20e3.png?v8",flags:"unicode/1f38f.png?v8",flamingo:"unicode/1f9a9.png?v8",flashlight:"unicode/1f526.png?v8",flat_shoe:"unicode/1f97f.png?v8",flatbread:"unicode/1fad3.png?v8",fleur_de_lis:"unicode/269c.png?v8",flight_arrival:"unicode/1f6ec.png?v8",flight_departure:"unicode/1f6eb.png?v8",flipper:"unicode/1f42c.png?v8",floppy_disk:"unicode/1f4be.png?v8",flower_playing_cards:"unicode/1f3b4.png?v8",flushed:"unicode/1f633.png?v8",fly:"unicode/1fab0.png?v8",flying_disc:"unicode/1f94f.png?v8",flying_saucer:"unicode/1f6f8.png?v8",fog:"unicode/1f32b.png?v8",foggy:"unicode/1f301.png?v8",fondue:"unicode/1fad5.png?v8",foot:"unicode/1f9b6.png?v8",football:"unicode/1f3c8.png?v8",footprints:"unicode/1f463.png?v8",fork_and_knife:"unicode/1f374.png?v8",fortune_cookie:"unicode/1f960.png?v8",fountain:"unicode/26f2.png?v8",fountain_pen:"unicode/1f58b.png?v8",four:"unicode/0034-20e3.png?v8",four_leaf_clover:"unicode/1f340.png?v8",fox_face:"unicode/1f98a.png?v8",fr:"unicode/1f1eb-1f1f7.png?v8",framed_picture:"unicode/1f5bc.png?v8",free:"unicode/1f193.png?v8",french_guiana:"unicode/1f1ec-1f1eb.png?v8",french_polynesia:"unicode/1f1f5-1f1eb.png?v8",french_southern_territories:"unicode/1f1f9-1f1eb.png?v8",fried_egg:"unicode/1f373.png?v8",fried_shrimp:"unicode/1f364.png?v8",fries:"unicode/1f35f.png?v8",frog:"unicode/1f438.png?v8",frowning:"unicode/1f626.png?v8",frowning_face:"unicode/2639.png?v8",frowning_man:"unicode/1f64d-2642.png?v8",frowning_person:"unicode/1f64d.png?v8",frowning_woman:"unicode/1f64d-2640.png?v8",fu:"unicode/1f595.png?v8",fuelpump:"unicode/26fd.png?v8",full_moon:"unicode/1f315.png?v8",full_moon_with_face:"unicode/1f31d.png?v8",funeral_urn:"unicode/26b1.png?v8",gabon:"unicode/1f1ec-1f1e6.png?v8",gambia:"unicode/1f1ec-1f1f2.png?v8",game_die:"unicode/1f3b2.png?v8",garlic:"unicode/1f9c4.png?v8",gb:"unicode/1f1ec-1f1e7.png?v8",gear:"unicode/2699.png?v8",gem:"unicode/1f48e.png?v8",gemini:"unicode/264a.png?v8",genie:"unicode/1f9de.png?v8",genie_man:"unicode/1f9de-2642.png?v8",genie_woman:"unicode/1f9de-2640.png?v8",georgia:"unicode/1f1ec-1f1ea.png?v8",ghana:"unicode/1f1ec-1f1ed.png?v8",ghost:"unicode/1f47b.png?v8",gibraltar:"unicode/1f1ec-1f1ee.png?v8",gift:"unicode/1f381.png?v8",gift_heart:"unicode/1f49d.png?v8",giraffe:"unicode/1f992.png?v8",girl:"unicode/1f467.png?v8",globe_with_meridians:"unicode/1f310.png?v8",gloves:"unicode/1f9e4.png?v8",goal_net:"unicode/1f945.png?v8",goat:"unicode/1f410.png?v8",goberserk:"goberserk.png?v8",godmode:"godmode.png?v8",goggles:"unicode/1f97d.png?v8",golf:"unicode/26f3.png?v8",golfing:"unicode/1f3cc.png?v8",golfing_man:"unicode/1f3cc-2642.png?v8",golfing_woman:"unicode/1f3cc-2640.png?v8",gorilla:"unicode/1f98d.png?v8",grapes:"unicode/1f347.png?v8",greece:"unicode/1f1ec-1f1f7.png?v8",green_apple:"unicode/1f34f.png?v8",green_book:"unicode/1f4d7.png?v8",green_circle:"unicode/1f7e2.png?v8",green_heart:"unicode/1f49a.png?v8",green_salad:"unicode/1f957.png?v8",green_square:"unicode/1f7e9.png?v8",greenland:"unicode/1f1ec-1f1f1.png?v8",grenada:"unicode/1f1ec-1f1e9.png?v8",grey_exclamation:"unicode/2755.png?v8",grey_question:"unicode/2754.png?v8",grimacing:"unicode/1f62c.png?v8",grin:"unicode/1f601.png?v8",grinning:"unicode/1f600.png?v8",guadeloupe:"unicode/1f1ec-1f1f5.png?v8",guam:"unicode/1f1ec-1f1fa.png?v8",guard:"unicode/1f482.png?v8",guardsman:"unicode/1f482-2642.png?v8",guardswoman:"unicode/1f482-2640.png?v8",guatemala:"unicode/1f1ec-1f1f9.png?v8",guernsey:"unicode/1f1ec-1f1ec.png?v8",guide_dog:"unicode/1f9ae.png?v8",guinea:"unicode/1f1ec-1f1f3.png?v8",guinea_bissau:"unicode/1f1ec-1f1fc.png?v8",guitar:"unicode/1f3b8.png?v8",gun:"unicode/1f52b.png?v8",guyana:"unicode/1f1ec-1f1fe.png?v8",haircut:"unicode/1f487.png?v8",haircut_man:"unicode/1f487-2642.png?v8",haircut_woman:"unicode/1f487-2640.png?v8",haiti:"unicode/1f1ed-1f1f9.png?v8",hamburger:"unicode/1f354.png?v8",hammer:"unicode/1f528.png?v8",hammer_and_pick:"unicode/2692.png?v8",hammer_and_wrench:"unicode/1f6e0.png?v8",hamster:"unicode/1f439.png?v8",hand:"unicode/270b.png?v8",hand_over_mouth:"unicode/1f92d.png?v8",handbag:"unicode/1f45c.png?v8",handball_person:"unicode/1f93e.png?v8",handshake:"unicode/1f91d.png?v8",hankey:"unicode/1f4a9.png?v8",hash:"unicode/0023-20e3.png?v8",hatched_chick:"unicode/1f425.png?v8",hatching_chick:"unicode/1f423.png?v8",headphones:"unicode/1f3a7.png?v8",headstone:"unicode/1faa6.png?v8",health_worker:"unicode/1f9d1-2695.png?v8",hear_no_evil:"unicode/1f649.png?v8",heard_mcdonald_islands:"unicode/1f1ed-1f1f2.png?v8",heart:"unicode/2764.png?v8",heart_decoration:"unicode/1f49f.png?v8",heart_eyes:"unicode/1f60d.png?v8",heart_eyes_cat:"unicode/1f63b.png?v8",heart_on_fire:"unicode/2764-1f525.png?v8",heartbeat:"unicode/1f493.png?v8",heartpulse:"unicode/1f497.png?v8",hearts:"unicode/2665.png?v8",heavy_check_mark:"unicode/2714.png?v8",heavy_division_sign:"unicode/2797.png?v8",heavy_dollar_sign:"unicode/1f4b2.png?v8",heavy_exclamation_mark:"unicode/2757.png?v8",heavy_heart_exclamation:"unicode/2763.png?v8",heavy_minus_sign:"unicode/2796.png?v8",heavy_multiplication_x:"unicode/2716.png?v8",heavy_plus_sign:"unicode/2795.png?v8",hedgehog:"unicode/1f994.png?v8",helicopter:"unicode/1f681.png?v8",herb:"unicode/1f33f.png?v8",hibiscus:"unicode/1f33a.png?v8",high_brightness:"unicode/1f506.png?v8",high_heel:"unicode/1f460.png?v8",hiking_boot:"unicode/1f97e.png?v8",hindu_temple:"unicode/1f6d5.png?v8",hippopotamus:"unicode/1f99b.png?v8",hocho:"unicode/1f52a.png?v8",hole:"unicode/1f573.png?v8",honduras:"unicode/1f1ed-1f1f3.png?v8",honey_pot:"unicode/1f36f.png?v8",honeybee:"unicode/1f41d.png?v8",hong_kong:"unicode/1f1ed-1f1f0.png?v8",hook:"unicode/1fa9d.png?v8",horse:"unicode/1f434.png?v8",horse_racing:"unicode/1f3c7.png?v8",hospital:"unicode/1f3e5.png?v8",hot_face:"unicode/1f975.png?v8",hot_pepper:"unicode/1f336.png?v8",hotdog:"unicode/1f32d.png?v8",hotel:"unicode/1f3e8.png?v8",hotsprings:"unicode/2668.png?v8",hourglass:"unicode/231b.png?v8",hourglass_flowing_sand:"unicode/23f3.png?v8",house:"unicode/1f3e0.png?v8",house_with_garden:"unicode/1f3e1.png?v8",houses:"unicode/1f3d8.png?v8",hugs:"unicode/1f917.png?v8",hungary:"unicode/1f1ed-1f1fa.png?v8",hurtrealbad:"hurtrealbad.png?v8",hushed:"unicode/1f62f.png?v8",hut:"unicode/1f6d6.png?v8",ice_cream:"unicode/1f368.png?v8",ice_cube:"unicode/1f9ca.png?v8",ice_hockey:"unicode/1f3d2.png?v8",ice_skate:"unicode/26f8.png?v8",icecream:"unicode/1f366.png?v8",iceland:"unicode/1f1ee-1f1f8.png?v8",id:"unicode/1f194.png?v8",ideograph_advantage:"unicode/1f250.png?v8",imp:"unicode/1f47f.png?v8",inbox_tray:"unicode/1f4e5.png?v8",incoming_envelope:"unicode/1f4e8.png?v8",india:"unicode/1f1ee-1f1f3.png?v8",indonesia:"unicode/1f1ee-1f1e9.png?v8",infinity:"unicode/267e.png?v8",information_desk_person:"unicode/1f481.png?v8",information_source:"unicode/2139.png?v8",innocent:"unicode/1f607.png?v8",interrobang:"unicode/2049.png?v8",iphone:"unicode/1f4f1.png?v8",iran:"unicode/1f1ee-1f1f7.png?v8",iraq:"unicode/1f1ee-1f1f6.png?v8",ireland:"unicode/1f1ee-1f1ea.png?v8",isle_of_man:"unicode/1f1ee-1f1f2.png?v8",israel:"unicode/1f1ee-1f1f1.png?v8",it:"unicode/1f1ee-1f1f9.png?v8",izakaya_lantern:"unicode/1f3ee.png?v8",jack_o_lantern:"unicode/1f383.png?v8",jamaica:"unicode/1f1ef-1f1f2.png?v8",japan:"unicode/1f5fe.png?v8",japanese_castle:"unicode/1f3ef.png?v8",japanese_goblin:"unicode/1f47a.png?v8",japanese_ogre:"unicode/1f479.png?v8",jeans:"unicode/1f456.png?v8",jersey:"unicode/1f1ef-1f1ea.png?v8",jigsaw:"unicode/1f9e9.png?v8",jordan:"unicode/1f1ef-1f1f4.png?v8",joy:"unicode/1f602.png?v8",joy_cat:"unicode/1f639.png?v8",joystick:"unicode/1f579.png?v8",jp:"unicode/1f1ef-1f1f5.png?v8",judge:"unicode/1f9d1-2696.png?v8",juggling_person:"unicode/1f939.png?v8",kaaba:"unicode/1f54b.png?v8",kangaroo:"unicode/1f998.png?v8",kazakhstan:"unicode/1f1f0-1f1ff.png?v8",kenya:"unicode/1f1f0-1f1ea.png?v8",key:"unicode/1f511.png?v8",keyboard:"unicode/2328.png?v8",keycap_ten:"unicode/1f51f.png?v8",kick_scooter:"unicode/1f6f4.png?v8",kimono:"unicode/1f458.png?v8",kiribati:"unicode/1f1f0-1f1ee.png?v8",kiss:"unicode/1f48b.png?v8",kissing:"unicode/1f617.png?v8",kissing_cat:"unicode/1f63d.png?v8",kissing_closed_eyes:"unicode/1f61a.png?v8",kissing_heart:"unicode/1f618.png?v8",kissing_smiling_eyes:"unicode/1f619.png?v8",kite:"unicode/1fa81.png?v8",kiwi_fruit:"unicode/1f95d.png?v8",kneeling_man:"unicode/1f9ce-2642.png?v8",kneeling_person:"unicode/1f9ce.png?v8",kneeling_woman:"unicode/1f9ce-2640.png?v8",knife:"unicode/1f52a.png?v8",knot:"unicode/1faa2.png?v8",koala:"unicode/1f428.png?v8",koko:"unicode/1f201.png?v8",kosovo:"unicode/1f1fd-1f1f0.png?v8",kr:"unicode/1f1f0-1f1f7.png?v8",kuwait:"unicode/1f1f0-1f1fc.png?v8",kyrgyzstan:"unicode/1f1f0-1f1ec.png?v8",lab_coat:"unicode/1f97c.png?v8",label:"unicode/1f3f7.png?v8",lacrosse:"unicode/1f94d.png?v8",ladder:"unicode/1fa9c.png?v8",lady_beetle:"unicode/1f41e.png?v8",lantern:"unicode/1f3ee.png?v8",laos:"unicode/1f1f1-1f1e6.png?v8",large_blue_circle:"unicode/1f535.png?v8",large_blue_diamond:"unicode/1f537.png?v8",large_orange_diamond:"unicode/1f536.png?v8",last_quarter_moon:"unicode/1f317.png?v8",last_quarter_moon_with_face:"unicode/1f31c.png?v8",latin_cross:"unicode/271d.png?v8",latvia:"unicode/1f1f1-1f1fb.png?v8",laughing:"unicode/1f606.png?v8",leafy_green:"unicode/1f96c.png?v8",leaves:"unicode/1f343.png?v8",lebanon:"unicode/1f1f1-1f1e7.png?v8",ledger:"unicode/1f4d2.png?v8",left_luggage:"unicode/1f6c5.png?v8",left_right_arrow:"unicode/2194.png?v8",left_speech_bubble:"unicode/1f5e8.png?v8",leftwards_arrow_with_hook:"unicode/21a9.png?v8",leg:"unicode/1f9b5.png?v8",lemon:"unicode/1f34b.png?v8",leo:"unicode/264c.png?v8",leopard:"unicode/1f406.png?v8",lesotho:"unicode/1f1f1-1f1f8.png?v8",level_slider:"unicode/1f39a.png?v8",liberia:"unicode/1f1f1-1f1f7.png?v8",libra:"unicode/264e.png?v8",libya:"unicode/1f1f1-1f1fe.png?v8",liechtenstein:"unicode/1f1f1-1f1ee.png?v8",light_rail:"unicode/1f688.png?v8",link:"unicode/1f517.png?v8",lion:"unicode/1f981.png?v8",lips:"unicode/1f444.png?v8",lipstick:"unicode/1f484.png?v8",lithuania:"unicode/1f1f1-1f1f9.png?v8",lizard:"unicode/1f98e.png?v8",llama:"unicode/1f999.png?v8",lobster:"unicode/1f99e.png?v8",lock:"unicode/1f512.png?v8",lock_with_ink_pen:"unicode/1f50f.png?v8",lollipop:"unicode/1f36d.png?v8",long_drum:"unicode/1fa98.png?v8",loop:"unicode/27bf.png?v8",lotion_bottle:"unicode/1f9f4.png?v8",lotus_position:"unicode/1f9d8.png?v8",lotus_position_man:"unicode/1f9d8-2642.png?v8",lotus_position_woman:"unicode/1f9d8-2640.png?v8",loud_sound:"unicode/1f50a.png?v8",loudspeaker:"unicode/1f4e2.png?v8",love_hotel:"unicode/1f3e9.png?v8",love_letter:"unicode/1f48c.png?v8",love_you_gesture:"unicode/1f91f.png?v8",low_brightness:"unicode/1f505.png?v8",luggage:"unicode/1f9f3.png?v8",lungs:"unicode/1fac1.png?v8",luxembourg:"unicode/1f1f1-1f1fa.png?v8",lying_face:"unicode/1f925.png?v8",m:"unicode/24c2.png?v8",macau:"unicode/1f1f2-1f1f4.png?v8",macedonia:"unicode/1f1f2-1f1f0.png?v8",madagascar:"unicode/1f1f2-1f1ec.png?v8",mag:"unicode/1f50d.png?v8",mag_right:"unicode/1f50e.png?v8",mage:"unicode/1f9d9.png?v8",mage_man:"unicode/1f9d9-2642.png?v8",mage_woman:"unicode/1f9d9-2640.png?v8",magic_wand:"unicode/1fa84.png?v8",magnet:"unicode/1f9f2.png?v8",mahjong:"unicode/1f004.png?v8",mailbox:"unicode/1f4eb.png?v8",mailbox_closed:"unicode/1f4ea.png?v8",mailbox_with_mail:"unicode/1f4ec.png?v8",mailbox_with_no_mail:"unicode/1f4ed.png?v8",malawi:"unicode/1f1f2-1f1fc.png?v8",malaysia:"unicode/1f1f2-1f1fe.png?v8",maldives:"unicode/1f1f2-1f1fb.png?v8",male_detective:"unicode/1f575-2642.png?v8",male_sign:"unicode/2642.png?v8",mali:"unicode/1f1f2-1f1f1.png?v8",malta:"unicode/1f1f2-1f1f9.png?v8",mammoth:"unicode/1f9a3.png?v8",man:"unicode/1f468.png?v8",man_artist:"unicode/1f468-1f3a8.png?v8",man_astronaut:"unicode/1f468-1f680.png?v8",man_beard:"unicode/1f9d4-2642.png?v8",man_cartwheeling:"unicode/1f938-2642.png?v8",man_cook:"unicode/1f468-1f373.png?v8",man_dancing:"unicode/1f57a.png?v8",man_facepalming:"unicode/1f926-2642.png?v8",man_factory_worker:"unicode/1f468-1f3ed.png?v8",man_farmer:"unicode/1f468-1f33e.png?v8",man_feeding_baby:"unicode/1f468-1f37c.png?v8",man_firefighter:"unicode/1f468-1f692.png?v8",man_health_worker:"unicode/1f468-2695.png?v8",man_in_manual_wheelchair:"unicode/1f468-1f9bd.png?v8",man_in_motorized_wheelchair:"unicode/1f468-1f9bc.png?v8",man_in_tuxedo:"unicode/1f935-2642.png?v8",man_judge:"unicode/1f468-2696.png?v8",man_juggling:"unicode/1f939-2642.png?v8",man_mechanic:"unicode/1f468-1f527.png?v8",man_office_worker:"unicode/1f468-1f4bc.png?v8",man_pilot:"unicode/1f468-2708.png?v8",man_playing_handball:"unicode/1f93e-2642.png?v8",man_playing_water_polo:"unicode/1f93d-2642.png?v8",man_scientist:"unicode/1f468-1f52c.png?v8",man_shrugging:"unicode/1f937-2642.png?v8",man_singer:"unicode/1f468-1f3a4.png?v8",man_student:"unicode/1f468-1f393.png?v8",man_teacher:"unicode/1f468-1f3eb.png?v8",man_technologist:"unicode/1f468-1f4bb.png?v8",man_with_gua_pi_mao:"unicode/1f472.png?v8",man_with_probing_cane:"unicode/1f468-1f9af.png?v8",man_with_turban:"unicode/1f473-2642.png?v8",man_with_veil:"unicode/1f470-2642.png?v8",mandarin:"unicode/1f34a.png?v8",mango:"unicode/1f96d.png?v8",mans_shoe:"unicode/1f45e.png?v8",mantelpiece_clock:"unicode/1f570.png?v8",manual_wheelchair:"unicode/1f9bd.png?v8",maple_leaf:"unicode/1f341.png?v8",marshall_islands:"unicode/1f1f2-1f1ed.png?v8",martial_arts_uniform:"unicode/1f94b.png?v8",martinique:"unicode/1f1f2-1f1f6.png?v8",mask:"unicode/1f637.png?v8",massage:"unicode/1f486.png?v8",massage_man:"unicode/1f486-2642.png?v8",massage_woman:"unicode/1f486-2640.png?v8",mate:"unicode/1f9c9.png?v8",mauritania:"unicode/1f1f2-1f1f7.png?v8",mauritius:"unicode/1f1f2-1f1fa.png?v8",mayotte:"unicode/1f1fe-1f1f9.png?v8",meat_on_bone:"unicode/1f356.png?v8",mechanic:"unicode/1f9d1-1f527.png?v8",mechanical_arm:"unicode/1f9be.png?v8",mechanical_leg:"unicode/1f9bf.png?v8",medal_military:"unicode/1f396.png?v8",medal_sports:"unicode/1f3c5.png?v8",medical_symbol:"unicode/2695.png?v8",mega:"unicode/1f4e3.png?v8",melon:"unicode/1f348.png?v8",memo:"unicode/1f4dd.png?v8",men_wrestling:"unicode/1f93c-2642.png?v8",mending_heart:"unicode/2764-1fa79.png?v8",menorah:"unicode/1f54e.png?v8",mens:"unicode/1f6b9.png?v8",mermaid:"unicode/1f9dc-2640.png?v8",merman:"unicode/1f9dc-2642.png?v8",merperson:"unicode/1f9dc.png?v8",metal:"unicode/1f918.png?v8",metro:"unicode/1f687.png?v8",mexico:"unicode/1f1f2-1f1fd.png?v8",microbe:"unicode/1f9a0.png?v8",micronesia:"unicode/1f1eb-1f1f2.png?v8",microphone:"unicode/1f3a4.png?v8",microscope:"unicode/1f52c.png?v8",middle_finger:"unicode/1f595.png?v8",military_helmet:"unicode/1fa96.png?v8",milk_glass:"unicode/1f95b.png?v8",milky_way:"unicode/1f30c.png?v8",minibus:"unicode/1f690.png?v8",minidisc:"unicode/1f4bd.png?v8",mirror:"unicode/1fa9e.png?v8",mobile_phone_off:"unicode/1f4f4.png?v8",moldova:"unicode/1f1f2-1f1e9.png?v8",monaco:"unicode/1f1f2-1f1e8.png?v8",money_mouth_face:"unicode/1f911.png?v8",money_with_wings:"unicode/1f4b8.png?v8",moneybag:"unicode/1f4b0.png?v8",mongolia:"unicode/1f1f2-1f1f3.png?v8",monkey:"unicode/1f412.png?v8",monkey_face:"unicode/1f435.png?v8",monocle_face:"unicode/1f9d0.png?v8",monorail:"unicode/1f69d.png?v8",montenegro:"unicode/1f1f2-1f1ea.png?v8",montserrat:"unicode/1f1f2-1f1f8.png?v8",moon:"unicode/1f314.png?v8",moon_cake:"unicode/1f96e.png?v8",morocco:"unicode/1f1f2-1f1e6.png?v8",mortar_board:"unicode/1f393.png?v8",mosque:"unicode/1f54c.png?v8",mosquito:"unicode/1f99f.png?v8",motor_boat:"unicode/1f6e5.png?v8",motor_scooter:"unicode/1f6f5.png?v8",motorcycle:"unicode/1f3cd.png?v8",motorized_wheelchair:"unicode/1f9bc.png?v8",motorway:"unicode/1f6e3.png?v8",mount_fuji:"unicode/1f5fb.png?v8",mountain:"unicode/26f0.png?v8",mountain_bicyclist:"unicode/1f6b5.png?v8",mountain_biking_man:"unicode/1f6b5-2642.png?v8",mountain_biking_woman:"unicode/1f6b5-2640.png?v8",mountain_cableway:"unicode/1f6a0.png?v8",mountain_railway:"unicode/1f69e.png?v8",mountain_snow:"unicode/1f3d4.png?v8",mouse:"unicode/1f42d.png?v8",mouse2:"unicode/1f401.png?v8",mouse_trap:"unicode/1faa4.png?v8",movie_camera:"unicode/1f3a5.png?v8",moyai:"unicode/1f5ff.png?v8",mozambique:"unicode/1f1f2-1f1ff.png?v8",mrs_claus:"unicode/1f936.png?v8",muscle:"unicode/1f4aa.png?v8",mushroom:"unicode/1f344.png?v8",musical_keyboard:"unicode/1f3b9.png?v8",musical_note:"unicode/1f3b5.png?v8",musical_score:"unicode/1f3bc.png?v8",mute:"unicode/1f507.png?v8",mx_claus:"unicode/1f9d1-1f384.png?v8",myanmar:"unicode/1f1f2-1f1f2.png?v8",nail_care:"unicode/1f485.png?v8",name_badge:"unicode/1f4db.png?v8",namibia:"unicode/1f1f3-1f1e6.png?v8",national_park:"unicode/1f3de.png?v8",nauru:"unicode/1f1f3-1f1f7.png?v8",nauseated_face:"unicode/1f922.png?v8",nazar_amulet:"unicode/1f9ff.png?v8",neckbeard:"neckbeard.png?v8",necktie:"unicode/1f454.png?v8",negative_squared_cross_mark:"unicode/274e.png?v8",nepal:"unicode/1f1f3-1f1f5.png?v8",nerd_face:"unicode/1f913.png?v8",nesting_dolls:"unicode/1fa86.png?v8",netherlands:"unicode/1f1f3-1f1f1.png?v8",neutral_face:"unicode/1f610.png?v8",new:"unicode/1f195.png?v8",new_caledonia:"unicode/1f1f3-1f1e8.png?v8",new_moon:"unicode/1f311.png?v8",new_moon_with_face:"unicode/1f31a.png?v8",new_zealand:"unicode/1f1f3-1f1ff.png?v8",newspaper:"unicode/1f4f0.png?v8",newspaper_roll:"unicode/1f5de.png?v8",next_track_button:"unicode/23ed.png?v8",ng:"unicode/1f196.png?v8",ng_man:"unicode/1f645-2642.png?v8",ng_woman:"unicode/1f645-2640.png?v8",nicaragua:"unicode/1f1f3-1f1ee.png?v8",niger:"unicode/1f1f3-1f1ea.png?v8",nigeria:"unicode/1f1f3-1f1ec.png?v8",night_with_stars:"unicode/1f303.png?v8",nine:"unicode/0039-20e3.png?v8",ninja:"unicode/1f977.png?v8",niue:"unicode/1f1f3-1f1fa.png?v8",no_bell:"unicode/1f515.png?v8",no_bicycles:"unicode/1f6b3.png?v8",no_entry:"unicode/26d4.png?v8",no_entry_sign:"unicode/1f6ab.png?v8",no_good:"unicode/1f645.png?v8",no_good_man:"unicode/1f645-2642.png?v8",no_good_woman:"unicode/1f645-2640.png?v8",no_mobile_phones:"unicode/1f4f5.png?v8",no_mouth:"unicode/1f636.png?v8",no_pedestrians:"unicode/1f6b7.png?v8",no_smoking:"unicode/1f6ad.png?v8","non-potable_water":"unicode/1f6b1.png?v8",norfolk_island:"unicode/1f1f3-1f1eb.png?v8",north_korea:"unicode/1f1f0-1f1f5.png?v8",northern_mariana_islands:"unicode/1f1f2-1f1f5.png?v8",norway:"unicode/1f1f3-1f1f4.png?v8",nose:"unicode/1f443.png?v8",notebook:"unicode/1f4d3.png?v8",notebook_with_decorative_cover:"unicode/1f4d4.png?v8",notes:"unicode/1f3b6.png?v8",nut_and_bolt:"unicode/1f529.png?v8",o:"unicode/2b55.png?v8",o2:"unicode/1f17e.png?v8",ocean:"unicode/1f30a.png?v8",octocat:"octocat.png?v8",octopus:"unicode/1f419.png?v8",oden:"unicode/1f362.png?v8",office:"unicode/1f3e2.png?v8",office_worker:"unicode/1f9d1-1f4bc.png?v8",oil_drum:"unicode/1f6e2.png?v8",ok:"unicode/1f197.png?v8",ok_hand:"unicode/1f44c.png?v8",ok_man:"unicode/1f646-2642.png?v8",ok_person:"unicode/1f646.png?v8",ok_woman:"unicode/1f646-2640.png?v8",old_key:"unicode/1f5dd.png?v8",older_adult:"unicode/1f9d3.png?v8",older_man:"unicode/1f474.png?v8",older_woman:"unicode/1f475.png?v8",olive:"unicode/1fad2.png?v8",om:"unicode/1f549.png?v8",oman:"unicode/1f1f4-1f1f2.png?v8",on:"unicode/1f51b.png?v8",oncoming_automobile:"unicode/1f698.png?v8",oncoming_bus:"unicode/1f68d.png?v8",oncoming_police_car:"unicode/1f694.png?v8",oncoming_taxi:"unicode/1f696.png?v8",one:"unicode/0031-20e3.png?v8",one_piece_swimsuit:"unicode/1fa71.png?v8",onion:"unicode/1f9c5.png?v8",open_book:"unicode/1f4d6.png?v8",open_file_folder:"unicode/1f4c2.png?v8",open_hands:"unicode/1f450.png?v8",open_mouth:"unicode/1f62e.png?v8",open_umbrella:"unicode/2602.png?v8",ophiuchus:"unicode/26ce.png?v8",orange:"unicode/1f34a.png?v8",orange_book:"unicode/1f4d9.png?v8",orange_circle:"unicode/1f7e0.png?v8",orange_heart:"unicode/1f9e1.png?v8",orange_square:"unicode/1f7e7.png?v8",orangutan:"unicode/1f9a7.png?v8",orthodox_cross:"unicode/2626.png?v8",otter:"unicode/1f9a6.png?v8",outbox_tray:"unicode/1f4e4.png?v8",owl:"unicode/1f989.png?v8",ox:"unicode/1f402.png?v8",oyster:"unicode/1f9aa.png?v8",package:"unicode/1f4e6.png?v8",page_facing_up:"unicode/1f4c4.png?v8",page_with_curl:"unicode/1f4c3.png?v8",pager:"unicode/1f4df.png?v8",paintbrush:"unicode/1f58c.png?v8",pakistan:"unicode/1f1f5-1f1f0.png?v8",palau:"unicode/1f1f5-1f1fc.png?v8",palestinian_territories:"unicode/1f1f5-1f1f8.png?v8",palm_tree:"unicode/1f334.png?v8",palms_up_together:"unicode/1f932.png?v8",panama:"unicode/1f1f5-1f1e6.png?v8",pancakes:"unicode/1f95e.png?v8",panda_face:"unicode/1f43c.png?v8",paperclip:"unicode/1f4ce.png?v8",paperclips:"unicode/1f587.png?v8",papua_new_guinea:"unicode/1f1f5-1f1ec.png?v8",parachute:"unicode/1fa82.png?v8",paraguay:"unicode/1f1f5-1f1fe.png?v8",parasol_on_ground:"unicode/26f1.png?v8",parking:"unicode/1f17f.png?v8",parrot:"unicode/1f99c.png?v8",part_alternation_mark:"unicode/303d.png?v8",partly_sunny:"unicode/26c5.png?v8",partying_face:"unicode/1f973.png?v8",passenger_ship:"unicode/1f6f3.png?v8",passport_control:"unicode/1f6c2.png?v8",pause_button:"unicode/23f8.png?v8",paw_prints:"unicode/1f43e.png?v8",peace_symbol:"unicode/262e.png?v8",peach:"unicode/1f351.png?v8",peacock:"unicode/1f99a.png?v8",peanuts:"unicode/1f95c.png?v8",pear:"unicode/1f350.png?v8",pen:"unicode/1f58a.png?v8",pencil:"unicode/1f4dd.png?v8",pencil2:"unicode/270f.png?v8",penguin:"unicode/1f427.png?v8",pensive:"unicode/1f614.png?v8",people_holding_hands:"unicode/1f9d1-1f91d-1f9d1.png?v8",people_hugging:"unicode/1fac2.png?v8",performing_arts:"unicode/1f3ad.png?v8",persevere:"unicode/1f623.png?v8",person_bald:"unicode/1f9d1-1f9b2.png?v8",person_curly_hair:"unicode/1f9d1-1f9b1.png?v8",person_feeding_baby:"unicode/1f9d1-1f37c.png?v8",person_fencing:"unicode/1f93a.png?v8",person_in_manual_wheelchair:"unicode/1f9d1-1f9bd.png?v8",person_in_motorized_wheelchair:"unicode/1f9d1-1f9bc.png?v8",person_in_tuxedo:"unicode/1f935.png?v8",person_red_hair:"unicode/1f9d1-1f9b0.png?v8",person_white_hair:"unicode/1f9d1-1f9b3.png?v8",person_with_probing_cane:"unicode/1f9d1-1f9af.png?v8",person_with_turban:"unicode/1f473.png?v8",person_with_veil:"unicode/1f470.png?v8",peru:"unicode/1f1f5-1f1ea.png?v8",petri_dish:"unicode/1f9eb.png?v8",philippines:"unicode/1f1f5-1f1ed.png?v8",phone:"unicode/260e.png?v8",pick:"unicode/26cf.png?v8",pickup_truck:"unicode/1f6fb.png?v8",pie:"unicode/1f967.png?v8",pig:"unicode/1f437.png?v8",pig2:"unicode/1f416.png?v8",pig_nose:"unicode/1f43d.png?v8",pill:"unicode/1f48a.png?v8",pilot:"unicode/1f9d1-2708.png?v8",pinata:"unicode/1fa85.png?v8",pinched_fingers:"unicode/1f90c.png?v8",pinching_hand:"unicode/1f90f.png?v8",pineapple:"unicode/1f34d.png?v8",ping_pong:"unicode/1f3d3.png?v8",pirate_flag:"unicode/1f3f4-2620.png?v8",pisces:"unicode/2653.png?v8",pitcairn_islands:"unicode/1f1f5-1f1f3.png?v8",pizza:"unicode/1f355.png?v8",placard:"unicode/1faa7.png?v8",place_of_worship:"unicode/1f6d0.png?v8",plate_with_cutlery:"unicode/1f37d.png?v8",play_or_pause_button:"unicode/23ef.png?v8",pleading_face:"unicode/1f97a.png?v8",plunger:"unicode/1faa0.png?v8",point_down:"unicode/1f447.png?v8",point_left:"unicode/1f448.png?v8",point_right:"unicode/1f449.png?v8",point_up:"unicode/261d.png?v8",point_up_2:"unicode/1f446.png?v8",poland:"unicode/1f1f5-1f1f1.png?v8",polar_bear:"unicode/1f43b-2744.png?v8",police_car:"unicode/1f693.png?v8",police_officer:"unicode/1f46e.png?v8",policeman:"unicode/1f46e-2642.png?v8",policewoman:"unicode/1f46e-2640.png?v8",poodle:"unicode/1f429.png?v8",poop:"unicode/1f4a9.png?v8",popcorn:"unicode/1f37f.png?v8",portugal:"unicode/1f1f5-1f1f9.png?v8",post_office:"unicode/1f3e3.png?v8",postal_horn:"unicode/1f4ef.png?v8",postbox:"unicode/1f4ee.png?v8",potable_water:"unicode/1f6b0.png?v8",potato:"unicode/1f954.png?v8",potted_plant:"unicode/1fab4.png?v8",pouch:"unicode/1f45d.png?v8",poultry_leg:"unicode/1f357.png?v8",pound:"unicode/1f4b7.png?v8",pout:"unicode/1f621.png?v8",pouting_cat:"unicode/1f63e.png?v8",pouting_face:"unicode/1f64e.png?v8",pouting_man:"unicode/1f64e-2642.png?v8",pouting_woman:"unicode/1f64e-2640.png?v8",pray:"unicode/1f64f.png?v8",prayer_beads:"unicode/1f4ff.png?v8",pregnant_woman:"unicode/1f930.png?v8",pretzel:"unicode/1f968.png?v8",previous_track_button:"unicode/23ee.png?v8",prince:"unicode/1f934.png?v8",princess:"unicode/1f478.png?v8",printer:"unicode/1f5a8.png?v8",probing_cane:"unicode/1f9af.png?v8",puerto_rico:"unicode/1f1f5-1f1f7.png?v8",punch:"unicode/1f44a.png?v8",purple_circle:"unicode/1f7e3.png?v8",purple_heart:"unicode/1f49c.png?v8",purple_square:"unicode/1f7ea.png?v8",purse:"unicode/1f45b.png?v8",pushpin:"unicode/1f4cc.png?v8",put_litter_in_its_place:"unicode/1f6ae.png?v8",qatar:"unicode/1f1f6-1f1e6.png?v8",question:"unicode/2753.png?v8",rabbit:"unicode/1f430.png?v8",rabbit2:"unicode/1f407.png?v8",raccoon:"unicode/1f99d.png?v8",racehorse:"unicode/1f40e.png?v8",racing_car:"unicode/1f3ce.png?v8",radio:"unicode/1f4fb.png?v8",radio_button:"unicode/1f518.png?v8",radioactive:"unicode/2622.png?v8",rage:"unicode/1f621.png?v8",rage1:"rage1.png?v8",rage2:"rage2.png?v8",rage3:"rage3.png?v8",rage4:"rage4.png?v8",railway_car:"unicode/1f683.png?v8",railway_track:"unicode/1f6e4.png?v8",rainbow:"unicode/1f308.png?v8",rainbow_flag:"unicode/1f3f3-1f308.png?v8",raised_back_of_hand:"unicode/1f91a.png?v8",raised_eyebrow:"unicode/1f928.png?v8",raised_hand:"unicode/270b.png?v8",raised_hand_with_fingers_splayed:"unicode/1f590.png?v8",raised_hands:"unicode/1f64c.png?v8",raising_hand:"unicode/1f64b.png?v8",raising_hand_man:"unicode/1f64b-2642.png?v8",raising_hand_woman:"unicode/1f64b-2640.png?v8",ram:"unicode/1f40f.png?v8",ramen:"unicode/1f35c.png?v8",rat:"unicode/1f400.png?v8",razor:"unicode/1fa92.png?v8",receipt:"unicode/1f9fe.png?v8",record_button:"unicode/23fa.png?v8",recycle:"unicode/267b.png?v8",red_car:"unicode/1f697.png?v8",red_circle:"unicode/1f534.png?v8",red_envelope:"unicode/1f9e7.png?v8",red_haired_man:"unicode/1f468-1f9b0.png?v8",red_haired_woman:"unicode/1f469-1f9b0.png?v8",red_square:"unicode/1f7e5.png?v8",registered:"unicode/00ae.png?v8",relaxed:"unicode/263a.png?v8",relieved:"unicode/1f60c.png?v8",reminder_ribbon:"unicode/1f397.png?v8",repeat:"unicode/1f501.png?v8",repeat_one:"unicode/1f502.png?v8",rescue_worker_helmet:"unicode/26d1.png?v8",restroom:"unicode/1f6bb.png?v8",reunion:"unicode/1f1f7-1f1ea.png?v8",revolving_hearts:"unicode/1f49e.png?v8",rewind:"unicode/23ea.png?v8",rhinoceros:"unicode/1f98f.png?v8",ribbon:"unicode/1f380.png?v8",rice:"unicode/1f35a.png?v8",rice_ball:"unicode/1f359.png?v8",rice_cracker:"unicode/1f358.png?v8",rice_scene:"unicode/1f391.png?v8",right_anger_bubble:"unicode/1f5ef.png?v8",ring:"unicode/1f48d.png?v8",ringed_planet:"unicode/1fa90.png?v8",robot:"unicode/1f916.png?v8",rock:"unicode/1faa8.png?v8",rocket:"unicode/1f680.png?v8",rofl:"unicode/1f923.png?v8",roll_eyes:"unicode/1f644.png?v8",roll_of_paper:"unicode/1f9fb.png?v8",roller_coaster:"unicode/1f3a2.png?v8",roller_skate:"unicode/1f6fc.png?v8",romania:"unicode/1f1f7-1f1f4.png?v8",rooster:"unicode/1f413.png?v8",rose:"unicode/1f339.png?v8",rosette:"unicode/1f3f5.png?v8",rotating_light:"unicode/1f6a8.png?v8",round_pushpin:"unicode/1f4cd.png?v8",rowboat:"unicode/1f6a3.png?v8",rowing_man:"unicode/1f6a3-2642.png?v8",rowing_woman:"unicode/1f6a3-2640.png?v8",ru:"unicode/1f1f7-1f1fa.png?v8",rugby_football:"unicode/1f3c9.png?v8",runner:"unicode/1f3c3.png?v8",running:"unicode/1f3c3.png?v8",running_man:"unicode/1f3c3-2642.png?v8",running_shirt_with_sash:"unicode/1f3bd.png?v8",running_woman:"unicode/1f3c3-2640.png?v8",rwanda:"unicode/1f1f7-1f1fc.png?v8",sa:"unicode/1f202.png?v8",safety_pin:"unicode/1f9f7.png?v8",safety_vest:"unicode/1f9ba.png?v8",sagittarius:"unicode/2650.png?v8",sailboat:"unicode/26f5.png?v8",sake:"unicode/1f376.png?v8",salt:"unicode/1f9c2.png?v8",samoa:"unicode/1f1fc-1f1f8.png?v8",san_marino:"unicode/1f1f8-1f1f2.png?v8",sandal:"unicode/1f461.png?v8",sandwich:"unicode/1f96a.png?v8",santa:"unicode/1f385.png?v8",sao_tome_principe:"unicode/1f1f8-1f1f9.png?v8",sari:"unicode/1f97b.png?v8",sassy_man:"unicode/1f481-2642.png?v8",sassy_woman:"unicode/1f481-2640.png?v8",satellite:"unicode/1f4e1.png?v8",satisfied:"unicode/1f606.png?v8",saudi_arabia:"unicode/1f1f8-1f1e6.png?v8",sauna_man:"unicode/1f9d6-2642.png?v8",sauna_person:"unicode/1f9d6.png?v8",sauna_woman:"unicode/1f9d6-2640.png?v8",sauropod:"unicode/1f995.png?v8",saxophone:"unicode/1f3b7.png?v8",scarf:"unicode/1f9e3.png?v8",school:"unicode/1f3eb.png?v8",school_satchel:"unicode/1f392.png?v8",scientist:"unicode/1f9d1-1f52c.png?v8",scissors:"unicode/2702.png?v8",scorpion:"unicode/1f982.png?v8",scorpius:"unicode/264f.png?v8",scotland:"unicode/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png?v8",scream:"unicode/1f631.png?v8",scream_cat:"unicode/1f640.png?v8",screwdriver:"unicode/1fa9b.png?v8",scroll:"unicode/1f4dc.png?v8",seal:"unicode/1f9ad.png?v8",seat:"unicode/1f4ba.png?v8",secret:"unicode/3299.png?v8",see_no_evil:"unicode/1f648.png?v8",seedling:"unicode/1f331.png?v8",selfie:"unicode/1f933.png?v8",senegal:"unicode/1f1f8-1f1f3.png?v8",serbia:"unicode/1f1f7-1f1f8.png?v8",service_dog:"unicode/1f415-1f9ba.png?v8",seven:"unicode/0037-20e3.png?v8",sewing_needle:"unicode/1faa1.png?v8",seychelles:"unicode/1f1f8-1f1e8.png?v8",shallow_pan_of_food:"unicode/1f958.png?v8",shamrock:"unicode/2618.png?v8",shark:"unicode/1f988.png?v8",shaved_ice:"unicode/1f367.png?v8",sheep:"unicode/1f411.png?v8",shell:"unicode/1f41a.png?v8",shield:"unicode/1f6e1.png?v8",shinto_shrine:"unicode/26e9.png?v8",ship:"unicode/1f6a2.png?v8",shipit:"shipit.png?v8",shirt:"unicode/1f455.png?v8",shit:"unicode/1f4a9.png?v8",shoe:"unicode/1f45e.png?v8",shopping:"unicode/1f6cd.png?v8",shopping_cart:"unicode/1f6d2.png?v8",shorts:"unicode/1fa73.png?v8",shower:"unicode/1f6bf.png?v8",shrimp:"unicode/1f990.png?v8",shrug:"unicode/1f937.png?v8",shushing_face:"unicode/1f92b.png?v8",sierra_leone:"unicode/1f1f8-1f1f1.png?v8",signal_strength:"unicode/1f4f6.png?v8",singapore:"unicode/1f1f8-1f1ec.png?v8",singer:"unicode/1f9d1-1f3a4.png?v8",sint_maarten:"unicode/1f1f8-1f1fd.png?v8",six:"unicode/0036-20e3.png?v8",six_pointed_star:"unicode/1f52f.png?v8",skateboard:"unicode/1f6f9.png?v8",ski:"unicode/1f3bf.png?v8",skier:"unicode/26f7.png?v8",skull:"unicode/1f480.png?v8",skull_and_crossbones:"unicode/2620.png?v8",skunk:"unicode/1f9a8.png?v8",sled:"unicode/1f6f7.png?v8",sleeping:"unicode/1f634.png?v8",sleeping_bed:"unicode/1f6cc.png?v8",sleepy:"unicode/1f62a.png?v8",slightly_frowning_face:"unicode/1f641.png?v8",slightly_smiling_face:"unicode/1f642.png?v8",slot_machine:"unicode/1f3b0.png?v8",sloth:"unicode/1f9a5.png?v8",slovakia:"unicode/1f1f8-1f1f0.png?v8",slovenia:"unicode/1f1f8-1f1ee.png?v8",small_airplane:"unicode/1f6e9.png?v8",small_blue_diamond:"unicode/1f539.png?v8",small_orange_diamond:"unicode/1f538.png?v8",small_red_triangle:"unicode/1f53a.png?v8",small_red_triangle_down:"unicode/1f53b.png?v8",smile:"unicode/1f604.png?v8",smile_cat:"unicode/1f638.png?v8",smiley:"unicode/1f603.png?v8",smiley_cat:"unicode/1f63a.png?v8",smiling_face_with_tear:"unicode/1f972.png?v8",smiling_face_with_three_hearts:"unicode/1f970.png?v8",smiling_imp:"unicode/1f608.png?v8",smirk:"unicode/1f60f.png?v8",smirk_cat:"unicode/1f63c.png?v8",smoking:"unicode/1f6ac.png?v8",snail:"unicode/1f40c.png?v8",snake:"unicode/1f40d.png?v8",sneezing_face:"unicode/1f927.png?v8",snowboarder:"unicode/1f3c2.png?v8",snowflake:"unicode/2744.png?v8",snowman:"unicode/26c4.png?v8",snowman_with_snow:"unicode/2603.png?v8",soap:"unicode/1f9fc.png?v8",sob:"unicode/1f62d.png?v8",soccer:"unicode/26bd.png?v8",socks:"unicode/1f9e6.png?v8",softball:"unicode/1f94e.png?v8",solomon_islands:"unicode/1f1f8-1f1e7.png?v8",somalia:"unicode/1f1f8-1f1f4.png?v8",soon:"unicode/1f51c.png?v8",sos:"unicode/1f198.png?v8",sound:"unicode/1f509.png?v8",south_africa:"unicode/1f1ff-1f1e6.png?v8",south_georgia_south_sandwich_islands:"unicode/1f1ec-1f1f8.png?v8",south_sudan:"unicode/1f1f8-1f1f8.png?v8",space_invader:"unicode/1f47e.png?v8",spades:"unicode/2660.png?v8",spaghetti:"unicode/1f35d.png?v8",sparkle:"unicode/2747.png?v8",sparkler:"unicode/1f387.png?v8",sparkles:"unicode/2728.png?v8",sparkling_heart:"unicode/1f496.png?v8",speak_no_evil:"unicode/1f64a.png?v8",speaker:"unicode/1f508.png?v8",speaking_head:"unicode/1f5e3.png?v8",speech_balloon:"unicode/1f4ac.png?v8",speedboat:"unicode/1f6a4.png?v8",spider:"unicode/1f577.png?v8",spider_web:"unicode/1f578.png?v8",spiral_calendar:"unicode/1f5d3.png?v8",spiral_notepad:"unicode/1f5d2.png?v8",sponge:"unicode/1f9fd.png?v8",spoon:"unicode/1f944.png?v8",squid:"unicode/1f991.png?v8",sri_lanka:"unicode/1f1f1-1f1f0.png?v8",st_barthelemy:"unicode/1f1e7-1f1f1.png?v8",st_helena:"unicode/1f1f8-1f1ed.png?v8",st_kitts_nevis:"unicode/1f1f0-1f1f3.png?v8",st_lucia:"unicode/1f1f1-1f1e8.png?v8",st_martin:"unicode/1f1f2-1f1eb.png?v8",st_pierre_miquelon:"unicode/1f1f5-1f1f2.png?v8",st_vincent_grenadines:"unicode/1f1fb-1f1e8.png?v8",stadium:"unicode/1f3df.png?v8",standing_man:"unicode/1f9cd-2642.png?v8",standing_person:"unicode/1f9cd.png?v8",standing_woman:"unicode/1f9cd-2640.png?v8",star:"unicode/2b50.png?v8",star2:"unicode/1f31f.png?v8",star_and_crescent:"unicode/262a.png?v8",star_of_david:"unicode/2721.png?v8",star_struck:"unicode/1f929.png?v8",stars:"unicode/1f320.png?v8",station:"unicode/1f689.png?v8",statue_of_liberty:"unicode/1f5fd.png?v8",steam_locomotive:"unicode/1f682.png?v8",stethoscope:"unicode/1fa7a.png?v8",stew:"unicode/1f372.png?v8",stop_button:"unicode/23f9.png?v8",stop_sign:"unicode/1f6d1.png?v8",stopwatch:"unicode/23f1.png?v8",straight_ruler:"unicode/1f4cf.png?v8",strawberry:"unicode/1f353.png?v8",stuck_out_tongue:"unicode/1f61b.png?v8",stuck_out_tongue_closed_eyes:"unicode/1f61d.png?v8",stuck_out_tongue_winking_eye:"unicode/1f61c.png?v8",student:"unicode/1f9d1-1f393.png?v8",studio_microphone:"unicode/1f399.png?v8",stuffed_flatbread:"unicode/1f959.png?v8",sudan:"unicode/1f1f8-1f1e9.png?v8",sun_behind_large_cloud:"unicode/1f325.png?v8",sun_behind_rain_cloud:"unicode/1f326.png?v8",sun_behind_small_cloud:"unicode/1f324.png?v8",sun_with_face:"unicode/1f31e.png?v8",sunflower:"unicode/1f33b.png?v8",sunglasses:"unicode/1f60e.png?v8",sunny:"unicode/2600.png?v8",sunrise:"unicode/1f305.png?v8",sunrise_over_mountains:"unicode/1f304.png?v8",superhero:"unicode/1f9b8.png?v8",superhero_man:"unicode/1f9b8-2642.png?v8",superhero_woman:"unicode/1f9b8-2640.png?v8",supervillain:"unicode/1f9b9.png?v8",supervillain_man:"unicode/1f9b9-2642.png?v8",supervillain_woman:"unicode/1f9b9-2640.png?v8",surfer:"unicode/1f3c4.png?v8",surfing_man:"unicode/1f3c4-2642.png?v8",surfing_woman:"unicode/1f3c4-2640.png?v8",suriname:"unicode/1f1f8-1f1f7.png?v8",sushi:"unicode/1f363.png?v8",suspect:"suspect.png?v8",suspension_railway:"unicode/1f69f.png?v8",svalbard_jan_mayen:"unicode/1f1f8-1f1ef.png?v8",swan:"unicode/1f9a2.png?v8",swaziland:"unicode/1f1f8-1f1ff.png?v8",sweat:"unicode/1f613.png?v8",sweat_drops:"unicode/1f4a6.png?v8",sweat_smile:"unicode/1f605.png?v8",sweden:"unicode/1f1f8-1f1ea.png?v8",sweet_potato:"unicode/1f360.png?v8",swim_brief:"unicode/1fa72.png?v8",swimmer:"unicode/1f3ca.png?v8",swimming_man:"unicode/1f3ca-2642.png?v8",swimming_woman:"unicode/1f3ca-2640.png?v8",switzerland:"unicode/1f1e8-1f1ed.png?v8",symbols:"unicode/1f523.png?v8",synagogue:"unicode/1f54d.png?v8",syria:"unicode/1f1f8-1f1fe.png?v8",syringe:"unicode/1f489.png?v8","t-rex":"unicode/1f996.png?v8",taco:"unicode/1f32e.png?v8",tada:"unicode/1f389.png?v8",taiwan:"unicode/1f1f9-1f1fc.png?v8",tajikistan:"unicode/1f1f9-1f1ef.png?v8",takeout_box:"unicode/1f961.png?v8",tamale:"unicode/1fad4.png?v8",tanabata_tree:"unicode/1f38b.png?v8",tangerine:"unicode/1f34a.png?v8",tanzania:"unicode/1f1f9-1f1ff.png?v8",taurus:"unicode/2649.png?v8",taxi:"unicode/1f695.png?v8",tea:"unicode/1f375.png?v8",teacher:"unicode/1f9d1-1f3eb.png?v8",teapot:"unicode/1fad6.png?v8",technologist:"unicode/1f9d1-1f4bb.png?v8",teddy_bear:"unicode/1f9f8.png?v8",telephone:"unicode/260e.png?v8",telephone_receiver:"unicode/1f4de.png?v8",telescope:"unicode/1f52d.png?v8",tennis:"unicode/1f3be.png?v8",tent:"unicode/26fa.png?v8",test_tube:"unicode/1f9ea.png?v8",thailand:"unicode/1f1f9-1f1ed.png?v8",thermometer:"unicode/1f321.png?v8",thinking:"unicode/1f914.png?v8",thong_sandal:"unicode/1fa74.png?v8",thought_balloon:"unicode/1f4ad.png?v8",thread:"unicode/1f9f5.png?v8",three:"unicode/0033-20e3.png?v8",thumbsdown:"unicode/1f44e.png?v8",thumbsup:"unicode/1f44d.png?v8",ticket:"unicode/1f3ab.png?v8",tickets:"unicode/1f39f.png?v8",tiger:"unicode/1f42f.png?v8",tiger2:"unicode/1f405.png?v8",timer_clock:"unicode/23f2.png?v8",timor_leste:"unicode/1f1f9-1f1f1.png?v8",tipping_hand_man:"unicode/1f481-2642.png?v8",tipping_hand_person:"unicode/1f481.png?v8",tipping_hand_woman:"unicode/1f481-2640.png?v8",tired_face:"unicode/1f62b.png?v8",tm:"unicode/2122.png?v8",togo:"unicode/1f1f9-1f1ec.png?v8",toilet:"unicode/1f6bd.png?v8",tokelau:"unicode/1f1f9-1f1f0.png?v8",tokyo_tower:"unicode/1f5fc.png?v8",tomato:"unicode/1f345.png?v8",tonga:"unicode/1f1f9-1f1f4.png?v8",tongue:"unicode/1f445.png?v8",toolbox:"unicode/1f9f0.png?v8",tooth:"unicode/1f9b7.png?v8",toothbrush:"unicode/1faa5.png?v8",top:"unicode/1f51d.png?v8",tophat:"unicode/1f3a9.png?v8",tornado:"unicode/1f32a.png?v8",tr:"unicode/1f1f9-1f1f7.png?v8",trackball:"unicode/1f5b2.png?v8",tractor:"unicode/1f69c.png?v8",traffic_light:"unicode/1f6a5.png?v8",train:"unicode/1f68b.png?v8",train2:"unicode/1f686.png?v8",tram:"unicode/1f68a.png?v8",transgender_flag:"unicode/1f3f3-26a7.png?v8",transgender_symbol:"unicode/26a7.png?v8",triangular_flag_on_post:"unicode/1f6a9.png?v8",triangular_ruler:"unicode/1f4d0.png?v8",trident:"unicode/1f531.png?v8",trinidad_tobago:"unicode/1f1f9-1f1f9.png?v8",tristan_da_cunha:"unicode/1f1f9-1f1e6.png?v8",triumph:"unicode/1f624.png?v8",trolleybus:"unicode/1f68e.png?v8",trollface:"trollface.png?v8",trophy:"unicode/1f3c6.png?v8",tropical_drink:"unicode/1f379.png?v8",tropical_fish:"unicode/1f420.png?v8",truck:"unicode/1f69a.png?v8",trumpet:"unicode/1f3ba.png?v8",tshirt:"unicode/1f455.png?v8",tulip:"unicode/1f337.png?v8",tumbler_glass:"unicode/1f943.png?v8",tunisia:"unicode/1f1f9-1f1f3.png?v8",turkey:"unicode/1f983.png?v8",turkmenistan:"unicode/1f1f9-1f1f2.png?v8",turks_caicos_islands:"unicode/1f1f9-1f1e8.png?v8",turtle:"unicode/1f422.png?v8",tuvalu:"unicode/1f1f9-1f1fb.png?v8",tv:"unicode/1f4fa.png?v8",twisted_rightwards_arrows:"unicode/1f500.png?v8",two:"unicode/0032-20e3.png?v8",two_hearts:"unicode/1f495.png?v8",two_men_holding_hands:"unicode/1f46c.png?v8",two_women_holding_hands:"unicode/1f46d.png?v8",u5272:"unicode/1f239.png?v8",u5408:"unicode/1f234.png?v8",u55b6:"unicode/1f23a.png?v8",u6307:"unicode/1f22f.png?v8",u6708:"unicode/1f237.png?v8",u6709:"unicode/1f236.png?v8",u6e80:"unicode/1f235.png?v8",u7121:"unicode/1f21a.png?v8",u7533:"unicode/1f238.png?v8",u7981:"unicode/1f232.png?v8",u7a7a:"unicode/1f233.png?v8",uganda:"unicode/1f1fa-1f1ec.png?v8",uk:"unicode/1f1ec-1f1e7.png?v8",ukraine:"unicode/1f1fa-1f1e6.png?v8",umbrella:"unicode/2614.png?v8",unamused:"unicode/1f612.png?v8",underage:"unicode/1f51e.png?v8",unicorn:"unicode/1f984.png?v8",united_arab_emirates:"unicode/1f1e6-1f1ea.png?v8",united_nations:"unicode/1f1fa-1f1f3.png?v8",unlock:"unicode/1f513.png?v8",up:"unicode/1f199.png?v8",upside_down_face:"unicode/1f643.png?v8",uruguay:"unicode/1f1fa-1f1fe.png?v8",us:"unicode/1f1fa-1f1f8.png?v8",us_outlying_islands:"unicode/1f1fa-1f1f2.png?v8",us_virgin_islands:"unicode/1f1fb-1f1ee.png?v8",uzbekistan:"unicode/1f1fa-1f1ff.png?v8",v:"unicode/270c.png?v8",vampire:"unicode/1f9db.png?v8",vampire_man:"unicode/1f9db-2642.png?v8",vampire_woman:"unicode/1f9db-2640.png?v8",vanuatu:"unicode/1f1fb-1f1fa.png?v8",vatican_city:"unicode/1f1fb-1f1e6.png?v8",venezuela:"unicode/1f1fb-1f1ea.png?v8",vertical_traffic_light:"unicode/1f6a6.png?v8",vhs:"unicode/1f4fc.png?v8",vibration_mode:"unicode/1f4f3.png?v8",video_camera:"unicode/1f4f9.png?v8",video_game:"unicode/1f3ae.png?v8",vietnam:"unicode/1f1fb-1f1f3.png?v8",violin:"unicode/1f3bb.png?v8",virgo:"unicode/264d.png?v8",volcano:"unicode/1f30b.png?v8",volleyball:"unicode/1f3d0.png?v8",vomiting_face:"unicode/1f92e.png?v8",vs:"unicode/1f19a.png?v8",vulcan_salute:"unicode/1f596.png?v8",waffle:"unicode/1f9c7.png?v8",wales:"unicode/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png?v8",walking:"unicode/1f6b6.png?v8",walking_man:"unicode/1f6b6-2642.png?v8",walking_woman:"unicode/1f6b6-2640.png?v8",wallis_futuna:"unicode/1f1fc-1f1eb.png?v8",waning_crescent_moon:"unicode/1f318.png?v8",waning_gibbous_moon:"unicode/1f316.png?v8",warning:"unicode/26a0.png?v8",wastebasket:"unicode/1f5d1.png?v8",watch:"unicode/231a.png?v8",water_buffalo:"unicode/1f403.png?v8",water_polo:"unicode/1f93d.png?v8",watermelon:"unicode/1f349.png?v8",wave:"unicode/1f44b.png?v8",wavy_dash:"unicode/3030.png?v8",waxing_crescent_moon:"unicode/1f312.png?v8",waxing_gibbous_moon:"unicode/1f314.png?v8",wc:"unicode/1f6be.png?v8",weary:"unicode/1f629.png?v8",wedding:"unicode/1f492.png?v8",weight_lifting:"unicode/1f3cb.png?v8",weight_lifting_man:"unicode/1f3cb-2642.png?v8",weight_lifting_woman:"unicode/1f3cb-2640.png?v8",western_sahara:"unicode/1f1ea-1f1ed.png?v8",whale:"unicode/1f433.png?v8",whale2:"unicode/1f40b.png?v8",wheel_of_dharma:"unicode/2638.png?v8",wheelchair:"unicode/267f.png?v8",white_check_mark:"unicode/2705.png?v8",white_circle:"unicode/26aa.png?v8",white_flag:"unicode/1f3f3.png?v8",white_flower:"unicode/1f4ae.png?v8",white_haired_man:"unicode/1f468-1f9b3.png?v8",white_haired_woman:"unicode/1f469-1f9b3.png?v8",white_heart:"unicode/1f90d.png?v8",white_large_square:"unicode/2b1c.png?v8",white_medium_small_square:"unicode/25fd.png?v8",white_medium_square:"unicode/25fb.png?v8",white_small_square:"unicode/25ab.png?v8",white_square_button:"unicode/1f533.png?v8",wilted_flower:"unicode/1f940.png?v8",wind_chime:"unicode/1f390.png?v8",wind_face:"unicode/1f32c.png?v8",window:"unicode/1fa9f.png?v8",wine_glass:"unicode/1f377.png?v8",wink:"unicode/1f609.png?v8",wolf:"unicode/1f43a.png?v8",woman:"unicode/1f469.png?v8",woman_artist:"unicode/1f469-1f3a8.png?v8",woman_astronaut:"unicode/1f469-1f680.png?v8",woman_beard:"unicode/1f9d4-2640.png?v8",woman_cartwheeling:"unicode/1f938-2640.png?v8",woman_cook:"unicode/1f469-1f373.png?v8",woman_dancing:"unicode/1f483.png?v8",woman_facepalming:"unicode/1f926-2640.png?v8",woman_factory_worker:"unicode/1f469-1f3ed.png?v8",woman_farmer:"unicode/1f469-1f33e.png?v8",woman_feeding_baby:"unicode/1f469-1f37c.png?v8",woman_firefighter:"unicode/1f469-1f692.png?v8",woman_health_worker:"unicode/1f469-2695.png?v8",woman_in_manual_wheelchair:"unicode/1f469-1f9bd.png?v8",woman_in_motorized_wheelchair:"unicode/1f469-1f9bc.png?v8",woman_in_tuxedo:"unicode/1f935-2640.png?v8",woman_judge:"unicode/1f469-2696.png?v8",woman_juggling:"unicode/1f939-2640.png?v8",woman_mechanic:"unicode/1f469-1f527.png?v8",woman_office_worker:"unicode/1f469-1f4bc.png?v8",woman_pilot:"unicode/1f469-2708.png?v8",woman_playing_handball:"unicode/1f93e-2640.png?v8",woman_playing_water_polo:"unicode/1f93d-2640.png?v8",woman_scientist:"unicode/1f469-1f52c.png?v8",woman_shrugging:"unicode/1f937-2640.png?v8",woman_singer:"unicode/1f469-1f3a4.png?v8",woman_student:"unicode/1f469-1f393.png?v8",woman_teacher:"unicode/1f469-1f3eb.png?v8",woman_technologist:"unicode/1f469-1f4bb.png?v8",woman_with_headscarf:"unicode/1f9d5.png?v8",woman_with_probing_cane:"unicode/1f469-1f9af.png?v8",woman_with_turban:"unicode/1f473-2640.png?v8",woman_with_veil:"unicode/1f470-2640.png?v8",womans_clothes:"unicode/1f45a.png?v8",womans_hat:"unicode/1f452.png?v8",women_wrestling:"unicode/1f93c-2640.png?v8",womens:"unicode/1f6ba.png?v8",wood:"unicode/1fab5.png?v8",woozy_face:"unicode/1f974.png?v8",world_map:"unicode/1f5fa.png?v8",worm:"unicode/1fab1.png?v8",worried:"unicode/1f61f.png?v8",wrench:"unicode/1f527.png?v8",wrestling:"unicode/1f93c.png?v8",writing_hand:"unicode/270d.png?v8",x:"unicode/274c.png?v8",yarn:"unicode/1f9f6.png?v8",yawning_face:"unicode/1f971.png?v8",yellow_circle:"unicode/1f7e1.png?v8",yellow_heart:"unicode/1f49b.png?v8",yellow_square:"unicode/1f7e8.png?v8",yemen:"unicode/1f1fe-1f1ea.png?v8",yen:"unicode/1f4b4.png?v8",yin_yang:"unicode/262f.png?v8",yo_yo:"unicode/1fa80.png?v8",yum:"unicode/1f60b.png?v8",zambia:"unicode/1f1ff-1f1f2.png?v8",zany_face:"unicode/1f92a.png?v8",zap:"unicode/26a1.png?v8",zebra:"unicode/1f993.png?v8",zero:"unicode/0030-20e3.png?v8",zimbabwe:"unicode/1f1ff-1f1fc.png?v8",zipper_mouth_face:"unicode/1f910.png?v8",zombie:"unicode/1f9df.png?v8",zombie_man:"unicode/1f9df-2642.png?v8",zombie_woman:"unicode/1f9df-2640.png?v8",zzz:"unicode/1f4a4.png?v8"}};function jn(e,t){return e.replace(/<(code|pre|script|template)[^>]*?>[\s\S]+?<\/(code|pre|script|template)>/g,function(e){return e.replace(/:/g,"__colon__")}).replace(//g,function(e){return e.replace(/:/g,"__colon__")}).replace(/([a-z]{2,}:)?\/\/[^\s'">)]+/gi,function(e){return e.replace(/:/g,"__colon__")}).replace(/:([a-z0-9_\-+]+?):/g,function(e,n){return i=e,o=n,e=t,n=Cn.data[o],i,i=n?e&&/unicode/.test(n)?''+n.replace("unicode/","").replace(/\.png.*/,"").split("-").map(function(e){return"&#x"+e+";"}).join("‍").concat("︎")+"":''+o+'':i;var i,o}).replace(/__colon__/g,":")}function Ln(e){var o={};return{str:e=(e=void 0===e?"":e)&&e.replace(/^('|")/,"").replace(/('|")$/,"").replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g,function(e,n,i){return-1===n.indexOf(":")?(o[n]=i&&i.replace(/"/g,"")||!0,""):e}).trim(),config:o}}function On(e){return(e=void 0===e?"":e).replace(/(<\/?a.*?>)/gi,"")}var qn,Pn=be(function(e){var u,f,p,d,n,g=function(u){var i=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,n=0,e={},R={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof T?new T(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=r.reach);m+=_.value.length,_=_.next){var b=_.value;if(i.length>n.length)return;if(!(b instanceof T)){var k,w=1;if(l){if(!(k=C(h,m,n,s))||k.index>=n.length)break;var y=k.index,x=k.index+k[0].length,S=m;for(S+=_.value.length;S<=y;)_=_.next,S+=_.value.length;if(S-=_.value.length,m=S,_.value instanceof T)continue;for(var A=_;A!==i.tail&&(Sr.reach&&(r.reach=E);b=_.prev;z&&(b=j(i,b,z),m+=z.length),L(i,b,w);$=new T(c,g?R.tokenize($,g):$,v,$);_=j(i,b,$),F&&j(i,_,F),1r.reach&&(r.reach=E.reach))}}}}}(e,t,n,t.head,0),function(e){var n=[],i=e.head.next;for(;i!==e.tail;)n.push(i.value),i=i.next;return n}(t)},hooks:{all:{},add:function(e,n){var i=R.hooks.all;i[e]=i[e]||[],i[e].push(n)},run:function(e,n){var i=R.hooks.all[e];if(i&&i.length)for(var o,t=0;o=i[t++];)o(n)}},Token:T};function T(e,n,i,o){this.type=e,this.content=n,this.alias=i,this.length=0|(o||"").length}function C(e,n,i,o){e.lastIndex=n;i=e.exec(i);return i&&o&&i[1]&&(o=i[1].length,i.index+=o,i[0]=i[0].slice(o)),i}function a(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function j(e,n,i){var o=n.next,i={value:i,prev:n,next:o};return n.next=i,o.prev=i,e.length++,i}function L(e,n,i){for(var o=n.next,t=0;t"+t.content+""},!u.document)return u.addEventListener&&(R.disableWorkerMessageHandler||u.addEventListener("message",function(e){var n=JSON.parse(e.data),i=n.language,e=n.code,n=n.immediateClose;u.postMessage(R.highlight(e,R.languages[i],i)),n&&u.close()},!1)),R;var o=R.util.currentScript();function t(){R.manual||R.highlightAll()}return o&&(R.filename=o.src,o.hasAttribute("data-manual")&&(R.manual=!0)),R.manual||("loading"===(e=document.readyState)||"interactive"===e&&o&&o.defer?document.addEventListener("DOMContentLoaded",t):window.requestAnimationFrame?window.requestAnimationFrame(t):window.setTimeout(t,16)),R}("undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{});e.exports&&(e.exports=g),void 0!==me&&(me.Prism=g),g.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},g.languages.markup.tag.inside["attr-value"].inside.entity=g.languages.markup.entity,g.languages.markup.doctype.inside["internal-subset"].inside=g.languages.markup,g.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))}),Object.defineProperty(g.languages.markup.tag,"addInlined",{value:function(e,n){var i={};i["language-"+n]={pattern:/(^$)/i,lookbehind:!0,inside:g.languages[n]},i.cdata=/^$/i;i={"included-cdata":{pattern://i,inside:i}};i["language-"+n]={pattern:/[\s\S]+/,inside:g.languages[n]};n={};n[e]={pattern:RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g,function(){return e}),"i"),lookbehind:!0,greedy:!0,inside:i},g.languages.insertBefore("markup","cdata",n)}}),Object.defineProperty(g.languages.markup.tag,"addAttribute",{value:function(e,n){g.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[n,"language-"+n],inside:g.languages[n]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),g.languages.html=g.languages.markup,g.languages.mathml=g.languages.markup,g.languages.svg=g.languages.markup,g.languages.xml=g.languages.extend("markup",{}),g.languages.ssml=g.languages.xml,g.languages.atom=g.languages.xml,g.languages.rss=g.languages.xml,function(e){var n=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:"+/[^;{\s"']|\s+(?!\s)/.source+"|"+n.source+")*?"+/(?:;|(?=\s*\{))/.source),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+n.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+n.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+n.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:n,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;e=e.languages.markup;e&&(e.tag.addInlined("style","css"),e.tag.addAttribute("style","css"))}(g),g.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},g.languages.javascript=g.languages.extend("clike",{"class-name":[g.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),g.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,g.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp(/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source+/\//.source+"(?:"+/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source+"|"+/(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source+")"+/(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:g.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:g.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:g.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:g.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:g.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),g.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:g.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),g.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),g.languages.markup&&(g.languages.markup.tag.addInlined("script","javascript"),g.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),g.languages.js=g.languages.javascript,void 0!==g&&"undefined"!=typeof document&&(Element.prototype.matches||(Element.prototype.matches=Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector),u={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"},d="pre[data-src]:not(["+(f="data-src-status")+'="loaded"]):not(['+f+'="'+(p="loading")+'"])',g.hooks.add("before-highlightall",function(e){e.selector+=", "+d}),g.hooks.add("before-sanity-check",function(e){var t,n,i,o,a,r,c=e.element;c.matches(d)&&(e.code="",c.setAttribute(f,p),(t=c.appendChild(document.createElement("CODE"))).textContent="Loading…",i=c.getAttribute("data-src"),"none"===(e=e.language)&&(n=(/\.(\w+)$/.exec(i)||[,"none"])[1],e=u[n]||n),g.util.setLanguage(t,e),g.util.setLanguage(c,e),(n=g.plugins.autoloader)&&n.loadLanguages(e),i=i,o=function(e){c.setAttribute(f,"loaded");var n,i,o=function(e){if(i=/^\s*(\d+)\s*(?:(,)\s*(?:(\d+)\s*)?)?$/.exec(e||"")){var n=Number(i[1]),e=i[2],i=i[3];return e?i?[n,Number(i)]:[n,void 0]:[n,n]}}(c.getAttribute("data-range"));o&&(n=e.split(/\r\n?|\n/g),i=o[0],o=null==o[1]?n.length:o[1],i<0&&(i+=n.length),i=Math.max(0,Math.min(i-1,n.length)),o<0&&(o+=n.length),o=Math.max(0,Math.min(o,n.length)),e=n.slice(i,o).join("\n"),c.hasAttribute("data-start")||c.setAttribute("data-start",String(i+1))),t.textContent=e,g.highlightElement(t)},a=function(e){c.setAttribute(f,"failed"),t.textContent=e},(r=new XMLHttpRequest).open("GET",i,!0),r.onreadystatechange=function(){4==r.readyState&&(r.status<400&&r.responseText?o(r.responseText):400<=r.status?a("✖ Error "+r.status+" while fetching file: "+r.statusText):a("✖ Error: File does not exist or is empty"))},r.send(null))}),n=!(g.plugins.fileHighlight={highlight:function(e){for(var n,i=(e||document).querySelectorAll(d),o=0;n=i[o++];)g.highlightElement(n)}}),g.fileHighlight=function(){n||(console.warn("Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead."),n=!0),g.plugins.fileHighlight.highlight.apply(this,arguments)})});function Mn(e,n){return"___"+e.toUpperCase()+n+"___"}qn=Prism,Object.defineProperties(qn.languages["markup-templating"]={},{buildPlaceholders:{value:function(o,t,e,a){var r;o.language===t&&(r=o.tokenStack=[],o.code=o.code.replace(e,function(e){if("function"==typeof a&&!a(e))return e;for(var n,i=r.length;-1!==o.code.indexOf(n=Mn(t,i));)++i;return r[i]=e,n}),o.grammar=qn.languages.markup)}},tokenizePlaceholders:{value:function(f,p){var d,g;f.language===p&&f.tokenStack&&(f.grammar=qn.languages[p],d=0,g=Object.keys(f.tokenStack),function e(n){for(var i=0;i=g.length);i++){var o,t,a,r,c,u=n[i];"string"==typeof u||u.content&&"string"==typeof u.content?(t=g[d],a=f.tokenStack[t],o="string"==typeof u?u:u.content,c=Mn(p,t),-1<(r=o.indexOf(c))&&(++d,t=o.substring(0,r),a=new qn.Token(p,qn.tokenize(a,f.grammar),"language-"+p,a),r=o.substring(r+c.length),c=[],t&&c.push.apply(c,e([t])),c.push(a),r&&c.push.apply(c,e([r])),"string"==typeof u?n.splice.apply(n,[i,1].concat(c)):u.content=c)):u.content&&e(u.content)}return n}(f.tokens))}}});function In(t,e){var a=this;this.config=t,this.router=e,this.cacheTree={},this.toc=[],this.cacheTOC={},this.linkTarget=t.externalLinkTarget||"_blank",this.linkRel="_blank"===this.linkTarget?t.externalLinkRel||"noopener":"",this.contentBase=e.getBasePath();var n=this._initRenderer();this.heading=n.heading;var r=o(e=t.markdown||{})?e(Sn,n):(Sn.setOptions(m(e,{renderer:m(n,e.renderer)})),Sn);this._marked=r,this.compile=function(i){var o=!0,e=c(function(e){o=!1;var n="";return i&&(n=f(i)?r(i):r.parser(i),n=t.noEmoji?n:jn(n,t.nativeEmoji),Tn.clear(),n)})(i),n=a.router.parse().file;return o?a.toc=a.cacheTOC[n]:a.cacheTOC[n]=[].concat(a.toc),e}}var Nn={},Hn={markdown:function(e){return{url:e}},mermaid:function(e){return{url:e}},iframe:function(e,n){return{html:'"}},video:function(e,n){return{html:'"}},audio:function(e,n){return{html:'"}},code:function(e,n){var i=e.match(/\.(\w+)$/);return{url:e,lang:i="md"===(i=n||i&&i[1])?"markdown":i}}};In.prototype.compileEmbed=function(e,n){var i,o,t=Ln(n),a=t.str,t=t.config;if(n=a,t.include)return R(e)||(e=q(this.contentBase,C(this.router.getCurrentPath()),e)),t.type&&(o=Hn[t.type])?(i=o.call(this,e,n)).type=t.type:(o="code",/\.(md|markdown)/.test(e)?o="markdown":/\.mmd/.test(e)?o="mermaid":/\.html?/.test(e)?o="iframe":/\.(mp4|ogg)/.test(e)?o="video":/\.mp3/.test(e)&&(o="audio"),(i=Hn[o].call(this,e,n)).type=o),i.fragment=t.fragment,i},In.prototype._matchNotCompileLink=function(e){for(var n=this.config.noCompileLinks||[],i=0;i/g.test(o)&&(o=o.replace("\x3c!-- {docsify-ignore} --\x3e",""),e.title=On(o),e.ignoreSubHeading=!0),/{docsify-ignore}/g.test(o)&&(o=o.replace("{docsify-ignore}",""),e.title=On(o),e.ignoreSubHeading=!0),//g.test(o)&&(o=o.replace("\x3c!-- {docsify-ignore-all} --\x3e",""),e.title=On(o),e.ignoreAllSubs=!0),/{docsify-ignore-all}/g.test(o)&&(o=o.replace("{docsify-ignore-all}",""),e.title=On(o),e.ignoreAllSubs=!0);i=Tn(t.id||o),t=a.toURL(a.getCurrentPath(),{id:i});return e.slug=t,g.toc.push(e),"'+o+""},t.code={renderer:e}.renderer.code=function(e,n){var i=Pn.languages[n=void 0===n?"markup":n]||Pn.languages.markup;return'
    '+Pn.highlight(e.replace(/@DOCSIFY_QM@/g,"`"),i,n)+"
    "},t.link=(i=(n={renderer:e,router:a,linkTarget:n,linkRel:i,compilerClass:g}).renderer,c=n.router,u=n.linkTarget,n.linkRel,f=n.compilerClass,i.link=function(e,n,i){var o=[],t=Ln(n=void 0===n?"":n),a=t.str,t=t.config;return u=t.target||u,r="_blank"===u?f.config.externalLinkRel||"noopener":"",n=a,R(e)||f._matchNotCompileLink(e)||t.ignore?(R(e)||"./"!==e.slice(0,2)||(e=document.URL.replace(/\/(?!.*\/).*/,"/").replace("#/./","")+e),o.push(0===e.indexOf("mailto:")?"":'target="'+u+'"'),o.push(0!==e.indexOf("mailto:")&&""!==r?' rel="'+r+'"':"")):(e===f.config.homepage&&(e="README"),e=c.toURL(e,null,c.getCurrentPath())),t.disabled&&(o.push("disabled"),e="javascript:void(0)"),t.class&&o.push('class="'+t.class+'"'),t.id&&o.push('id="'+t.id+'"'),n&&o.push('title="'+n+'"'),'"+i+""}),t.paragraph={renderer:e}.renderer.paragraph=function(e){e=/^!>/.test(e)?$n("tip",e):/^\?>/.test(e)?$n("warn",e):"

    "+e+"

    ";return e},t.image=(o=(i={renderer:e,contentBase:o,router:a}).renderer,p=i.contentBase,d=i.router,o.image=function(e,n,i){var o=e,t=[],a=Ln(n),r=a.str,a=a.config;return n=r,a["no-zoom"]&&t.push("data-no-zoom"),n&&t.push('title="'+n+'"'),a.size&&(n=(r=a.size.split("x"))[0],(r=r[1])?t.push('width="'+n+'" height="'+r+'"'):t.push('width="'+n+'"')),a.class&&t.push('class="'+a.class+'"'),a.id&&t.push('id="'+a.id+'"'),R(e)||(o=q(p,C(d.getCurrentPath()),e)),0":''+i+'"}),t.list={renderer:e}.renderer.list=function(e,n,i){n=n?"ol":"ul";return"<"+n+" "+[/
  • /.test(e.split('class="task-list"')[0])?'class="task-list"':"",i&&1"+e+""},t.listitem={renderer:e}.renderer.listitem=function(e){return/^(]*>)/.test(e)?'
  • ":"
  • "+e+"
  • "},e.origin=t,e},In.prototype.sidebar=function(e,n){var i=this.toc,o=this.router.getCurrentPath(),t="";if(e)t=this.compile(e);else{for(var a=0;a{inner}");this.cacheTree[o]=n}return t},In.prototype.subSidebar=function(e){if(e){var n=this.router.getCurrentPath(),i=this.cacheTree,o=this.toc;o[0]&&o[0].ignoreAllSubs&&o.splice(0),o[0]&&1===o[0].level&&o.shift();for(var t=0;t\n'+e+"\n"}]).links={}:(n=[{type:"html",text:e}]).links={}),a({token:t,embedToken:n}),++u>=c&&a({})}}(n);n.embed.url?X(n.embed.url).then(o):o(n.embed.html)}}({compile:i,embedTokens:c,fetch:n},function(e){var n,i=e.embedToken,e=e.token;e?(n=e.index,p.forEach(function(e){n>e.start&&(n+=e.length)}),m(f,i.links),r=r.slice(0,n).concat(i,r.slice(n+1)),p.push({start:n,length:i.length-1})):(Bn[t]=r.concat(),r.links=Bn[t].links=f,o(r))})}function Yn(e,n,i){var o,t,a,r;return n="function"==typeof i?i(n):"string"==typeof i?(a=[],r=0,(o=i).replace(V,function(n,e,i){a.push(o.substring(r,i-1)),r=i+=n.length+1,a.push(t&&t[n]||function(e){return("00"+("string"==typeof Y[n]?e[Y[n]]():Y[n](e))).slice(-n.length)})}),r!==o.length&&a.push(o.substring(r)),function(e){for(var n="",i=0,o=e||new Date;i404 - Not found","Vue"in window)for(var a=0,r=k(".markdown-section > *").filter(n);ascript").filter(function(e){return!/template/.test(e.type)})[0])||(e=e.innerText.trim())&&new Function(e)()),"Vue"in window){var u,f,p=[],d=Object.keys(i.vueComponents||{});2===t&&d.length&&d.forEach(function(e){window.Vue.options.components[e]||window.Vue.component(e,i.vueComponents[e])}),!Un&&i.vueGlobalOptions&&"function"==typeof i.vueGlobalOptions.data&&(Un=i.vueGlobalOptions.data()),p.push.apply(p,Object.keys(i.vueMounts||{}).map(function(e){return[b(o,e),i.vueMounts[e]]}).filter(function(e){var n=e[0];e[1];return n})),(i.vueGlobalOptions||d.length)&&(u=/{{2}[^{}]*}{2}/,f=/<[^>/]+\s([@:]|v-)[\w-:.[\]]+[=>\s]/,p.push.apply(p,k(".markdown-section > *").filter(function(i){return!p.some(function(e){var n=e[0];e[1];return n===i})}).filter(function(e){return e.tagName.toLowerCase()in(i.vueComponents||{})||e.querySelector(d.join(",")||null)||u.test(e.outerHTML)||f.test(e.outerHTML)}).map(function(e){var n=m({},i.vueGlobalOptions||{});return Un&&(n.data=function(){return Un}),[e,n]})));for(var g=0,s=p;g([^<]*?)

    $'))&&("color"===n[2]?o.style.background=n[1]+(n[3]||""):(e=n[1],S(o,"add","has-mask"),R(n[1])||(e=q(this.router.getBasePath(),n[1])),o.style.backgroundImage="url("+e+")",o.style.backgroundSize="cover",o.style.backgroundPosition="center center"),i=i.replace(n[0],"")),this._renderTo(".cover-main",i),K()):S(o,"remove","show")},n.prototype._updateRender=function(){var e,n,i,o;e=this,n=l(".app-name-link"),i=e.config.nameLink,o=e.route.path,n&&(f(e.config.nameLink)?n.setAttribute("href",i):"object"==typeof i&&(e=Object.keys(i).filter(function(e){return-1':"")),e.coverpage&&(f+=(o=", 100%, 85%",'
    \x3c!--cover--\x3e
    ')),e.logo&&(o=/^data:image/.test(e.logo),n=/(?:http[s]?:)?\/\//.test(e.logo),i=/^\./.test(e.logo),o||n||i||(e.logo=q(this.router.getBasePath(),e.logo))),f+=(i=(n=e).name||"","
    "+('')+'
    \x3c!--main--\x3e
    '),this._renderTo(u,f,!0)):this.rendered=!0,e.mergeNavbar&&s?p=b(".sidebar"):(c.classList.add("app-nav"),e.repo||c.classList.add("no-badge")),e.loadNavbar&&y(p,c),e.themeColor&&(v.head.appendChild(w("div","").firstElementChild),a=e.themeColor,window.CSS&&window.CSS.supports&&window.CSS.supports("(--v:red)")||(e=k("style:not(.inserted),link"),[].forEach.call(e,function(e){"STYLE"===e.nodeName?Q(e,a):"LINK"===e.nodeName&&(e=e.getAttribute("href"),/\.css$/.test(e)&&X(e).then(function(e){e=w("style",e);_.appendChild(e),Q(e,a)}))}))),this._updateRender(),S(h,"ready")},n}(function(e){function n(){e.apply(this,arguments)}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype.routes=function(){return this.config.routes||{}},n.prototype.matchVirtualRoute=function(t){var a=this.routes(),r=Object.keys(a),c=function(){return null};function u(){var e=r.shift();if(!e)return c(null);var n=A(o=(i="^",0===(o=e).indexOf(i)?o:"^"+o),"$")?o:o+"$",i=t.match(n);if(!i)return u();var o=a[e];if("string"==typeof o)return c(o);if("function"!=typeof o)return u();n=o,e=Xn(),o=e[0];return(0,e[1])(function(e){return"string"==typeof e?c(e):!1===e?c(null):u()}),n.length<=2?o(n(t,i)):n(t,i,o)}return{then:function(e){c=e,u()}}},n}(function(i){function e(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];i.apply(this,e),this.route={}}return i&&(e.__proto__=i),((e.prototype=Object.create(i&&i.prototype)).constructor=e).prototype.updateRender=function(){this.router.normalize(),this.route=this.router.parse(),h.setAttribute("data-page",this.route.file)},e.prototype.initRouter=function(){var n=this,e=this.config,e=new("history"===(e.routerMode||"hash")&&t?D:H)(e);this.router=e,this.updateRender(),U=this.route,e.onchange(function(e){n.updateRender(),n._updateRender(),U.path!==n.route.path?(n.$fetch(d,n.$resetEvents.bind(n,e.source)),U=n.route):n.$resetEvents(e.source)})},e}(function(e){function n(){e.apply(this,arguments)}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype.initLifecycle=function(){var i=this;this._hooks={},this._lifecycle={},["init","mounted","beforeEach","afterEach","doneEach","ready"].forEach(function(e){var n=i._hooks[e]=[];i._lifecycle[e]=function(e){return n.push(e)}})},n.prototype.callHook=function(e,t,a){void 0===a&&(a=d);var r=this._hooks[e],c=this.config.catchPluginErrors,u=function(n){var e=r[n];if(n>=r.length)a(t);else if("function"==typeof e){var i="Docsify plugin error";if(2===e.length)try{e(t,function(e){t=e,u(n+1)})}catch(e){if(!c)throw e;console.error(i,e),u(n+1)}else try{var o=e(t);t=void 0===o?t:o,u(n+1)}catch(e){if(!c)throw e;console.error(i,e),u(n+1)}}else u(n+1)};u(0)},n}(we))))))));function Kn(e,n,i){return Qn&&Qn.abort&&Qn.abort(),Qn=X(e,!0,i)}window.Docsify={util:Me,dom:n,get:X,slugify:Tn,version:"4.13.1"},window.DocsifyCompiler=In,window.marked=Sn,window.Prism=Pn,e(function(e){return new Jn})}(); \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/static/js/emoji.min.js b/ruoyi-admin/src/main/resources/static/static/js/emoji.min.js deleted file mode 100644 index 89151602..00000000 --- a/ruoyi-admin/src/main/resources/static/static/js/emoji.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(){var o="https://github.githubassets.com/images/icons/emoji/",i={100:"unicode/1f4af.png?v8",1234:"unicode/1f522.png?v8","+1":"unicode/1f44d.png?v8","-1":"unicode/1f44e.png?v8","1st_place_medal":"unicode/1f947.png?v8","2nd_place_medal":"unicode/1f948.png?v8","3rd_place_medal":"unicode/1f949.png?v8","8ball":"unicode/1f3b1.png?v8",a:"unicode/1f170.png?v8",ab:"unicode/1f18e.png?v8",abacus:"unicode/1f9ee.png?v8",abc:"unicode/1f524.png?v8",abcd:"unicode/1f521.png?v8",accept:"unicode/1f251.png?v8",accessibility:"accessibility.png?v8",accordion:"unicode/1fa97.png?v8",adhesive_bandage:"unicode/1fa79.png?v8",adult:"unicode/1f9d1.png?v8",aerial_tramway:"unicode/1f6a1.png?v8",afghanistan:"unicode/1f1e6-1f1eb.png?v8",airplane:"unicode/2708.png?v8",aland_islands:"unicode/1f1e6-1f1fd.png?v8",alarm_clock:"unicode/23f0.png?v8",albania:"unicode/1f1e6-1f1f1.png?v8",alembic:"unicode/2697.png?v8",algeria:"unicode/1f1e9-1f1ff.png?v8",alien:"unicode/1f47d.png?v8",ambulance:"unicode/1f691.png?v8",american_samoa:"unicode/1f1e6-1f1f8.png?v8",amphora:"unicode/1f3fa.png?v8",anatomical_heart:"unicode/1fac0.png?v8",anchor:"unicode/2693.png?v8",andorra:"unicode/1f1e6-1f1e9.png?v8",angel:"unicode/1f47c.png?v8",anger:"unicode/1f4a2.png?v8",angola:"unicode/1f1e6-1f1f4.png?v8",angry:"unicode/1f620.png?v8",anguilla:"unicode/1f1e6-1f1ee.png?v8",anguished:"unicode/1f627.png?v8",ant:"unicode/1f41c.png?v8",antarctica:"unicode/1f1e6-1f1f6.png?v8",antigua_barbuda:"unicode/1f1e6-1f1ec.png?v8",apple:"unicode/1f34e.png?v8",aquarius:"unicode/2652.png?v8",argentina:"unicode/1f1e6-1f1f7.png?v8",aries:"unicode/2648.png?v8",armenia:"unicode/1f1e6-1f1f2.png?v8",arrow_backward:"unicode/25c0.png?v8",arrow_double_down:"unicode/23ec.png?v8",arrow_double_up:"unicode/23eb.png?v8",arrow_down:"unicode/2b07.png?v8",arrow_down_small:"unicode/1f53d.png?v8",arrow_forward:"unicode/25b6.png?v8",arrow_heading_down:"unicode/2935.png?v8",arrow_heading_up:"unicode/2934.png?v8",arrow_left:"unicode/2b05.png?v8",arrow_lower_left:"unicode/2199.png?v8",arrow_lower_right:"unicode/2198.png?v8",arrow_right:"unicode/27a1.png?v8",arrow_right_hook:"unicode/21aa.png?v8",arrow_up:"unicode/2b06.png?v8",arrow_up_down:"unicode/2195.png?v8",arrow_up_small:"unicode/1f53c.png?v8",arrow_upper_left:"unicode/2196.png?v8",arrow_upper_right:"unicode/2197.png?v8",arrows_clockwise:"unicode/1f503.png?v8",arrows_counterclockwise:"unicode/1f504.png?v8",art:"unicode/1f3a8.png?v8",articulated_lorry:"unicode/1f69b.png?v8",artificial_satellite:"unicode/1f6f0.png?v8",artist:"unicode/1f9d1-1f3a8.png?v8",aruba:"unicode/1f1e6-1f1fc.png?v8",ascension_island:"unicode/1f1e6-1f1e8.png?v8",asterisk:"unicode/002a-20e3.png?v8",astonished:"unicode/1f632.png?v8",astronaut:"unicode/1f9d1-1f680.png?v8",athletic_shoe:"unicode/1f45f.png?v8",atm:"unicode/1f3e7.png?v8",atom:"atom.png?v8",atom_symbol:"unicode/269b.png?v8",australia:"unicode/1f1e6-1f1fa.png?v8",austria:"unicode/1f1e6-1f1f9.png?v8",auto_rickshaw:"unicode/1f6fa.png?v8",avocado:"unicode/1f951.png?v8",axe:"unicode/1fa93.png?v8",azerbaijan:"unicode/1f1e6-1f1ff.png?v8",b:"unicode/1f171.png?v8",baby:"unicode/1f476.png?v8",baby_bottle:"unicode/1f37c.png?v8",baby_chick:"unicode/1f424.png?v8",baby_symbol:"unicode/1f6bc.png?v8",back:"unicode/1f519.png?v8",bacon:"unicode/1f953.png?v8",badger:"unicode/1f9a1.png?v8",badminton:"unicode/1f3f8.png?v8",bagel:"unicode/1f96f.png?v8",baggage_claim:"unicode/1f6c4.png?v8",baguette_bread:"unicode/1f956.png?v8",bahamas:"unicode/1f1e7-1f1f8.png?v8",bahrain:"unicode/1f1e7-1f1ed.png?v8",balance_scale:"unicode/2696.png?v8",bald_man:"unicode/1f468-1f9b2.png?v8",bald_woman:"unicode/1f469-1f9b2.png?v8",ballet_shoes:"unicode/1fa70.png?v8",balloon:"unicode/1f388.png?v8",ballot_box:"unicode/1f5f3.png?v8",ballot_box_with_check:"unicode/2611.png?v8",bamboo:"unicode/1f38d.png?v8",banana:"unicode/1f34c.png?v8",bangbang:"unicode/203c.png?v8",bangladesh:"unicode/1f1e7-1f1e9.png?v8",banjo:"unicode/1fa95.png?v8",bank:"unicode/1f3e6.png?v8",bar_chart:"unicode/1f4ca.png?v8",barbados:"unicode/1f1e7-1f1e7.png?v8",barber:"unicode/1f488.png?v8",baseball:"unicode/26be.png?v8",basecamp:"basecamp.png?v8",basecampy:"basecampy.png?v8",basket:"unicode/1f9fa.png?v8",basketball:"unicode/1f3c0.png?v8",basketball_man:"unicode/26f9-2642.png?v8",basketball_woman:"unicode/26f9-2640.png?v8",bat:"unicode/1f987.png?v8",bath:"unicode/1f6c0.png?v8",bathtub:"unicode/1f6c1.png?v8",battery:"unicode/1f50b.png?v8",beach_umbrella:"unicode/1f3d6.png?v8",bear:"unicode/1f43b.png?v8",bearded_person:"unicode/1f9d4.png?v8",beaver:"unicode/1f9ab.png?v8",bed:"unicode/1f6cf.png?v8",bee:"unicode/1f41d.png?v8",beer:"unicode/1f37a.png?v8",beers:"unicode/1f37b.png?v8",beetle:"unicode/1fab2.png?v8",beginner:"unicode/1f530.png?v8",belarus:"unicode/1f1e7-1f1fe.png?v8",belgium:"unicode/1f1e7-1f1ea.png?v8",belize:"unicode/1f1e7-1f1ff.png?v8",bell:"unicode/1f514.png?v8",bell_pepper:"unicode/1fad1.png?v8",bellhop_bell:"unicode/1f6ce.png?v8",benin:"unicode/1f1e7-1f1ef.png?v8",bento:"unicode/1f371.png?v8",bermuda:"unicode/1f1e7-1f1f2.png?v8",beverage_box:"unicode/1f9c3.png?v8",bhutan:"unicode/1f1e7-1f1f9.png?v8",bicyclist:"unicode/1f6b4.png?v8",bike:"unicode/1f6b2.png?v8",biking_man:"unicode/1f6b4-2642.png?v8",biking_woman:"unicode/1f6b4-2640.png?v8",bikini:"unicode/1f459.png?v8",billed_cap:"unicode/1f9e2.png?v8",biohazard:"unicode/2623.png?v8",bird:"unicode/1f426.png?v8",birthday:"unicode/1f382.png?v8",bison:"unicode/1f9ac.png?v8",black_cat:"unicode/1f408-2b1b.png?v8",black_circle:"unicode/26ab.png?v8",black_flag:"unicode/1f3f4.png?v8",black_heart:"unicode/1f5a4.png?v8",black_joker:"unicode/1f0cf.png?v8",black_large_square:"unicode/2b1b.png?v8",black_medium_small_square:"unicode/25fe.png?v8",black_medium_square:"unicode/25fc.png?v8",black_nib:"unicode/2712.png?v8",black_small_square:"unicode/25aa.png?v8",black_square_button:"unicode/1f532.png?v8",blond_haired_man:"unicode/1f471-2642.png?v8",blond_haired_person:"unicode/1f471.png?v8",blond_haired_woman:"unicode/1f471-2640.png?v8",blonde_woman:"unicode/1f471-2640.png?v8",blossom:"unicode/1f33c.png?v8",blowfish:"unicode/1f421.png?v8",blue_book:"unicode/1f4d8.png?v8",blue_car:"unicode/1f699.png?v8",blue_heart:"unicode/1f499.png?v8",blue_square:"unicode/1f7e6.png?v8",blueberries:"unicode/1fad0.png?v8",blush:"unicode/1f60a.png?v8",boar:"unicode/1f417.png?v8",boat:"unicode/26f5.png?v8",bolivia:"unicode/1f1e7-1f1f4.png?v8",bomb:"unicode/1f4a3.png?v8",bone:"unicode/1f9b4.png?v8",book:"unicode/1f4d6.png?v8",bookmark:"unicode/1f516.png?v8",bookmark_tabs:"unicode/1f4d1.png?v8",books:"unicode/1f4da.png?v8",boom:"unicode/1f4a5.png?v8",boomerang:"unicode/1fa83.png?v8",boot:"unicode/1f462.png?v8",bosnia_herzegovina:"unicode/1f1e7-1f1e6.png?v8",botswana:"unicode/1f1e7-1f1fc.png?v8",bouncing_ball_man:"unicode/26f9-2642.png?v8",bouncing_ball_person:"unicode/26f9.png?v8",bouncing_ball_woman:"unicode/26f9-2640.png?v8",bouquet:"unicode/1f490.png?v8",bouvet_island:"unicode/1f1e7-1f1fb.png?v8",bow:"unicode/1f647.png?v8",bow_and_arrow:"unicode/1f3f9.png?v8",bowing_man:"unicode/1f647-2642.png?v8",bowing_woman:"unicode/1f647-2640.png?v8",bowl_with_spoon:"unicode/1f963.png?v8",bowling:"unicode/1f3b3.png?v8",bowtie:"bowtie.png?v8",boxing_glove:"unicode/1f94a.png?v8",boy:"unicode/1f466.png?v8",brain:"unicode/1f9e0.png?v8",brazil:"unicode/1f1e7-1f1f7.png?v8",bread:"unicode/1f35e.png?v8",breast_feeding:"unicode/1f931.png?v8",bricks:"unicode/1f9f1.png?v8",bride_with_veil:"unicode/1f470-2640.png?v8",bridge_at_night:"unicode/1f309.png?v8",briefcase:"unicode/1f4bc.png?v8",british_indian_ocean_territory:"unicode/1f1ee-1f1f4.png?v8",british_virgin_islands:"unicode/1f1fb-1f1ec.png?v8",broccoli:"unicode/1f966.png?v8",broken_heart:"unicode/1f494.png?v8",broom:"unicode/1f9f9.png?v8",brown_circle:"unicode/1f7e4.png?v8",brown_heart:"unicode/1f90e.png?v8",brown_square:"unicode/1f7eb.png?v8",brunei:"unicode/1f1e7-1f1f3.png?v8",bubble_tea:"unicode/1f9cb.png?v8",bucket:"unicode/1faa3.png?v8",bug:"unicode/1f41b.png?v8",building_construction:"unicode/1f3d7.png?v8",bulb:"unicode/1f4a1.png?v8",bulgaria:"unicode/1f1e7-1f1ec.png?v8",bullettrain_front:"unicode/1f685.png?v8",bullettrain_side:"unicode/1f684.png?v8",burkina_faso:"unicode/1f1e7-1f1eb.png?v8",burrito:"unicode/1f32f.png?v8",burundi:"unicode/1f1e7-1f1ee.png?v8",bus:"unicode/1f68c.png?v8",business_suit_levitating:"unicode/1f574.png?v8",busstop:"unicode/1f68f.png?v8",bust_in_silhouette:"unicode/1f464.png?v8",busts_in_silhouette:"unicode/1f465.png?v8",butter:"unicode/1f9c8.png?v8",butterfly:"unicode/1f98b.png?v8",cactus:"unicode/1f335.png?v8",cake:"unicode/1f370.png?v8",calendar:"unicode/1f4c6.png?v8",call_me_hand:"unicode/1f919.png?v8",calling:"unicode/1f4f2.png?v8",cambodia:"unicode/1f1f0-1f1ed.png?v8",camel:"unicode/1f42b.png?v8",camera:"unicode/1f4f7.png?v8",camera_flash:"unicode/1f4f8.png?v8",cameroon:"unicode/1f1e8-1f1f2.png?v8",camping:"unicode/1f3d5.png?v8",canada:"unicode/1f1e8-1f1e6.png?v8",canary_islands:"unicode/1f1ee-1f1e8.png?v8",cancer:"unicode/264b.png?v8",candle:"unicode/1f56f.png?v8",candy:"unicode/1f36c.png?v8",canned_food:"unicode/1f96b.png?v8",canoe:"unicode/1f6f6.png?v8",cape_verde:"unicode/1f1e8-1f1fb.png?v8",capital_abcd:"unicode/1f520.png?v8",capricorn:"unicode/2651.png?v8",car:"unicode/1f697.png?v8",card_file_box:"unicode/1f5c3.png?v8",card_index:"unicode/1f4c7.png?v8",card_index_dividers:"unicode/1f5c2.png?v8",caribbean_netherlands:"unicode/1f1e7-1f1f6.png?v8",carousel_horse:"unicode/1f3a0.png?v8",carpentry_saw:"unicode/1fa9a.png?v8",carrot:"unicode/1f955.png?v8",cartwheeling:"unicode/1f938.png?v8",cat:"unicode/1f431.png?v8",cat2:"unicode/1f408.png?v8",cayman_islands:"unicode/1f1f0-1f1fe.png?v8",cd:"unicode/1f4bf.png?v8",central_african_republic:"unicode/1f1e8-1f1eb.png?v8",ceuta_melilla:"unicode/1f1ea-1f1e6.png?v8",chad:"unicode/1f1f9-1f1e9.png?v8",chains:"unicode/26d3.png?v8",chair:"unicode/1fa91.png?v8",champagne:"unicode/1f37e.png?v8",chart:"unicode/1f4b9.png?v8",chart_with_downwards_trend:"unicode/1f4c9.png?v8",chart_with_upwards_trend:"unicode/1f4c8.png?v8",checkered_flag:"unicode/1f3c1.png?v8",cheese:"unicode/1f9c0.png?v8",cherries:"unicode/1f352.png?v8",cherry_blossom:"unicode/1f338.png?v8",chess_pawn:"unicode/265f.png?v8",chestnut:"unicode/1f330.png?v8",chicken:"unicode/1f414.png?v8",child:"unicode/1f9d2.png?v8",children_crossing:"unicode/1f6b8.png?v8",chile:"unicode/1f1e8-1f1f1.png?v8",chipmunk:"unicode/1f43f.png?v8",chocolate_bar:"unicode/1f36b.png?v8",chopsticks:"unicode/1f962.png?v8",christmas_island:"unicode/1f1e8-1f1fd.png?v8",christmas_tree:"unicode/1f384.png?v8",church:"unicode/26ea.png?v8",cinema:"unicode/1f3a6.png?v8",circus_tent:"unicode/1f3aa.png?v8",city_sunrise:"unicode/1f307.png?v8",city_sunset:"unicode/1f306.png?v8",cityscape:"unicode/1f3d9.png?v8",cl:"unicode/1f191.png?v8",clamp:"unicode/1f5dc.png?v8",clap:"unicode/1f44f.png?v8",clapper:"unicode/1f3ac.png?v8",classical_building:"unicode/1f3db.png?v8",climbing:"unicode/1f9d7.png?v8",climbing_man:"unicode/1f9d7-2642.png?v8",climbing_woman:"unicode/1f9d7-2640.png?v8",clinking_glasses:"unicode/1f942.png?v8",clipboard:"unicode/1f4cb.png?v8",clipperton_island:"unicode/1f1e8-1f1f5.png?v8",clock1:"unicode/1f550.png?v8",clock10:"unicode/1f559.png?v8",clock1030:"unicode/1f565.png?v8",clock11:"unicode/1f55a.png?v8",clock1130:"unicode/1f566.png?v8",clock12:"unicode/1f55b.png?v8",clock1230:"unicode/1f567.png?v8",clock130:"unicode/1f55c.png?v8",clock2:"unicode/1f551.png?v8",clock230:"unicode/1f55d.png?v8",clock3:"unicode/1f552.png?v8",clock330:"unicode/1f55e.png?v8",clock4:"unicode/1f553.png?v8",clock430:"unicode/1f55f.png?v8",clock5:"unicode/1f554.png?v8",clock530:"unicode/1f560.png?v8",clock6:"unicode/1f555.png?v8",clock630:"unicode/1f561.png?v8",clock7:"unicode/1f556.png?v8",clock730:"unicode/1f562.png?v8",clock8:"unicode/1f557.png?v8",clock830:"unicode/1f563.png?v8",clock9:"unicode/1f558.png?v8",clock930:"unicode/1f564.png?v8",closed_book:"unicode/1f4d5.png?v8",closed_lock_with_key:"unicode/1f510.png?v8",closed_umbrella:"unicode/1f302.png?v8",cloud:"unicode/2601.png?v8",cloud_with_lightning:"unicode/1f329.png?v8",cloud_with_lightning_and_rain:"unicode/26c8.png?v8",cloud_with_rain:"unicode/1f327.png?v8",cloud_with_snow:"unicode/1f328.png?v8",clown_face:"unicode/1f921.png?v8",clubs:"unicode/2663.png?v8",cn:"unicode/1f1e8-1f1f3.png?v8",coat:"unicode/1f9e5.png?v8",cockroach:"unicode/1fab3.png?v8",cocktail:"unicode/1f378.png?v8",coconut:"unicode/1f965.png?v8",cocos_islands:"unicode/1f1e8-1f1e8.png?v8",coffee:"unicode/2615.png?v8",coffin:"unicode/26b0.png?v8",coin:"unicode/1fa99.png?v8",cold_face:"unicode/1f976.png?v8",cold_sweat:"unicode/1f630.png?v8",collision:"unicode/1f4a5.png?v8",colombia:"unicode/1f1e8-1f1f4.png?v8",comet:"unicode/2604.png?v8",comoros:"unicode/1f1f0-1f1f2.png?v8",compass:"unicode/1f9ed.png?v8",computer:"unicode/1f4bb.png?v8",computer_mouse:"unicode/1f5b1.png?v8",confetti_ball:"unicode/1f38a.png?v8",confounded:"unicode/1f616.png?v8",confused:"unicode/1f615.png?v8",congo_brazzaville:"unicode/1f1e8-1f1ec.png?v8",congo_kinshasa:"unicode/1f1e8-1f1e9.png?v8",congratulations:"unicode/3297.png?v8",construction:"unicode/1f6a7.png?v8",construction_worker:"unicode/1f477.png?v8",construction_worker_man:"unicode/1f477-2642.png?v8",construction_worker_woman:"unicode/1f477-2640.png?v8",control_knobs:"unicode/1f39b.png?v8",convenience_store:"unicode/1f3ea.png?v8",cook:"unicode/1f9d1-1f373.png?v8",cook_islands:"unicode/1f1e8-1f1f0.png?v8",cookie:"unicode/1f36a.png?v8",cool:"unicode/1f192.png?v8",cop:"unicode/1f46e.png?v8",copyright:"unicode/00a9.png?v8",corn:"unicode/1f33d.png?v8",costa_rica:"unicode/1f1e8-1f1f7.png?v8",cote_divoire:"unicode/1f1e8-1f1ee.png?v8",couch_and_lamp:"unicode/1f6cb.png?v8",couple:"unicode/1f46b.png?v8",couple_with_heart:"unicode/1f491.png?v8",couple_with_heart_man_man:"unicode/1f468-2764-1f468.png?v8",couple_with_heart_woman_man:"unicode/1f469-2764-1f468.png?v8",couple_with_heart_woman_woman:"unicode/1f469-2764-1f469.png?v8",couplekiss:"unicode/1f48f.png?v8",couplekiss_man_man:"unicode/1f468-2764-1f48b-1f468.png?v8",couplekiss_man_woman:"unicode/1f469-2764-1f48b-1f468.png?v8",couplekiss_woman_woman:"unicode/1f469-2764-1f48b-1f469.png?v8",cow:"unicode/1f42e.png?v8",cow2:"unicode/1f404.png?v8",cowboy_hat_face:"unicode/1f920.png?v8",crab:"unicode/1f980.png?v8",crayon:"unicode/1f58d.png?v8",credit_card:"unicode/1f4b3.png?v8",crescent_moon:"unicode/1f319.png?v8",cricket:"unicode/1f997.png?v8",cricket_game:"unicode/1f3cf.png?v8",croatia:"unicode/1f1ed-1f1f7.png?v8",crocodile:"unicode/1f40a.png?v8",croissant:"unicode/1f950.png?v8",crossed_fingers:"unicode/1f91e.png?v8",crossed_flags:"unicode/1f38c.png?v8",crossed_swords:"unicode/2694.png?v8",crown:"unicode/1f451.png?v8",cry:"unicode/1f622.png?v8",crying_cat_face:"unicode/1f63f.png?v8",crystal_ball:"unicode/1f52e.png?v8",cuba:"unicode/1f1e8-1f1fa.png?v8",cucumber:"unicode/1f952.png?v8",cup_with_straw:"unicode/1f964.png?v8",cupcake:"unicode/1f9c1.png?v8",cupid:"unicode/1f498.png?v8",curacao:"unicode/1f1e8-1f1fc.png?v8",curling_stone:"unicode/1f94c.png?v8",curly_haired_man:"unicode/1f468-1f9b1.png?v8",curly_haired_woman:"unicode/1f469-1f9b1.png?v8",curly_loop:"unicode/27b0.png?v8",currency_exchange:"unicode/1f4b1.png?v8",curry:"unicode/1f35b.png?v8",cursing_face:"unicode/1f92c.png?v8",custard:"unicode/1f36e.png?v8",customs:"unicode/1f6c3.png?v8",cut_of_meat:"unicode/1f969.png?v8",cyclone:"unicode/1f300.png?v8",cyprus:"unicode/1f1e8-1f1fe.png?v8",czech_republic:"unicode/1f1e8-1f1ff.png?v8",dagger:"unicode/1f5e1.png?v8",dancer:"unicode/1f483.png?v8",dancers:"unicode/1f46f.png?v8",dancing_men:"unicode/1f46f-2642.png?v8",dancing_women:"unicode/1f46f-2640.png?v8",dango:"unicode/1f361.png?v8",dark_sunglasses:"unicode/1f576.png?v8",dart:"unicode/1f3af.png?v8",dash:"unicode/1f4a8.png?v8",date:"unicode/1f4c5.png?v8",de:"unicode/1f1e9-1f1ea.png?v8",deaf_man:"unicode/1f9cf-2642.png?v8",deaf_person:"unicode/1f9cf.png?v8",deaf_woman:"unicode/1f9cf-2640.png?v8",deciduous_tree:"unicode/1f333.png?v8",deer:"unicode/1f98c.png?v8",denmark:"unicode/1f1e9-1f1f0.png?v8",department_store:"unicode/1f3ec.png?v8",dependabot:"dependabot.png?v8",derelict_house:"unicode/1f3da.png?v8",desert:"unicode/1f3dc.png?v8",desert_island:"unicode/1f3dd.png?v8",desktop_computer:"unicode/1f5a5.png?v8",detective:"unicode/1f575.png?v8",diamond_shape_with_a_dot_inside:"unicode/1f4a0.png?v8",diamonds:"unicode/2666.png?v8",diego_garcia:"unicode/1f1e9-1f1ec.png?v8",disappointed:"unicode/1f61e.png?v8",disappointed_relieved:"unicode/1f625.png?v8",disguised_face:"unicode/1f978.png?v8",diving_mask:"unicode/1f93f.png?v8",diya_lamp:"unicode/1fa94.png?v8",dizzy:"unicode/1f4ab.png?v8",dizzy_face:"unicode/1f635.png?v8",djibouti:"unicode/1f1e9-1f1ef.png?v8",dna:"unicode/1f9ec.png?v8",do_not_litter:"unicode/1f6af.png?v8",dodo:"unicode/1f9a4.png?v8",dog:"unicode/1f436.png?v8",dog2:"unicode/1f415.png?v8",dollar:"unicode/1f4b5.png?v8",dolls:"unicode/1f38e.png?v8",dolphin:"unicode/1f42c.png?v8",dominica:"unicode/1f1e9-1f1f2.png?v8",dominican_republic:"unicode/1f1e9-1f1f4.png?v8",door:"unicode/1f6aa.png?v8",doughnut:"unicode/1f369.png?v8",dove:"unicode/1f54a.png?v8",dragon:"unicode/1f409.png?v8",dragon_face:"unicode/1f432.png?v8",dress:"unicode/1f457.png?v8",dromedary_camel:"unicode/1f42a.png?v8",drooling_face:"unicode/1f924.png?v8",drop_of_blood:"unicode/1fa78.png?v8",droplet:"unicode/1f4a7.png?v8",drum:"unicode/1f941.png?v8",duck:"unicode/1f986.png?v8",dumpling:"unicode/1f95f.png?v8",dvd:"unicode/1f4c0.png?v8","e-mail":"unicode/1f4e7.png?v8",eagle:"unicode/1f985.png?v8",ear:"unicode/1f442.png?v8",ear_of_rice:"unicode/1f33e.png?v8",ear_with_hearing_aid:"unicode/1f9bb.png?v8",earth_africa:"unicode/1f30d.png?v8",earth_americas:"unicode/1f30e.png?v8",earth_asia:"unicode/1f30f.png?v8",ecuador:"unicode/1f1ea-1f1e8.png?v8",egg:"unicode/1f95a.png?v8",eggplant:"unicode/1f346.png?v8",egypt:"unicode/1f1ea-1f1ec.png?v8",eight:"unicode/0038-20e3.png?v8",eight_pointed_black_star:"unicode/2734.png?v8",eight_spoked_asterisk:"unicode/2733.png?v8",eject_button:"unicode/23cf.png?v8",el_salvador:"unicode/1f1f8-1f1fb.png?v8",electric_plug:"unicode/1f50c.png?v8",electron:"electron.png?v8",elephant:"unicode/1f418.png?v8",elevator:"unicode/1f6d7.png?v8",elf:"unicode/1f9dd.png?v8",elf_man:"unicode/1f9dd-2642.png?v8",elf_woman:"unicode/1f9dd-2640.png?v8",email:"unicode/1f4e7.png?v8",end:"unicode/1f51a.png?v8",england:"unicode/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png?v8",envelope:"unicode/2709.png?v8",envelope_with_arrow:"unicode/1f4e9.png?v8",equatorial_guinea:"unicode/1f1ec-1f1f6.png?v8",eritrea:"unicode/1f1ea-1f1f7.png?v8",es:"unicode/1f1ea-1f1f8.png?v8",estonia:"unicode/1f1ea-1f1ea.png?v8",ethiopia:"unicode/1f1ea-1f1f9.png?v8",eu:"unicode/1f1ea-1f1fa.png?v8",euro:"unicode/1f4b6.png?v8",european_castle:"unicode/1f3f0.png?v8",european_post_office:"unicode/1f3e4.png?v8",european_union:"unicode/1f1ea-1f1fa.png?v8",evergreen_tree:"unicode/1f332.png?v8",exclamation:"unicode/2757.png?v8",exploding_head:"unicode/1f92f.png?v8",expressionless:"unicode/1f611.png?v8",eye:"unicode/1f441.png?v8",eye_speech_bubble:"unicode/1f441-1f5e8.png?v8",eyeglasses:"unicode/1f453.png?v8",eyes:"unicode/1f440.png?v8",face_exhaling:"unicode/1f62e-1f4a8.png?v8",face_in_clouds:"unicode/1f636-1f32b.png?v8",face_with_head_bandage:"unicode/1f915.png?v8",face_with_spiral_eyes:"unicode/1f635-1f4ab.png?v8",face_with_thermometer:"unicode/1f912.png?v8",facepalm:"unicode/1f926.png?v8",facepunch:"unicode/1f44a.png?v8",factory:"unicode/1f3ed.png?v8",factory_worker:"unicode/1f9d1-1f3ed.png?v8",fairy:"unicode/1f9da.png?v8",fairy_man:"unicode/1f9da-2642.png?v8",fairy_woman:"unicode/1f9da-2640.png?v8",falafel:"unicode/1f9c6.png?v8",falkland_islands:"unicode/1f1eb-1f1f0.png?v8",fallen_leaf:"unicode/1f342.png?v8",family:"unicode/1f46a.png?v8",family_man_boy:"unicode/1f468-1f466.png?v8",family_man_boy_boy:"unicode/1f468-1f466-1f466.png?v8",family_man_girl:"unicode/1f468-1f467.png?v8",family_man_girl_boy:"unicode/1f468-1f467-1f466.png?v8",family_man_girl_girl:"unicode/1f468-1f467-1f467.png?v8",family_man_man_boy:"unicode/1f468-1f468-1f466.png?v8",family_man_man_boy_boy:"unicode/1f468-1f468-1f466-1f466.png?v8",family_man_man_girl:"unicode/1f468-1f468-1f467.png?v8",family_man_man_girl_boy:"unicode/1f468-1f468-1f467-1f466.png?v8",family_man_man_girl_girl:"unicode/1f468-1f468-1f467-1f467.png?v8",family_man_woman_boy:"unicode/1f468-1f469-1f466.png?v8",family_man_woman_boy_boy:"unicode/1f468-1f469-1f466-1f466.png?v8",family_man_woman_girl:"unicode/1f468-1f469-1f467.png?v8",family_man_woman_girl_boy:"unicode/1f468-1f469-1f467-1f466.png?v8",family_man_woman_girl_girl:"unicode/1f468-1f469-1f467-1f467.png?v8",family_woman_boy:"unicode/1f469-1f466.png?v8",family_woman_boy_boy:"unicode/1f469-1f466-1f466.png?v8",family_woman_girl:"unicode/1f469-1f467.png?v8",family_woman_girl_boy:"unicode/1f469-1f467-1f466.png?v8",family_woman_girl_girl:"unicode/1f469-1f467-1f467.png?v8",family_woman_woman_boy:"unicode/1f469-1f469-1f466.png?v8",family_woman_woman_boy_boy:"unicode/1f469-1f469-1f466-1f466.png?v8",family_woman_woman_girl:"unicode/1f469-1f469-1f467.png?v8",family_woman_woman_girl_boy:"unicode/1f469-1f469-1f467-1f466.png?v8",family_woman_woman_girl_girl:"unicode/1f469-1f469-1f467-1f467.png?v8",farmer:"unicode/1f9d1-1f33e.png?v8",faroe_islands:"unicode/1f1eb-1f1f4.png?v8",fast_forward:"unicode/23e9.png?v8",fax:"unicode/1f4e0.png?v8",fearful:"unicode/1f628.png?v8",feather:"unicode/1fab6.png?v8",feelsgood:"feelsgood.png?v8",feet:"unicode/1f43e.png?v8",female_detective:"unicode/1f575-2640.png?v8",female_sign:"unicode/2640.png?v8",ferris_wheel:"unicode/1f3a1.png?v8",ferry:"unicode/26f4.png?v8",field_hockey:"unicode/1f3d1.png?v8",fiji:"unicode/1f1eb-1f1ef.png?v8",file_cabinet:"unicode/1f5c4.png?v8",file_folder:"unicode/1f4c1.png?v8",film_projector:"unicode/1f4fd.png?v8",film_strip:"unicode/1f39e.png?v8",finland:"unicode/1f1eb-1f1ee.png?v8",finnadie:"finnadie.png?v8",fire:"unicode/1f525.png?v8",fire_engine:"unicode/1f692.png?v8",fire_extinguisher:"unicode/1f9ef.png?v8",firecracker:"unicode/1f9e8.png?v8",firefighter:"unicode/1f9d1-1f692.png?v8",fireworks:"unicode/1f386.png?v8",first_quarter_moon:"unicode/1f313.png?v8",first_quarter_moon_with_face:"unicode/1f31b.png?v8",fish:"unicode/1f41f.png?v8",fish_cake:"unicode/1f365.png?v8",fishing_pole_and_fish:"unicode/1f3a3.png?v8",fishsticks:"fishsticks.png?v8",fist:"unicode/270a.png?v8",fist_left:"unicode/1f91b.png?v8",fist_oncoming:"unicode/1f44a.png?v8",fist_raised:"unicode/270a.png?v8",fist_right:"unicode/1f91c.png?v8",five:"unicode/0035-20e3.png?v8",flags:"unicode/1f38f.png?v8",flamingo:"unicode/1f9a9.png?v8",flashlight:"unicode/1f526.png?v8",flat_shoe:"unicode/1f97f.png?v8",flatbread:"unicode/1fad3.png?v8",fleur_de_lis:"unicode/269c.png?v8",flight_arrival:"unicode/1f6ec.png?v8",flight_departure:"unicode/1f6eb.png?v8",flipper:"unicode/1f42c.png?v8",floppy_disk:"unicode/1f4be.png?v8",flower_playing_cards:"unicode/1f3b4.png?v8",flushed:"unicode/1f633.png?v8",fly:"unicode/1fab0.png?v8",flying_disc:"unicode/1f94f.png?v8",flying_saucer:"unicode/1f6f8.png?v8",fog:"unicode/1f32b.png?v8",foggy:"unicode/1f301.png?v8",fondue:"unicode/1fad5.png?v8",foot:"unicode/1f9b6.png?v8",football:"unicode/1f3c8.png?v8",footprints:"unicode/1f463.png?v8",fork_and_knife:"unicode/1f374.png?v8",fortune_cookie:"unicode/1f960.png?v8",fountain:"unicode/26f2.png?v8",fountain_pen:"unicode/1f58b.png?v8",four:"unicode/0034-20e3.png?v8",four_leaf_clover:"unicode/1f340.png?v8",fox_face:"unicode/1f98a.png?v8",fr:"unicode/1f1eb-1f1f7.png?v8",framed_picture:"unicode/1f5bc.png?v8",free:"unicode/1f193.png?v8",french_guiana:"unicode/1f1ec-1f1eb.png?v8",french_polynesia:"unicode/1f1f5-1f1eb.png?v8",french_southern_territories:"unicode/1f1f9-1f1eb.png?v8",fried_egg:"unicode/1f373.png?v8",fried_shrimp:"unicode/1f364.png?v8",fries:"unicode/1f35f.png?v8",frog:"unicode/1f438.png?v8",frowning:"unicode/1f626.png?v8",frowning_face:"unicode/2639.png?v8",frowning_man:"unicode/1f64d-2642.png?v8",frowning_person:"unicode/1f64d.png?v8",frowning_woman:"unicode/1f64d-2640.png?v8",fu:"unicode/1f595.png?v8",fuelpump:"unicode/26fd.png?v8",full_moon:"unicode/1f315.png?v8",full_moon_with_face:"unicode/1f31d.png?v8",funeral_urn:"unicode/26b1.png?v8",gabon:"unicode/1f1ec-1f1e6.png?v8",gambia:"unicode/1f1ec-1f1f2.png?v8",game_die:"unicode/1f3b2.png?v8",garlic:"unicode/1f9c4.png?v8",gb:"unicode/1f1ec-1f1e7.png?v8",gear:"unicode/2699.png?v8",gem:"unicode/1f48e.png?v8",gemini:"unicode/264a.png?v8",genie:"unicode/1f9de.png?v8",genie_man:"unicode/1f9de-2642.png?v8",genie_woman:"unicode/1f9de-2640.png?v8",georgia:"unicode/1f1ec-1f1ea.png?v8",ghana:"unicode/1f1ec-1f1ed.png?v8",ghost:"unicode/1f47b.png?v8",gibraltar:"unicode/1f1ec-1f1ee.png?v8",gift:"unicode/1f381.png?v8",gift_heart:"unicode/1f49d.png?v8",giraffe:"unicode/1f992.png?v8",girl:"unicode/1f467.png?v8",globe_with_meridians:"unicode/1f310.png?v8",gloves:"unicode/1f9e4.png?v8",goal_net:"unicode/1f945.png?v8",goat:"unicode/1f410.png?v8",goberserk:"goberserk.png?v8",godmode:"godmode.png?v8",goggles:"unicode/1f97d.png?v8",golf:"unicode/26f3.png?v8",golfing:"unicode/1f3cc.png?v8",golfing_man:"unicode/1f3cc-2642.png?v8",golfing_woman:"unicode/1f3cc-2640.png?v8",gorilla:"unicode/1f98d.png?v8",grapes:"unicode/1f347.png?v8",greece:"unicode/1f1ec-1f1f7.png?v8",green_apple:"unicode/1f34f.png?v8",green_book:"unicode/1f4d7.png?v8",green_circle:"unicode/1f7e2.png?v8",green_heart:"unicode/1f49a.png?v8",green_salad:"unicode/1f957.png?v8",green_square:"unicode/1f7e9.png?v8",greenland:"unicode/1f1ec-1f1f1.png?v8",grenada:"unicode/1f1ec-1f1e9.png?v8",grey_exclamation:"unicode/2755.png?v8",grey_question:"unicode/2754.png?v8",grimacing:"unicode/1f62c.png?v8",grin:"unicode/1f601.png?v8",grinning:"unicode/1f600.png?v8",guadeloupe:"unicode/1f1ec-1f1f5.png?v8",guam:"unicode/1f1ec-1f1fa.png?v8",guard:"unicode/1f482.png?v8",guardsman:"unicode/1f482-2642.png?v8",guardswoman:"unicode/1f482-2640.png?v8",guatemala:"unicode/1f1ec-1f1f9.png?v8",guernsey:"unicode/1f1ec-1f1ec.png?v8",guide_dog:"unicode/1f9ae.png?v8",guinea:"unicode/1f1ec-1f1f3.png?v8",guinea_bissau:"unicode/1f1ec-1f1fc.png?v8",guitar:"unicode/1f3b8.png?v8",gun:"unicode/1f52b.png?v8",guyana:"unicode/1f1ec-1f1fe.png?v8",haircut:"unicode/1f487.png?v8",haircut_man:"unicode/1f487-2642.png?v8",haircut_woman:"unicode/1f487-2640.png?v8",haiti:"unicode/1f1ed-1f1f9.png?v8",hamburger:"unicode/1f354.png?v8",hammer:"unicode/1f528.png?v8",hammer_and_pick:"unicode/2692.png?v8",hammer_and_wrench:"unicode/1f6e0.png?v8",hamster:"unicode/1f439.png?v8",hand:"unicode/270b.png?v8",hand_over_mouth:"unicode/1f92d.png?v8",handbag:"unicode/1f45c.png?v8",handball_person:"unicode/1f93e.png?v8",handshake:"unicode/1f91d.png?v8",hankey:"unicode/1f4a9.png?v8",hash:"unicode/0023-20e3.png?v8",hatched_chick:"unicode/1f425.png?v8",hatching_chick:"unicode/1f423.png?v8",headphones:"unicode/1f3a7.png?v8",headstone:"unicode/1faa6.png?v8",health_worker:"unicode/1f9d1-2695.png?v8",hear_no_evil:"unicode/1f649.png?v8",heard_mcdonald_islands:"unicode/1f1ed-1f1f2.png?v8",heart:"unicode/2764.png?v8",heart_decoration:"unicode/1f49f.png?v8",heart_eyes:"unicode/1f60d.png?v8",heart_eyes_cat:"unicode/1f63b.png?v8",heart_on_fire:"unicode/2764-1f525.png?v8",heartbeat:"unicode/1f493.png?v8",heartpulse:"unicode/1f497.png?v8",hearts:"unicode/2665.png?v8",heavy_check_mark:"unicode/2714.png?v8",heavy_division_sign:"unicode/2797.png?v8",heavy_dollar_sign:"unicode/1f4b2.png?v8",heavy_exclamation_mark:"unicode/2757.png?v8",heavy_heart_exclamation:"unicode/2763.png?v8",heavy_minus_sign:"unicode/2796.png?v8",heavy_multiplication_x:"unicode/2716.png?v8",heavy_plus_sign:"unicode/2795.png?v8",hedgehog:"unicode/1f994.png?v8",helicopter:"unicode/1f681.png?v8",herb:"unicode/1f33f.png?v8",hibiscus:"unicode/1f33a.png?v8",high_brightness:"unicode/1f506.png?v8",high_heel:"unicode/1f460.png?v8",hiking_boot:"unicode/1f97e.png?v8",hindu_temple:"unicode/1f6d5.png?v8",hippopotamus:"unicode/1f99b.png?v8",hocho:"unicode/1f52a.png?v8",hole:"unicode/1f573.png?v8",honduras:"unicode/1f1ed-1f1f3.png?v8",honey_pot:"unicode/1f36f.png?v8",honeybee:"unicode/1f41d.png?v8",hong_kong:"unicode/1f1ed-1f1f0.png?v8",hook:"unicode/1fa9d.png?v8",horse:"unicode/1f434.png?v8",horse_racing:"unicode/1f3c7.png?v8",hospital:"unicode/1f3e5.png?v8",hot_face:"unicode/1f975.png?v8",hot_pepper:"unicode/1f336.png?v8",hotdog:"unicode/1f32d.png?v8",hotel:"unicode/1f3e8.png?v8",hotsprings:"unicode/2668.png?v8",hourglass:"unicode/231b.png?v8",hourglass_flowing_sand:"unicode/23f3.png?v8",house:"unicode/1f3e0.png?v8",house_with_garden:"unicode/1f3e1.png?v8",houses:"unicode/1f3d8.png?v8",hugs:"unicode/1f917.png?v8",hungary:"unicode/1f1ed-1f1fa.png?v8",hurtrealbad:"hurtrealbad.png?v8",hushed:"unicode/1f62f.png?v8",hut:"unicode/1f6d6.png?v8",ice_cream:"unicode/1f368.png?v8",ice_cube:"unicode/1f9ca.png?v8",ice_hockey:"unicode/1f3d2.png?v8",ice_skate:"unicode/26f8.png?v8",icecream:"unicode/1f366.png?v8",iceland:"unicode/1f1ee-1f1f8.png?v8",id:"unicode/1f194.png?v8",ideograph_advantage:"unicode/1f250.png?v8",imp:"unicode/1f47f.png?v8",inbox_tray:"unicode/1f4e5.png?v8",incoming_envelope:"unicode/1f4e8.png?v8",india:"unicode/1f1ee-1f1f3.png?v8",indonesia:"unicode/1f1ee-1f1e9.png?v8",infinity:"unicode/267e.png?v8",information_desk_person:"unicode/1f481.png?v8",information_source:"unicode/2139.png?v8",innocent:"unicode/1f607.png?v8",interrobang:"unicode/2049.png?v8",iphone:"unicode/1f4f1.png?v8",iran:"unicode/1f1ee-1f1f7.png?v8",iraq:"unicode/1f1ee-1f1f6.png?v8",ireland:"unicode/1f1ee-1f1ea.png?v8",isle_of_man:"unicode/1f1ee-1f1f2.png?v8",israel:"unicode/1f1ee-1f1f1.png?v8",it:"unicode/1f1ee-1f1f9.png?v8",izakaya_lantern:"unicode/1f3ee.png?v8",jack_o_lantern:"unicode/1f383.png?v8",jamaica:"unicode/1f1ef-1f1f2.png?v8",japan:"unicode/1f5fe.png?v8",japanese_castle:"unicode/1f3ef.png?v8",japanese_goblin:"unicode/1f47a.png?v8",japanese_ogre:"unicode/1f479.png?v8",jeans:"unicode/1f456.png?v8",jersey:"unicode/1f1ef-1f1ea.png?v8",jigsaw:"unicode/1f9e9.png?v8",jordan:"unicode/1f1ef-1f1f4.png?v8",joy:"unicode/1f602.png?v8",joy_cat:"unicode/1f639.png?v8",joystick:"unicode/1f579.png?v8",jp:"unicode/1f1ef-1f1f5.png?v8",judge:"unicode/1f9d1-2696.png?v8",juggling_person:"unicode/1f939.png?v8",kaaba:"unicode/1f54b.png?v8",kangaroo:"unicode/1f998.png?v8",kazakhstan:"unicode/1f1f0-1f1ff.png?v8",kenya:"unicode/1f1f0-1f1ea.png?v8",key:"unicode/1f511.png?v8",keyboard:"unicode/2328.png?v8",keycap_ten:"unicode/1f51f.png?v8",kick_scooter:"unicode/1f6f4.png?v8",kimono:"unicode/1f458.png?v8",kiribati:"unicode/1f1f0-1f1ee.png?v8",kiss:"unicode/1f48b.png?v8",kissing:"unicode/1f617.png?v8",kissing_cat:"unicode/1f63d.png?v8",kissing_closed_eyes:"unicode/1f61a.png?v8",kissing_heart:"unicode/1f618.png?v8",kissing_smiling_eyes:"unicode/1f619.png?v8",kite:"unicode/1fa81.png?v8",kiwi_fruit:"unicode/1f95d.png?v8",kneeling_man:"unicode/1f9ce-2642.png?v8",kneeling_person:"unicode/1f9ce.png?v8",kneeling_woman:"unicode/1f9ce-2640.png?v8",knife:"unicode/1f52a.png?v8",knot:"unicode/1faa2.png?v8",koala:"unicode/1f428.png?v8",koko:"unicode/1f201.png?v8",kosovo:"unicode/1f1fd-1f1f0.png?v8",kr:"unicode/1f1f0-1f1f7.png?v8",kuwait:"unicode/1f1f0-1f1fc.png?v8",kyrgyzstan:"unicode/1f1f0-1f1ec.png?v8",lab_coat:"unicode/1f97c.png?v8",label:"unicode/1f3f7.png?v8",lacrosse:"unicode/1f94d.png?v8",ladder:"unicode/1fa9c.png?v8",lady_beetle:"unicode/1f41e.png?v8",lantern:"unicode/1f3ee.png?v8",laos:"unicode/1f1f1-1f1e6.png?v8",large_blue_circle:"unicode/1f535.png?v8",large_blue_diamond:"unicode/1f537.png?v8",large_orange_diamond:"unicode/1f536.png?v8",last_quarter_moon:"unicode/1f317.png?v8",last_quarter_moon_with_face:"unicode/1f31c.png?v8",latin_cross:"unicode/271d.png?v8",latvia:"unicode/1f1f1-1f1fb.png?v8",laughing:"unicode/1f606.png?v8",leafy_green:"unicode/1f96c.png?v8",leaves:"unicode/1f343.png?v8",lebanon:"unicode/1f1f1-1f1e7.png?v8",ledger:"unicode/1f4d2.png?v8",left_luggage:"unicode/1f6c5.png?v8",left_right_arrow:"unicode/2194.png?v8",left_speech_bubble:"unicode/1f5e8.png?v8",leftwards_arrow_with_hook:"unicode/21a9.png?v8",leg:"unicode/1f9b5.png?v8",lemon:"unicode/1f34b.png?v8",leo:"unicode/264c.png?v8",leopard:"unicode/1f406.png?v8",lesotho:"unicode/1f1f1-1f1f8.png?v8",level_slider:"unicode/1f39a.png?v8",liberia:"unicode/1f1f1-1f1f7.png?v8",libra:"unicode/264e.png?v8",libya:"unicode/1f1f1-1f1fe.png?v8",liechtenstein:"unicode/1f1f1-1f1ee.png?v8",light_rail:"unicode/1f688.png?v8",link:"unicode/1f517.png?v8",lion:"unicode/1f981.png?v8",lips:"unicode/1f444.png?v8",lipstick:"unicode/1f484.png?v8",lithuania:"unicode/1f1f1-1f1f9.png?v8",lizard:"unicode/1f98e.png?v8",llama:"unicode/1f999.png?v8",lobster:"unicode/1f99e.png?v8",lock:"unicode/1f512.png?v8",lock_with_ink_pen:"unicode/1f50f.png?v8",lollipop:"unicode/1f36d.png?v8",long_drum:"unicode/1fa98.png?v8",loop:"unicode/27bf.png?v8",lotion_bottle:"unicode/1f9f4.png?v8",lotus_position:"unicode/1f9d8.png?v8",lotus_position_man:"unicode/1f9d8-2642.png?v8",lotus_position_woman:"unicode/1f9d8-2640.png?v8",loud_sound:"unicode/1f50a.png?v8",loudspeaker:"unicode/1f4e2.png?v8",love_hotel:"unicode/1f3e9.png?v8",love_letter:"unicode/1f48c.png?v8",love_you_gesture:"unicode/1f91f.png?v8",low_brightness:"unicode/1f505.png?v8",luggage:"unicode/1f9f3.png?v8",lungs:"unicode/1fac1.png?v8",luxembourg:"unicode/1f1f1-1f1fa.png?v8",lying_face:"unicode/1f925.png?v8",m:"unicode/24c2.png?v8",macau:"unicode/1f1f2-1f1f4.png?v8",macedonia:"unicode/1f1f2-1f1f0.png?v8",madagascar:"unicode/1f1f2-1f1ec.png?v8",mag:"unicode/1f50d.png?v8",mag_right:"unicode/1f50e.png?v8",mage:"unicode/1f9d9.png?v8",mage_man:"unicode/1f9d9-2642.png?v8",mage_woman:"unicode/1f9d9-2640.png?v8",magic_wand:"unicode/1fa84.png?v8",magnet:"unicode/1f9f2.png?v8",mahjong:"unicode/1f004.png?v8",mailbox:"unicode/1f4eb.png?v8",mailbox_closed:"unicode/1f4ea.png?v8",mailbox_with_mail:"unicode/1f4ec.png?v8",mailbox_with_no_mail:"unicode/1f4ed.png?v8",malawi:"unicode/1f1f2-1f1fc.png?v8",malaysia:"unicode/1f1f2-1f1fe.png?v8",maldives:"unicode/1f1f2-1f1fb.png?v8",male_detective:"unicode/1f575-2642.png?v8",male_sign:"unicode/2642.png?v8",mali:"unicode/1f1f2-1f1f1.png?v8",malta:"unicode/1f1f2-1f1f9.png?v8",mammoth:"unicode/1f9a3.png?v8",man:"unicode/1f468.png?v8",man_artist:"unicode/1f468-1f3a8.png?v8",man_astronaut:"unicode/1f468-1f680.png?v8",man_beard:"unicode/1f9d4-2642.png?v8",man_cartwheeling:"unicode/1f938-2642.png?v8",man_cook:"unicode/1f468-1f373.png?v8",man_dancing:"unicode/1f57a.png?v8",man_facepalming:"unicode/1f926-2642.png?v8",man_factory_worker:"unicode/1f468-1f3ed.png?v8",man_farmer:"unicode/1f468-1f33e.png?v8",man_feeding_baby:"unicode/1f468-1f37c.png?v8",man_firefighter:"unicode/1f468-1f692.png?v8",man_health_worker:"unicode/1f468-2695.png?v8",man_in_manual_wheelchair:"unicode/1f468-1f9bd.png?v8",man_in_motorized_wheelchair:"unicode/1f468-1f9bc.png?v8",man_in_tuxedo:"unicode/1f935-2642.png?v8",man_judge:"unicode/1f468-2696.png?v8",man_juggling:"unicode/1f939-2642.png?v8",man_mechanic:"unicode/1f468-1f527.png?v8",man_office_worker:"unicode/1f468-1f4bc.png?v8",man_pilot:"unicode/1f468-2708.png?v8",man_playing_handball:"unicode/1f93e-2642.png?v8",man_playing_water_polo:"unicode/1f93d-2642.png?v8",man_scientist:"unicode/1f468-1f52c.png?v8",man_shrugging:"unicode/1f937-2642.png?v8",man_singer:"unicode/1f468-1f3a4.png?v8",man_student:"unicode/1f468-1f393.png?v8",man_teacher:"unicode/1f468-1f3eb.png?v8",man_technologist:"unicode/1f468-1f4bb.png?v8",man_with_gua_pi_mao:"unicode/1f472.png?v8",man_with_probing_cane:"unicode/1f468-1f9af.png?v8",man_with_turban:"unicode/1f473-2642.png?v8",man_with_veil:"unicode/1f470-2642.png?v8",mandarin:"unicode/1f34a.png?v8",mango:"unicode/1f96d.png?v8",mans_shoe:"unicode/1f45e.png?v8",mantelpiece_clock:"unicode/1f570.png?v8",manual_wheelchair:"unicode/1f9bd.png?v8",maple_leaf:"unicode/1f341.png?v8",marshall_islands:"unicode/1f1f2-1f1ed.png?v8",martial_arts_uniform:"unicode/1f94b.png?v8",martinique:"unicode/1f1f2-1f1f6.png?v8",mask:"unicode/1f637.png?v8",massage:"unicode/1f486.png?v8",massage_man:"unicode/1f486-2642.png?v8",massage_woman:"unicode/1f486-2640.png?v8",mate:"unicode/1f9c9.png?v8",mauritania:"unicode/1f1f2-1f1f7.png?v8",mauritius:"unicode/1f1f2-1f1fa.png?v8",mayotte:"unicode/1f1fe-1f1f9.png?v8",meat_on_bone:"unicode/1f356.png?v8",mechanic:"unicode/1f9d1-1f527.png?v8",mechanical_arm:"unicode/1f9be.png?v8",mechanical_leg:"unicode/1f9bf.png?v8",medal_military:"unicode/1f396.png?v8",medal_sports:"unicode/1f3c5.png?v8",medical_symbol:"unicode/2695.png?v8",mega:"unicode/1f4e3.png?v8",melon:"unicode/1f348.png?v8",memo:"unicode/1f4dd.png?v8",men_wrestling:"unicode/1f93c-2642.png?v8",mending_heart:"unicode/2764-1fa79.png?v8",menorah:"unicode/1f54e.png?v8",mens:"unicode/1f6b9.png?v8",mermaid:"unicode/1f9dc-2640.png?v8",merman:"unicode/1f9dc-2642.png?v8",merperson:"unicode/1f9dc.png?v8",metal:"unicode/1f918.png?v8",metro:"unicode/1f687.png?v8",mexico:"unicode/1f1f2-1f1fd.png?v8",microbe:"unicode/1f9a0.png?v8",micronesia:"unicode/1f1eb-1f1f2.png?v8",microphone:"unicode/1f3a4.png?v8",microscope:"unicode/1f52c.png?v8",middle_finger:"unicode/1f595.png?v8",military_helmet:"unicode/1fa96.png?v8",milk_glass:"unicode/1f95b.png?v8",milky_way:"unicode/1f30c.png?v8",minibus:"unicode/1f690.png?v8",minidisc:"unicode/1f4bd.png?v8",mirror:"unicode/1fa9e.png?v8",mobile_phone_off:"unicode/1f4f4.png?v8",moldova:"unicode/1f1f2-1f1e9.png?v8",monaco:"unicode/1f1f2-1f1e8.png?v8",money_mouth_face:"unicode/1f911.png?v8",money_with_wings:"unicode/1f4b8.png?v8",moneybag:"unicode/1f4b0.png?v8",mongolia:"unicode/1f1f2-1f1f3.png?v8",monkey:"unicode/1f412.png?v8",monkey_face:"unicode/1f435.png?v8",monocle_face:"unicode/1f9d0.png?v8",monorail:"unicode/1f69d.png?v8",montenegro:"unicode/1f1f2-1f1ea.png?v8",montserrat:"unicode/1f1f2-1f1f8.png?v8",moon:"unicode/1f314.png?v8",moon_cake:"unicode/1f96e.png?v8",morocco:"unicode/1f1f2-1f1e6.png?v8",mortar_board:"unicode/1f393.png?v8",mosque:"unicode/1f54c.png?v8",mosquito:"unicode/1f99f.png?v8",motor_boat:"unicode/1f6e5.png?v8",motor_scooter:"unicode/1f6f5.png?v8",motorcycle:"unicode/1f3cd.png?v8",motorized_wheelchair:"unicode/1f9bc.png?v8",motorway:"unicode/1f6e3.png?v8",mount_fuji:"unicode/1f5fb.png?v8",mountain:"unicode/26f0.png?v8",mountain_bicyclist:"unicode/1f6b5.png?v8",mountain_biking_man:"unicode/1f6b5-2642.png?v8",mountain_biking_woman:"unicode/1f6b5-2640.png?v8",mountain_cableway:"unicode/1f6a0.png?v8",mountain_railway:"unicode/1f69e.png?v8",mountain_snow:"unicode/1f3d4.png?v8",mouse:"unicode/1f42d.png?v8",mouse2:"unicode/1f401.png?v8",mouse_trap:"unicode/1faa4.png?v8",movie_camera:"unicode/1f3a5.png?v8",moyai:"unicode/1f5ff.png?v8",mozambique:"unicode/1f1f2-1f1ff.png?v8",mrs_claus:"unicode/1f936.png?v8",muscle:"unicode/1f4aa.png?v8",mushroom:"unicode/1f344.png?v8",musical_keyboard:"unicode/1f3b9.png?v8",musical_note:"unicode/1f3b5.png?v8",musical_score:"unicode/1f3bc.png?v8",mute:"unicode/1f507.png?v8",mx_claus:"unicode/1f9d1-1f384.png?v8",myanmar:"unicode/1f1f2-1f1f2.png?v8",nail_care:"unicode/1f485.png?v8",name_badge:"unicode/1f4db.png?v8",namibia:"unicode/1f1f3-1f1e6.png?v8",national_park:"unicode/1f3de.png?v8",nauru:"unicode/1f1f3-1f1f7.png?v8",nauseated_face:"unicode/1f922.png?v8",nazar_amulet:"unicode/1f9ff.png?v8",neckbeard:"neckbeard.png?v8",necktie:"unicode/1f454.png?v8",negative_squared_cross_mark:"unicode/274e.png?v8",nepal:"unicode/1f1f3-1f1f5.png?v8",nerd_face:"unicode/1f913.png?v8",nesting_dolls:"unicode/1fa86.png?v8",netherlands:"unicode/1f1f3-1f1f1.png?v8",neutral_face:"unicode/1f610.png?v8",new:"unicode/1f195.png?v8",new_caledonia:"unicode/1f1f3-1f1e8.png?v8",new_moon:"unicode/1f311.png?v8",new_moon_with_face:"unicode/1f31a.png?v8",new_zealand:"unicode/1f1f3-1f1ff.png?v8",newspaper:"unicode/1f4f0.png?v8",newspaper_roll:"unicode/1f5de.png?v8",next_track_button:"unicode/23ed.png?v8",ng:"unicode/1f196.png?v8",ng_man:"unicode/1f645-2642.png?v8",ng_woman:"unicode/1f645-2640.png?v8",nicaragua:"unicode/1f1f3-1f1ee.png?v8",niger:"unicode/1f1f3-1f1ea.png?v8",nigeria:"unicode/1f1f3-1f1ec.png?v8",night_with_stars:"unicode/1f303.png?v8",nine:"unicode/0039-20e3.png?v8",ninja:"unicode/1f977.png?v8",niue:"unicode/1f1f3-1f1fa.png?v8",no_bell:"unicode/1f515.png?v8",no_bicycles:"unicode/1f6b3.png?v8",no_entry:"unicode/26d4.png?v8",no_entry_sign:"unicode/1f6ab.png?v8",no_good:"unicode/1f645.png?v8",no_good_man:"unicode/1f645-2642.png?v8",no_good_woman:"unicode/1f645-2640.png?v8",no_mobile_phones:"unicode/1f4f5.png?v8",no_mouth:"unicode/1f636.png?v8",no_pedestrians:"unicode/1f6b7.png?v8",no_smoking:"unicode/1f6ad.png?v8","non-potable_water":"unicode/1f6b1.png?v8",norfolk_island:"unicode/1f1f3-1f1eb.png?v8",north_korea:"unicode/1f1f0-1f1f5.png?v8",northern_mariana_islands:"unicode/1f1f2-1f1f5.png?v8",norway:"unicode/1f1f3-1f1f4.png?v8",nose:"unicode/1f443.png?v8",notebook:"unicode/1f4d3.png?v8",notebook_with_decorative_cover:"unicode/1f4d4.png?v8",notes:"unicode/1f3b6.png?v8",nut_and_bolt:"unicode/1f529.png?v8",o:"unicode/2b55.png?v8",o2:"unicode/1f17e.png?v8",ocean:"unicode/1f30a.png?v8",octocat:"octocat.png?v8",octopus:"unicode/1f419.png?v8",oden:"unicode/1f362.png?v8",office:"unicode/1f3e2.png?v8",office_worker:"unicode/1f9d1-1f4bc.png?v8",oil_drum:"unicode/1f6e2.png?v8",ok:"unicode/1f197.png?v8",ok_hand:"unicode/1f44c.png?v8",ok_man:"unicode/1f646-2642.png?v8",ok_person:"unicode/1f646.png?v8",ok_woman:"unicode/1f646-2640.png?v8",old_key:"unicode/1f5dd.png?v8",older_adult:"unicode/1f9d3.png?v8",older_man:"unicode/1f474.png?v8",older_woman:"unicode/1f475.png?v8",olive:"unicode/1fad2.png?v8",om:"unicode/1f549.png?v8",oman:"unicode/1f1f4-1f1f2.png?v8",on:"unicode/1f51b.png?v8",oncoming_automobile:"unicode/1f698.png?v8",oncoming_bus:"unicode/1f68d.png?v8",oncoming_police_car:"unicode/1f694.png?v8",oncoming_taxi:"unicode/1f696.png?v8",one:"unicode/0031-20e3.png?v8",one_piece_swimsuit:"unicode/1fa71.png?v8",onion:"unicode/1f9c5.png?v8",open_book:"unicode/1f4d6.png?v8",open_file_folder:"unicode/1f4c2.png?v8",open_hands:"unicode/1f450.png?v8",open_mouth:"unicode/1f62e.png?v8",open_umbrella:"unicode/2602.png?v8",ophiuchus:"unicode/26ce.png?v8",orange:"unicode/1f34a.png?v8",orange_book:"unicode/1f4d9.png?v8",orange_circle:"unicode/1f7e0.png?v8",orange_heart:"unicode/1f9e1.png?v8",orange_square:"unicode/1f7e7.png?v8",orangutan:"unicode/1f9a7.png?v8",orthodox_cross:"unicode/2626.png?v8",otter:"unicode/1f9a6.png?v8",outbox_tray:"unicode/1f4e4.png?v8",owl:"unicode/1f989.png?v8",ox:"unicode/1f402.png?v8",oyster:"unicode/1f9aa.png?v8",package:"unicode/1f4e6.png?v8",page_facing_up:"unicode/1f4c4.png?v8",page_with_curl:"unicode/1f4c3.png?v8",pager:"unicode/1f4df.png?v8",paintbrush:"unicode/1f58c.png?v8",pakistan:"unicode/1f1f5-1f1f0.png?v8",palau:"unicode/1f1f5-1f1fc.png?v8",palestinian_territories:"unicode/1f1f5-1f1f8.png?v8",palm_tree:"unicode/1f334.png?v8",palms_up_together:"unicode/1f932.png?v8",panama:"unicode/1f1f5-1f1e6.png?v8",pancakes:"unicode/1f95e.png?v8",panda_face:"unicode/1f43c.png?v8",paperclip:"unicode/1f4ce.png?v8",paperclips:"unicode/1f587.png?v8",papua_new_guinea:"unicode/1f1f5-1f1ec.png?v8",parachute:"unicode/1fa82.png?v8",paraguay:"unicode/1f1f5-1f1fe.png?v8",parasol_on_ground:"unicode/26f1.png?v8",parking:"unicode/1f17f.png?v8",parrot:"unicode/1f99c.png?v8",part_alternation_mark:"unicode/303d.png?v8",partly_sunny:"unicode/26c5.png?v8",partying_face:"unicode/1f973.png?v8",passenger_ship:"unicode/1f6f3.png?v8",passport_control:"unicode/1f6c2.png?v8",pause_button:"unicode/23f8.png?v8",paw_prints:"unicode/1f43e.png?v8",peace_symbol:"unicode/262e.png?v8",peach:"unicode/1f351.png?v8",peacock:"unicode/1f99a.png?v8",peanuts:"unicode/1f95c.png?v8",pear:"unicode/1f350.png?v8",pen:"unicode/1f58a.png?v8",pencil:"unicode/1f4dd.png?v8",pencil2:"unicode/270f.png?v8",penguin:"unicode/1f427.png?v8",pensive:"unicode/1f614.png?v8",people_holding_hands:"unicode/1f9d1-1f91d-1f9d1.png?v8",people_hugging:"unicode/1fac2.png?v8",performing_arts:"unicode/1f3ad.png?v8",persevere:"unicode/1f623.png?v8",person_bald:"unicode/1f9d1-1f9b2.png?v8",person_curly_hair:"unicode/1f9d1-1f9b1.png?v8",person_feeding_baby:"unicode/1f9d1-1f37c.png?v8",person_fencing:"unicode/1f93a.png?v8",person_in_manual_wheelchair:"unicode/1f9d1-1f9bd.png?v8",person_in_motorized_wheelchair:"unicode/1f9d1-1f9bc.png?v8",person_in_tuxedo:"unicode/1f935.png?v8",person_red_hair:"unicode/1f9d1-1f9b0.png?v8",person_white_hair:"unicode/1f9d1-1f9b3.png?v8",person_with_probing_cane:"unicode/1f9d1-1f9af.png?v8",person_with_turban:"unicode/1f473.png?v8",person_with_veil:"unicode/1f470.png?v8",peru:"unicode/1f1f5-1f1ea.png?v8",petri_dish:"unicode/1f9eb.png?v8",philippines:"unicode/1f1f5-1f1ed.png?v8",phone:"unicode/260e.png?v8",pick:"unicode/26cf.png?v8",pickup_truck:"unicode/1f6fb.png?v8",pie:"unicode/1f967.png?v8",pig:"unicode/1f437.png?v8",pig2:"unicode/1f416.png?v8",pig_nose:"unicode/1f43d.png?v8",pill:"unicode/1f48a.png?v8",pilot:"unicode/1f9d1-2708.png?v8",pinata:"unicode/1fa85.png?v8",pinched_fingers:"unicode/1f90c.png?v8",pinching_hand:"unicode/1f90f.png?v8",pineapple:"unicode/1f34d.png?v8",ping_pong:"unicode/1f3d3.png?v8",pirate_flag:"unicode/1f3f4-2620.png?v8",pisces:"unicode/2653.png?v8",pitcairn_islands:"unicode/1f1f5-1f1f3.png?v8",pizza:"unicode/1f355.png?v8",placard:"unicode/1faa7.png?v8",place_of_worship:"unicode/1f6d0.png?v8",plate_with_cutlery:"unicode/1f37d.png?v8",play_or_pause_button:"unicode/23ef.png?v8",pleading_face:"unicode/1f97a.png?v8",plunger:"unicode/1faa0.png?v8",point_down:"unicode/1f447.png?v8",point_left:"unicode/1f448.png?v8",point_right:"unicode/1f449.png?v8",point_up:"unicode/261d.png?v8",point_up_2:"unicode/1f446.png?v8",poland:"unicode/1f1f5-1f1f1.png?v8",polar_bear:"unicode/1f43b-2744.png?v8",police_car:"unicode/1f693.png?v8",police_officer:"unicode/1f46e.png?v8",policeman:"unicode/1f46e-2642.png?v8",policewoman:"unicode/1f46e-2640.png?v8",poodle:"unicode/1f429.png?v8",poop:"unicode/1f4a9.png?v8",popcorn:"unicode/1f37f.png?v8",portugal:"unicode/1f1f5-1f1f9.png?v8",post_office:"unicode/1f3e3.png?v8",postal_horn:"unicode/1f4ef.png?v8",postbox:"unicode/1f4ee.png?v8",potable_water:"unicode/1f6b0.png?v8",potato:"unicode/1f954.png?v8",potted_plant:"unicode/1fab4.png?v8",pouch:"unicode/1f45d.png?v8",poultry_leg:"unicode/1f357.png?v8",pound:"unicode/1f4b7.png?v8",pout:"unicode/1f621.png?v8",pouting_cat:"unicode/1f63e.png?v8",pouting_face:"unicode/1f64e.png?v8",pouting_man:"unicode/1f64e-2642.png?v8",pouting_woman:"unicode/1f64e-2640.png?v8",pray:"unicode/1f64f.png?v8",prayer_beads:"unicode/1f4ff.png?v8",pregnant_woman:"unicode/1f930.png?v8",pretzel:"unicode/1f968.png?v8",previous_track_button:"unicode/23ee.png?v8",prince:"unicode/1f934.png?v8",princess:"unicode/1f478.png?v8",printer:"unicode/1f5a8.png?v8",probing_cane:"unicode/1f9af.png?v8",puerto_rico:"unicode/1f1f5-1f1f7.png?v8",punch:"unicode/1f44a.png?v8",purple_circle:"unicode/1f7e3.png?v8",purple_heart:"unicode/1f49c.png?v8",purple_square:"unicode/1f7ea.png?v8",purse:"unicode/1f45b.png?v8",pushpin:"unicode/1f4cc.png?v8",put_litter_in_its_place:"unicode/1f6ae.png?v8",qatar:"unicode/1f1f6-1f1e6.png?v8",question:"unicode/2753.png?v8",rabbit:"unicode/1f430.png?v8",rabbit2:"unicode/1f407.png?v8",raccoon:"unicode/1f99d.png?v8",racehorse:"unicode/1f40e.png?v8",racing_car:"unicode/1f3ce.png?v8",radio:"unicode/1f4fb.png?v8",radio_button:"unicode/1f518.png?v8",radioactive:"unicode/2622.png?v8",rage:"unicode/1f621.png?v8",rage1:"rage1.png?v8",rage2:"rage2.png?v8",rage3:"rage3.png?v8",rage4:"rage4.png?v8",railway_car:"unicode/1f683.png?v8",railway_track:"unicode/1f6e4.png?v8",rainbow:"unicode/1f308.png?v8",rainbow_flag:"unicode/1f3f3-1f308.png?v8",raised_back_of_hand:"unicode/1f91a.png?v8",raised_eyebrow:"unicode/1f928.png?v8",raised_hand:"unicode/270b.png?v8",raised_hand_with_fingers_splayed:"unicode/1f590.png?v8",raised_hands:"unicode/1f64c.png?v8",raising_hand:"unicode/1f64b.png?v8",raising_hand_man:"unicode/1f64b-2642.png?v8",raising_hand_woman:"unicode/1f64b-2640.png?v8",ram:"unicode/1f40f.png?v8",ramen:"unicode/1f35c.png?v8",rat:"unicode/1f400.png?v8",razor:"unicode/1fa92.png?v8",receipt:"unicode/1f9fe.png?v8",record_button:"unicode/23fa.png?v8",recycle:"unicode/267b.png?v8",red_car:"unicode/1f697.png?v8",red_circle:"unicode/1f534.png?v8",red_envelope:"unicode/1f9e7.png?v8",red_haired_man:"unicode/1f468-1f9b0.png?v8",red_haired_woman:"unicode/1f469-1f9b0.png?v8",red_square:"unicode/1f7e5.png?v8",registered:"unicode/00ae.png?v8",relaxed:"unicode/263a.png?v8",relieved:"unicode/1f60c.png?v8",reminder_ribbon:"unicode/1f397.png?v8",repeat:"unicode/1f501.png?v8",repeat_one:"unicode/1f502.png?v8",rescue_worker_helmet:"unicode/26d1.png?v8",restroom:"unicode/1f6bb.png?v8",reunion:"unicode/1f1f7-1f1ea.png?v8",revolving_hearts:"unicode/1f49e.png?v8",rewind:"unicode/23ea.png?v8",rhinoceros:"unicode/1f98f.png?v8",ribbon:"unicode/1f380.png?v8",rice:"unicode/1f35a.png?v8",rice_ball:"unicode/1f359.png?v8",rice_cracker:"unicode/1f358.png?v8",rice_scene:"unicode/1f391.png?v8",right_anger_bubble:"unicode/1f5ef.png?v8",ring:"unicode/1f48d.png?v8",ringed_planet:"unicode/1fa90.png?v8",robot:"unicode/1f916.png?v8",rock:"unicode/1faa8.png?v8",rocket:"unicode/1f680.png?v8",rofl:"unicode/1f923.png?v8",roll_eyes:"unicode/1f644.png?v8",roll_of_paper:"unicode/1f9fb.png?v8",roller_coaster:"unicode/1f3a2.png?v8",roller_skate:"unicode/1f6fc.png?v8",romania:"unicode/1f1f7-1f1f4.png?v8",rooster:"unicode/1f413.png?v8",rose:"unicode/1f339.png?v8",rosette:"unicode/1f3f5.png?v8",rotating_light:"unicode/1f6a8.png?v8",round_pushpin:"unicode/1f4cd.png?v8",rowboat:"unicode/1f6a3.png?v8",rowing_man:"unicode/1f6a3-2642.png?v8",rowing_woman:"unicode/1f6a3-2640.png?v8",ru:"unicode/1f1f7-1f1fa.png?v8",rugby_football:"unicode/1f3c9.png?v8",runner:"unicode/1f3c3.png?v8",running:"unicode/1f3c3.png?v8",running_man:"unicode/1f3c3-2642.png?v8",running_shirt_with_sash:"unicode/1f3bd.png?v8",running_woman:"unicode/1f3c3-2640.png?v8",rwanda:"unicode/1f1f7-1f1fc.png?v8",sa:"unicode/1f202.png?v8",safety_pin:"unicode/1f9f7.png?v8",safety_vest:"unicode/1f9ba.png?v8",sagittarius:"unicode/2650.png?v8",sailboat:"unicode/26f5.png?v8",sake:"unicode/1f376.png?v8",salt:"unicode/1f9c2.png?v8",samoa:"unicode/1f1fc-1f1f8.png?v8",san_marino:"unicode/1f1f8-1f1f2.png?v8",sandal:"unicode/1f461.png?v8",sandwich:"unicode/1f96a.png?v8",santa:"unicode/1f385.png?v8",sao_tome_principe:"unicode/1f1f8-1f1f9.png?v8",sari:"unicode/1f97b.png?v8",sassy_man:"unicode/1f481-2642.png?v8",sassy_woman:"unicode/1f481-2640.png?v8",satellite:"unicode/1f4e1.png?v8",satisfied:"unicode/1f606.png?v8",saudi_arabia:"unicode/1f1f8-1f1e6.png?v8",sauna_man:"unicode/1f9d6-2642.png?v8",sauna_person:"unicode/1f9d6.png?v8",sauna_woman:"unicode/1f9d6-2640.png?v8",sauropod:"unicode/1f995.png?v8",saxophone:"unicode/1f3b7.png?v8",scarf:"unicode/1f9e3.png?v8",school:"unicode/1f3eb.png?v8",school_satchel:"unicode/1f392.png?v8",scientist:"unicode/1f9d1-1f52c.png?v8",scissors:"unicode/2702.png?v8",scorpion:"unicode/1f982.png?v8",scorpius:"unicode/264f.png?v8",scotland:"unicode/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png?v8",scream:"unicode/1f631.png?v8",scream_cat:"unicode/1f640.png?v8",screwdriver:"unicode/1fa9b.png?v8",scroll:"unicode/1f4dc.png?v8",seal:"unicode/1f9ad.png?v8",seat:"unicode/1f4ba.png?v8",secret:"unicode/3299.png?v8",see_no_evil:"unicode/1f648.png?v8",seedling:"unicode/1f331.png?v8",selfie:"unicode/1f933.png?v8",senegal:"unicode/1f1f8-1f1f3.png?v8",serbia:"unicode/1f1f7-1f1f8.png?v8",service_dog:"unicode/1f415-1f9ba.png?v8",seven:"unicode/0037-20e3.png?v8",sewing_needle:"unicode/1faa1.png?v8",seychelles:"unicode/1f1f8-1f1e8.png?v8",shallow_pan_of_food:"unicode/1f958.png?v8",shamrock:"unicode/2618.png?v8",shark:"unicode/1f988.png?v8",shaved_ice:"unicode/1f367.png?v8",sheep:"unicode/1f411.png?v8",shell:"unicode/1f41a.png?v8",shield:"unicode/1f6e1.png?v8",shinto_shrine:"unicode/26e9.png?v8",ship:"unicode/1f6a2.png?v8",shipit:"shipit.png?v8",shirt:"unicode/1f455.png?v8",shit:"unicode/1f4a9.png?v8",shoe:"unicode/1f45e.png?v8",shopping:"unicode/1f6cd.png?v8",shopping_cart:"unicode/1f6d2.png?v8",shorts:"unicode/1fa73.png?v8",shower:"unicode/1f6bf.png?v8",shrimp:"unicode/1f990.png?v8",shrug:"unicode/1f937.png?v8",shushing_face:"unicode/1f92b.png?v8",sierra_leone:"unicode/1f1f8-1f1f1.png?v8",signal_strength:"unicode/1f4f6.png?v8",singapore:"unicode/1f1f8-1f1ec.png?v8",singer:"unicode/1f9d1-1f3a4.png?v8",sint_maarten:"unicode/1f1f8-1f1fd.png?v8",six:"unicode/0036-20e3.png?v8",six_pointed_star:"unicode/1f52f.png?v8",skateboard:"unicode/1f6f9.png?v8",ski:"unicode/1f3bf.png?v8",skier:"unicode/26f7.png?v8",skull:"unicode/1f480.png?v8",skull_and_crossbones:"unicode/2620.png?v8",skunk:"unicode/1f9a8.png?v8",sled:"unicode/1f6f7.png?v8",sleeping:"unicode/1f634.png?v8",sleeping_bed:"unicode/1f6cc.png?v8",sleepy:"unicode/1f62a.png?v8",slightly_frowning_face:"unicode/1f641.png?v8",slightly_smiling_face:"unicode/1f642.png?v8",slot_machine:"unicode/1f3b0.png?v8",sloth:"unicode/1f9a5.png?v8",slovakia:"unicode/1f1f8-1f1f0.png?v8",slovenia:"unicode/1f1f8-1f1ee.png?v8",small_airplane:"unicode/1f6e9.png?v8",small_blue_diamond:"unicode/1f539.png?v8",small_orange_diamond:"unicode/1f538.png?v8",small_red_triangle:"unicode/1f53a.png?v8",small_red_triangle_down:"unicode/1f53b.png?v8",smile:"unicode/1f604.png?v8",smile_cat:"unicode/1f638.png?v8",smiley:"unicode/1f603.png?v8",smiley_cat:"unicode/1f63a.png?v8",smiling_face_with_tear:"unicode/1f972.png?v8",smiling_face_with_three_hearts:"unicode/1f970.png?v8",smiling_imp:"unicode/1f608.png?v8",smirk:"unicode/1f60f.png?v8",smirk_cat:"unicode/1f63c.png?v8",smoking:"unicode/1f6ac.png?v8",snail:"unicode/1f40c.png?v8",snake:"unicode/1f40d.png?v8",sneezing_face:"unicode/1f927.png?v8",snowboarder:"unicode/1f3c2.png?v8",snowflake:"unicode/2744.png?v8",snowman:"unicode/26c4.png?v8",snowman_with_snow:"unicode/2603.png?v8",soap:"unicode/1f9fc.png?v8",sob:"unicode/1f62d.png?v8",soccer:"unicode/26bd.png?v8",socks:"unicode/1f9e6.png?v8",softball:"unicode/1f94e.png?v8",solomon_islands:"unicode/1f1f8-1f1e7.png?v8",somalia:"unicode/1f1f8-1f1f4.png?v8",soon:"unicode/1f51c.png?v8",sos:"unicode/1f198.png?v8",sound:"unicode/1f509.png?v8",south_africa:"unicode/1f1ff-1f1e6.png?v8",south_georgia_south_sandwich_islands:"unicode/1f1ec-1f1f8.png?v8",south_sudan:"unicode/1f1f8-1f1f8.png?v8",space_invader:"unicode/1f47e.png?v8",spades:"unicode/2660.png?v8",spaghetti:"unicode/1f35d.png?v8",sparkle:"unicode/2747.png?v8",sparkler:"unicode/1f387.png?v8",sparkles:"unicode/2728.png?v8",sparkling_heart:"unicode/1f496.png?v8",speak_no_evil:"unicode/1f64a.png?v8",speaker:"unicode/1f508.png?v8",speaking_head:"unicode/1f5e3.png?v8",speech_balloon:"unicode/1f4ac.png?v8",speedboat:"unicode/1f6a4.png?v8",spider:"unicode/1f577.png?v8",spider_web:"unicode/1f578.png?v8",spiral_calendar:"unicode/1f5d3.png?v8",spiral_notepad:"unicode/1f5d2.png?v8",sponge:"unicode/1f9fd.png?v8",spoon:"unicode/1f944.png?v8",squid:"unicode/1f991.png?v8",sri_lanka:"unicode/1f1f1-1f1f0.png?v8",st_barthelemy:"unicode/1f1e7-1f1f1.png?v8",st_helena:"unicode/1f1f8-1f1ed.png?v8",st_kitts_nevis:"unicode/1f1f0-1f1f3.png?v8",st_lucia:"unicode/1f1f1-1f1e8.png?v8",st_martin:"unicode/1f1f2-1f1eb.png?v8",st_pierre_miquelon:"unicode/1f1f5-1f1f2.png?v8",st_vincent_grenadines:"unicode/1f1fb-1f1e8.png?v8",stadium:"unicode/1f3df.png?v8",standing_man:"unicode/1f9cd-2642.png?v8",standing_person:"unicode/1f9cd.png?v8",standing_woman:"unicode/1f9cd-2640.png?v8",star:"unicode/2b50.png?v8",star2:"unicode/1f31f.png?v8",star_and_crescent:"unicode/262a.png?v8",star_of_david:"unicode/2721.png?v8",star_struck:"unicode/1f929.png?v8",stars:"unicode/1f320.png?v8",station:"unicode/1f689.png?v8",statue_of_liberty:"unicode/1f5fd.png?v8",steam_locomotive:"unicode/1f682.png?v8",stethoscope:"unicode/1fa7a.png?v8",stew:"unicode/1f372.png?v8",stop_button:"unicode/23f9.png?v8",stop_sign:"unicode/1f6d1.png?v8",stopwatch:"unicode/23f1.png?v8",straight_ruler:"unicode/1f4cf.png?v8",strawberry:"unicode/1f353.png?v8",stuck_out_tongue:"unicode/1f61b.png?v8",stuck_out_tongue_closed_eyes:"unicode/1f61d.png?v8",stuck_out_tongue_winking_eye:"unicode/1f61c.png?v8",student:"unicode/1f9d1-1f393.png?v8",studio_microphone:"unicode/1f399.png?v8",stuffed_flatbread:"unicode/1f959.png?v8",sudan:"unicode/1f1f8-1f1e9.png?v8",sun_behind_large_cloud:"unicode/1f325.png?v8",sun_behind_rain_cloud:"unicode/1f326.png?v8",sun_behind_small_cloud:"unicode/1f324.png?v8",sun_with_face:"unicode/1f31e.png?v8",sunflower:"unicode/1f33b.png?v8",sunglasses:"unicode/1f60e.png?v8",sunny:"unicode/2600.png?v8",sunrise:"unicode/1f305.png?v8",sunrise_over_mountains:"unicode/1f304.png?v8",superhero:"unicode/1f9b8.png?v8",superhero_man:"unicode/1f9b8-2642.png?v8",superhero_woman:"unicode/1f9b8-2640.png?v8",supervillain:"unicode/1f9b9.png?v8",supervillain_man:"unicode/1f9b9-2642.png?v8",supervillain_woman:"unicode/1f9b9-2640.png?v8",surfer:"unicode/1f3c4.png?v8",surfing_man:"unicode/1f3c4-2642.png?v8",surfing_woman:"unicode/1f3c4-2640.png?v8",suriname:"unicode/1f1f8-1f1f7.png?v8",sushi:"unicode/1f363.png?v8",suspect:"suspect.png?v8",suspension_railway:"unicode/1f69f.png?v8",svalbard_jan_mayen:"unicode/1f1f8-1f1ef.png?v8",swan:"unicode/1f9a2.png?v8",swaziland:"unicode/1f1f8-1f1ff.png?v8",sweat:"unicode/1f613.png?v8",sweat_drops:"unicode/1f4a6.png?v8",sweat_smile:"unicode/1f605.png?v8",sweden:"unicode/1f1f8-1f1ea.png?v8",sweet_potato:"unicode/1f360.png?v8",swim_brief:"unicode/1fa72.png?v8",swimmer:"unicode/1f3ca.png?v8",swimming_man:"unicode/1f3ca-2642.png?v8",swimming_woman:"unicode/1f3ca-2640.png?v8",switzerland:"unicode/1f1e8-1f1ed.png?v8",symbols:"unicode/1f523.png?v8",synagogue:"unicode/1f54d.png?v8",syria:"unicode/1f1f8-1f1fe.png?v8",syringe:"unicode/1f489.png?v8","t-rex":"unicode/1f996.png?v8",taco:"unicode/1f32e.png?v8",tada:"unicode/1f389.png?v8",taiwan:"unicode/1f1f9-1f1fc.png?v8",tajikistan:"unicode/1f1f9-1f1ef.png?v8",takeout_box:"unicode/1f961.png?v8",tamale:"unicode/1fad4.png?v8",tanabata_tree:"unicode/1f38b.png?v8",tangerine:"unicode/1f34a.png?v8",tanzania:"unicode/1f1f9-1f1ff.png?v8",taurus:"unicode/2649.png?v8",taxi:"unicode/1f695.png?v8",tea:"unicode/1f375.png?v8",teacher:"unicode/1f9d1-1f3eb.png?v8",teapot:"unicode/1fad6.png?v8",technologist:"unicode/1f9d1-1f4bb.png?v8",teddy_bear:"unicode/1f9f8.png?v8",telephone:"unicode/260e.png?v8",telephone_receiver:"unicode/1f4de.png?v8",telescope:"unicode/1f52d.png?v8",tennis:"unicode/1f3be.png?v8",tent:"unicode/26fa.png?v8",test_tube:"unicode/1f9ea.png?v8",thailand:"unicode/1f1f9-1f1ed.png?v8",thermometer:"unicode/1f321.png?v8",thinking:"unicode/1f914.png?v8",thong_sandal:"unicode/1fa74.png?v8",thought_balloon:"unicode/1f4ad.png?v8",thread:"unicode/1f9f5.png?v8",three:"unicode/0033-20e3.png?v8",thumbsdown:"unicode/1f44e.png?v8",thumbsup:"unicode/1f44d.png?v8",ticket:"unicode/1f3ab.png?v8",tickets:"unicode/1f39f.png?v8",tiger:"unicode/1f42f.png?v8",tiger2:"unicode/1f405.png?v8",timer_clock:"unicode/23f2.png?v8",timor_leste:"unicode/1f1f9-1f1f1.png?v8",tipping_hand_man:"unicode/1f481-2642.png?v8",tipping_hand_person:"unicode/1f481.png?v8",tipping_hand_woman:"unicode/1f481-2640.png?v8",tired_face:"unicode/1f62b.png?v8",tm:"unicode/2122.png?v8",togo:"unicode/1f1f9-1f1ec.png?v8",toilet:"unicode/1f6bd.png?v8",tokelau:"unicode/1f1f9-1f1f0.png?v8",tokyo_tower:"unicode/1f5fc.png?v8",tomato:"unicode/1f345.png?v8",tonga:"unicode/1f1f9-1f1f4.png?v8",tongue:"unicode/1f445.png?v8",toolbox:"unicode/1f9f0.png?v8",tooth:"unicode/1f9b7.png?v8",toothbrush:"unicode/1faa5.png?v8",top:"unicode/1f51d.png?v8",tophat:"unicode/1f3a9.png?v8",tornado:"unicode/1f32a.png?v8",tr:"unicode/1f1f9-1f1f7.png?v8",trackball:"unicode/1f5b2.png?v8",tractor:"unicode/1f69c.png?v8",traffic_light:"unicode/1f6a5.png?v8",train:"unicode/1f68b.png?v8",train2:"unicode/1f686.png?v8",tram:"unicode/1f68a.png?v8",transgender_flag:"unicode/1f3f3-26a7.png?v8",transgender_symbol:"unicode/26a7.png?v8",triangular_flag_on_post:"unicode/1f6a9.png?v8",triangular_ruler:"unicode/1f4d0.png?v8",trident:"unicode/1f531.png?v8",trinidad_tobago:"unicode/1f1f9-1f1f9.png?v8",tristan_da_cunha:"unicode/1f1f9-1f1e6.png?v8",triumph:"unicode/1f624.png?v8",trolleybus:"unicode/1f68e.png?v8",trollface:"trollface.png?v8",trophy:"unicode/1f3c6.png?v8",tropical_drink:"unicode/1f379.png?v8",tropical_fish:"unicode/1f420.png?v8",truck:"unicode/1f69a.png?v8",trumpet:"unicode/1f3ba.png?v8",tshirt:"unicode/1f455.png?v8",tulip:"unicode/1f337.png?v8",tumbler_glass:"unicode/1f943.png?v8",tunisia:"unicode/1f1f9-1f1f3.png?v8",turkey:"unicode/1f983.png?v8",turkmenistan:"unicode/1f1f9-1f1f2.png?v8",turks_caicos_islands:"unicode/1f1f9-1f1e8.png?v8",turtle:"unicode/1f422.png?v8",tuvalu:"unicode/1f1f9-1f1fb.png?v8",tv:"unicode/1f4fa.png?v8",twisted_rightwards_arrows:"unicode/1f500.png?v8",two:"unicode/0032-20e3.png?v8",two_hearts:"unicode/1f495.png?v8",two_men_holding_hands:"unicode/1f46c.png?v8",two_women_holding_hands:"unicode/1f46d.png?v8",u5272:"unicode/1f239.png?v8",u5408:"unicode/1f234.png?v8",u55b6:"unicode/1f23a.png?v8",u6307:"unicode/1f22f.png?v8",u6708:"unicode/1f237.png?v8",u6709:"unicode/1f236.png?v8",u6e80:"unicode/1f235.png?v8",u7121:"unicode/1f21a.png?v8",u7533:"unicode/1f238.png?v8",u7981:"unicode/1f232.png?v8",u7a7a:"unicode/1f233.png?v8",uganda:"unicode/1f1fa-1f1ec.png?v8",uk:"unicode/1f1ec-1f1e7.png?v8",ukraine:"unicode/1f1fa-1f1e6.png?v8",umbrella:"unicode/2614.png?v8",unamused:"unicode/1f612.png?v8",underage:"unicode/1f51e.png?v8",unicorn:"unicode/1f984.png?v8",united_arab_emirates:"unicode/1f1e6-1f1ea.png?v8",united_nations:"unicode/1f1fa-1f1f3.png?v8",unlock:"unicode/1f513.png?v8",up:"unicode/1f199.png?v8",upside_down_face:"unicode/1f643.png?v8",uruguay:"unicode/1f1fa-1f1fe.png?v8",us:"unicode/1f1fa-1f1f8.png?v8",us_outlying_islands:"unicode/1f1fa-1f1f2.png?v8",us_virgin_islands:"unicode/1f1fb-1f1ee.png?v8",uzbekistan:"unicode/1f1fa-1f1ff.png?v8",v:"unicode/270c.png?v8",vampire:"unicode/1f9db.png?v8",vampire_man:"unicode/1f9db-2642.png?v8",vampire_woman:"unicode/1f9db-2640.png?v8",vanuatu:"unicode/1f1fb-1f1fa.png?v8",vatican_city:"unicode/1f1fb-1f1e6.png?v8",venezuela:"unicode/1f1fb-1f1ea.png?v8",vertical_traffic_light:"unicode/1f6a6.png?v8",vhs:"unicode/1f4fc.png?v8",vibration_mode:"unicode/1f4f3.png?v8",video_camera:"unicode/1f4f9.png?v8",video_game:"unicode/1f3ae.png?v8",vietnam:"unicode/1f1fb-1f1f3.png?v8",violin:"unicode/1f3bb.png?v8",virgo:"unicode/264d.png?v8",volcano:"unicode/1f30b.png?v8",volleyball:"unicode/1f3d0.png?v8",vomiting_face:"unicode/1f92e.png?v8",vs:"unicode/1f19a.png?v8",vulcan_salute:"unicode/1f596.png?v8",waffle:"unicode/1f9c7.png?v8",wales:"unicode/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png?v8",walking:"unicode/1f6b6.png?v8",walking_man:"unicode/1f6b6-2642.png?v8",walking_woman:"unicode/1f6b6-2640.png?v8",wallis_futuna:"unicode/1f1fc-1f1eb.png?v8",waning_crescent_moon:"unicode/1f318.png?v8",waning_gibbous_moon:"unicode/1f316.png?v8",warning:"unicode/26a0.png?v8",wastebasket:"unicode/1f5d1.png?v8",watch:"unicode/231a.png?v8",water_buffalo:"unicode/1f403.png?v8",water_polo:"unicode/1f93d.png?v8",watermelon:"unicode/1f349.png?v8",wave:"unicode/1f44b.png?v8",wavy_dash:"unicode/3030.png?v8",waxing_crescent_moon:"unicode/1f312.png?v8",waxing_gibbous_moon:"unicode/1f314.png?v8",wc:"unicode/1f6be.png?v8",weary:"unicode/1f629.png?v8",wedding:"unicode/1f492.png?v8",weight_lifting:"unicode/1f3cb.png?v8",weight_lifting_man:"unicode/1f3cb-2642.png?v8",weight_lifting_woman:"unicode/1f3cb-2640.png?v8",western_sahara:"unicode/1f1ea-1f1ed.png?v8",whale:"unicode/1f433.png?v8",whale2:"unicode/1f40b.png?v8",wheel_of_dharma:"unicode/2638.png?v8",wheelchair:"unicode/267f.png?v8",white_check_mark:"unicode/2705.png?v8",white_circle:"unicode/26aa.png?v8",white_flag:"unicode/1f3f3.png?v8",white_flower:"unicode/1f4ae.png?v8",white_haired_man:"unicode/1f468-1f9b3.png?v8",white_haired_woman:"unicode/1f469-1f9b3.png?v8",white_heart:"unicode/1f90d.png?v8",white_large_square:"unicode/2b1c.png?v8",white_medium_small_square:"unicode/25fd.png?v8",white_medium_square:"unicode/25fb.png?v8",white_small_square:"unicode/25ab.png?v8",white_square_button:"unicode/1f533.png?v8",wilted_flower:"unicode/1f940.png?v8",wind_chime:"unicode/1f390.png?v8",wind_face:"unicode/1f32c.png?v8",window:"unicode/1fa9f.png?v8",wine_glass:"unicode/1f377.png?v8",wink:"unicode/1f609.png?v8",wolf:"unicode/1f43a.png?v8",woman:"unicode/1f469.png?v8",woman_artist:"unicode/1f469-1f3a8.png?v8",woman_astronaut:"unicode/1f469-1f680.png?v8",woman_beard:"unicode/1f9d4-2640.png?v8",woman_cartwheeling:"unicode/1f938-2640.png?v8",woman_cook:"unicode/1f469-1f373.png?v8",woman_dancing:"unicode/1f483.png?v8",woman_facepalming:"unicode/1f926-2640.png?v8",woman_factory_worker:"unicode/1f469-1f3ed.png?v8",woman_farmer:"unicode/1f469-1f33e.png?v8",woman_feeding_baby:"unicode/1f469-1f37c.png?v8",woman_firefighter:"unicode/1f469-1f692.png?v8",woman_health_worker:"unicode/1f469-2695.png?v8",woman_in_manual_wheelchair:"unicode/1f469-1f9bd.png?v8",woman_in_motorized_wheelchair:"unicode/1f469-1f9bc.png?v8",woman_in_tuxedo:"unicode/1f935-2640.png?v8",woman_judge:"unicode/1f469-2696.png?v8",woman_juggling:"unicode/1f939-2640.png?v8",woman_mechanic:"unicode/1f469-1f527.png?v8",woman_office_worker:"unicode/1f469-1f4bc.png?v8",woman_pilot:"unicode/1f469-2708.png?v8",woman_playing_handball:"unicode/1f93e-2640.png?v8",woman_playing_water_polo:"unicode/1f93d-2640.png?v8",woman_scientist:"unicode/1f469-1f52c.png?v8",woman_shrugging:"unicode/1f937-2640.png?v8",woman_singer:"unicode/1f469-1f3a4.png?v8",woman_student:"unicode/1f469-1f393.png?v8",woman_teacher:"unicode/1f469-1f3eb.png?v8",woman_technologist:"unicode/1f469-1f4bb.png?v8",woman_with_headscarf:"unicode/1f9d5.png?v8",woman_with_probing_cane:"unicode/1f469-1f9af.png?v8",woman_with_turban:"unicode/1f473-2640.png?v8",woman_with_veil:"unicode/1f470-2640.png?v8",womans_clothes:"unicode/1f45a.png?v8",womans_hat:"unicode/1f452.png?v8",women_wrestling:"unicode/1f93c-2640.png?v8",womens:"unicode/1f6ba.png?v8",wood:"unicode/1fab5.png?v8",woozy_face:"unicode/1f974.png?v8",world_map:"unicode/1f5fa.png?v8",worm:"unicode/1fab1.png?v8",worried:"unicode/1f61f.png?v8",wrench:"unicode/1f527.png?v8",wrestling:"unicode/1f93c.png?v8",writing_hand:"unicode/270d.png?v8",x:"unicode/274c.png?v8",yarn:"unicode/1f9f6.png?v8",yawning_face:"unicode/1f971.png?v8",yellow_circle:"unicode/1f7e1.png?v8",yellow_heart:"unicode/1f49b.png?v8",yellow_square:"unicode/1f7e8.png?v8",yemen:"unicode/1f1fe-1f1ea.png?v8",yen:"unicode/1f4b4.png?v8",yin_yang:"unicode/262f.png?v8",yo_yo:"unicode/1fa80.png?v8",yum:"unicode/1f60b.png?v8",zambia:"unicode/1f1ff-1f1f2.png?v8",zany_face:"unicode/1f92a.png?v8",zap:"unicode/26a1.png?v8",zebra:"unicode/1f993.png?v8",zero:"unicode/0030-20e3.png?v8",zimbabwe:"unicode/1f1ff-1f1fc.png?v8",zipper_mouth_face:"unicode/1f910.png?v8",zombie:"unicode/1f9df.png?v8",zombie_man:"unicode/1f9df-2642.png?v8",zombie_woman:"unicode/1f9df-2640.png?v8",zzz:"unicode/1f4a4.png?v8"};window&&window.console&&console.info("Docsify emoji plugin has been deprecated as of v4.13"),window.emojify=function(n,e){return!1===Object.prototype.hasOwnProperty.call(i,e)?n:''+e+''}}(); \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/static/js/prism-bash.min.js b/ruoyi-admin/src/main/resources/static/static/js/prism-bash.min.js deleted file mode 100644 index f1659f1e..00000000 --- a/ruoyi-admin/src/main/resources/static/static/js/prism-bash.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",a={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},n={bash:a,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},parameter:{pattern:/(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/,alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:n},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:a}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:n},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:n.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:n.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},a.inside=e.languages.bash;for(var s=["comment","function-name","for-or-select","assign-left","parameter","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=n.variable[1].inside,i=0;i]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var s=e.languages.extend("typescript",{});delete s["class-name"],e.languages.typescript["class-name"].inside=s,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:s}}}}),e.languages.ts=e.languages.typescript}(Prism); \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/static/js/search.min.js b/ruoyi-admin/src/main/resources/static/static/js/search.min.js deleted file mode 100644 index 9719f653..00000000 --- a/ruoyi-admin/src/main/resources/static/static/js/search.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(){function u(e){return e.replace(//,"").replace(/{docsify-ignore}/,"").replace(//,"").replace(/{docsify-ignore-all}/,"").trim()}var f={},m={EXPIRE_KEY:"docsify.search.expires",INDEX_KEY:"docsify.search.index"};function g(e){var n={"&":"&","<":"<",">":">",'"':""","'":"'"};return String(e).replace(/[&<>"']/g,function(e){return n[e]})}function y(e){return e.text||"table"!==e.type||(e.cells.unshift(e.header),e.text=e.cells.map(function(e){return e.join(" | ")}).join(" |\n ")),e.text}function v(e){return e.text||"list"!==e.type||(e.text=e.raw),e.text}function b(o,e,s,c){void 0===e&&(e="");var d,e=window.marked.lexer(e),l=window.Docsify.slugify,p={},h="";return e.forEach(function(e,n){var t,a,i,r;"heading"===e.type&&e.depth<=c?(t=(a=(i=e.text,r={},{str:i=(i=void 0===i?"":i)&&i.replace(/^('|")/,"").replace(/('|")$/,"").replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g,function(e,n,t){return-1===n.indexOf(":")?(r[n]=t&&t.replace(/"/g,"")||!0,""):e}).trim(),config:r})).str,i=a.config,a=u(e.text),d=i.id?s.toURL(o,{id:l(i.id)}):s.toURL(o,{id:l(g(a))}),t&&(h=u(t)),p[d]={slug:d,title:h,body:""}):(0===n&&(d=s.toURL(o),p[d]={slug:d,title:"/"!==o?o.slice(1):"Home Page",body:e.text||""}),d&&(p[d]?p[d].body?(e.text=y(e),e.text=v(e),p[d].body+="\n"+(e.text||"")):(e.text=y(e),e.text=v(e),p[d].body=e.text||""):p[d]={slug:d,title:"",body:""}))}),l.clear(),p}function p(e){return e&&e.normalize?e.normalize("NFD").replace(/[\u0300-\u036f]/g,""):e}function o(e){var n=[],t=[];Object.keys(f).forEach(function(n){t=t.concat(Object.keys(f[n]).map(function(e){return f[n][e]}))});var a=(e=e.trim()).split(/[\s\-,\\/]+/);1!==a.length&&(a=[].concat(e,a));for(var i=0;il.length&&(t=l.length),a=c&&"..."+c.substring(n,t).replace(a,function(e){return''+e+""})+"...",o+=a)}),0\n\n

    '+e.title+"

    \n

    "+e.content+"

    \n
    \n"}),t.classList.add("show"),a.classList.add("show"),t.innerHTML=r||'

    '+c+"

    ",s.hideOtherSidebarContent&&(i&&i.classList.add("hide"),n&&n.classList.add("hide"))}function l(e){s=e}function h(e,n){var t,a,i=n.router.parse().query.s;l(e),Docsify.dom.style("\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .input-wrap {\n display: flex;\n align-items: center;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 0.6em 7px;\n font-size: inherit;\n border: 1px solid transparent;\n}\n\n.search input:focus {\n box-shadow: 0 0 5px var(--theme-color, #42b983);\n border: 1px solid var(--theme-color, #42b983);\n}\n\n.search input::-webkit-search-decoration,\n.search input::-webkit-search-cancel-button,\n.search input {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\n.search input::-ms-clear {\n display: none;\n height: 0;\n width: 0;\n}\n\n.search .clear-button {\n cursor: pointer;\n width: 36px;\n text-align: right;\n display: none;\n}\n\n.search .clear-button.show {\n display: block;\n}\n\n.search .clear-button svg {\n transform: scale(.5);\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}\n\n.app-name.hide, .sidebar-nav.hide {\n display: none;\n}"),function(e){void 0===e&&(e="");var n=Docsify.dom.create("div",'
    \n \n
    \n \n \n \n \n \n
    \n
    \n
    \n '),e=Docsify.dom.find("aside");Docsify.dom.toggleClass(n,"search"),Docsify.dom.before(e,n)}(i),n=Docsify.dom.find("div.search"),a=Docsify.dom.find(n,"input"),e=Docsify.dom.find(n,".input-wrap"),Docsify.dom.on(n,"click",function(e){return-1===["A","H2","P","EM"].indexOf(e.target.tagName)&&e.stopPropagation()}),Docsify.dom.on(a,"input",function(n){clearTimeout(t),t=setTimeout(function(e){return d(n.target.value.trim())},100)}),Docsify.dom.on(e,"click",function(e){"INPUT"!==e.target.tagName&&(a.value="",d())}),i&&setTimeout(function(e){return d(i)},500)}function x(e,n){var t,a,i,r,o;l(e),t=e.placeholder,a=n.route.path,(r=Docsify.dom.getNode('.search input[type="search"]'))&&("string"==typeof t?r.placeholder=t:(i=Object.keys(t).filter(function(e){return-1u.scrollOffset&&setTimeout(a,150))}),window.addEventListener("resize",a);var f={open:i,close:a,toggle:o,update:function(){var e=0 com.squareup.okhttp3 okhttp + ${okhttp.version}
    com.squareup.okhttp3 okhttp-sse + ${okhttp.version} com.squareup.okhttp3 logging-interceptor + ${okhttp.version} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/constant/RegexConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/constant/RegexConstants.java new file mode 100644 index 00000000..0e9abd8a --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/constant/RegexConstants.java @@ -0,0 +1,59 @@ +package org.ruoyi.common.core.constant; + +import cn.hutool.core.lang.RegexPool; + +/** + * 常用正则表达式字符串 + *

    + * 常用正则表达式集合,更多正则见: https://any86.github.io/any-rule/ + * + * @author Feng + */ +public interface RegexConstants extends RegexPool { + + /** + * 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线) + */ + String DICTIONARY_TYPE = "^[a-z][a-z0-9_]*$"; + + /** + * 权限标识必须符合以下格式: + * 1. 标准格式:xxx:yyy:zzz + * - 第一部分(xxx):只能包含字母、数字和下划线(_),不能使用 `*` + * - 第二部分(yyy):可以包含字母、数字、下划线(_)和 `*` + * - 第三部分(zzz):可以包含字母、数字、下划线(_)和 `*` + * 2. 允许空字符串(""),表示没有权限标识 + */ + String PERMISSION_STRING = "^$|^[a-zA-Z0-9_]+:[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]+$"; + + /** + * 身份证号码(后6位) + */ + String ID_CARD_LAST_6 = "^(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$"; + + /** + * QQ号码 + */ + String QQ_NUMBER = "^[1-9][0-9]\\d{4,9}$"; + + /** + * 邮政编码 + */ + String POSTAL_CODE = "^[1-9]\\d{5}$"; + + /** + * 注册账号 + */ + String ACCOUNT = "^[a-zA-Z][a-zA-Z0-9_]{4,15}$"; + + /** + * 密码:包含至少8个字符,包括大写字母、小写字母、数字和特殊字符 + */ + String PASSWORD = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$"; + + /** + * 通用状态(0表示正常,1表示停用) + */ + String STATUS = "^[01]$"; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/constant/SystemConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/constant/SystemConstants.java new file mode 100644 index 00000000..adde6d58 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/constant/SystemConstants.java @@ -0,0 +1,80 @@ +package org.ruoyi.common.core.constant; + +/** + * 系统常量信息 + * + * @author Lion Li + */ +public interface SystemConstants { + + /** + * 正常状态 + */ + String NORMAL = "0"; + + /** + * 异常状态 + */ + String DISABLE = "1"; + + /** + * 是否为系统默认(是) + */ + String YES = "Y"; + + /** + * 是否为系统默认(否) + */ + String NO = "N"; + + /** + * 是否菜单外链(是) + */ + String YES_FRAME = "0"; + + /** + * 是否菜单外链(否) + */ + String NO_FRAME = "1"; + + /** + * 菜单类型(目录) + */ + String TYPE_DIR = "M"; + + /** + * 菜单类型(菜单) + */ + String TYPE_MENU = "C"; + + /** + * 菜单类型(按钮) + */ + String TYPE_BUTTON = "F"; + + /** + * Layout组件标识 + */ + String LAYOUT = "Layout"; + + /** + * ParentView组件标识 + */ + String PARENT_VIEW = "ParentView"; + + /** + * InnerLink组件标识 + */ + String INNER_LINK = "InnerLink"; + + /** + * 超级管理员ID + */ + Long SUPER_ADMIN_ID = 1L; + + /** + * 根部门祖级列表 + */ + String ROOT_DEPT_ANCESTORS = "0"; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/factory/RegexPatternPoolFactory.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/factory/RegexPatternPoolFactory.java new file mode 100644 index 00000000..c15bdbac --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/factory/RegexPatternPoolFactory.java @@ -0,0 +1,53 @@ +package org.ruoyi.common.core.factory; + +import cn.hutool.core.lang.PatternPool; +import org.ruoyi.common.core.constant.RegexConstants; + + +import java.util.regex.Pattern; + +/** + * 正则表达式模式池工厂 + *

    初始化的时候将正则表达式加入缓存池当中

    + *

    提高正则表达式的性能,避免重复编译相同的正则表达式

    + * + * @author 21001 + */ +public class RegexPatternPoolFactory extends PatternPool { + + /** + * 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线) + */ + public static final Pattern DICTIONARY_TYPE = get(RegexConstants.DICTIONARY_TYPE); + + /** + * 身份证号码(后6位) + */ + public static final Pattern ID_CARD_LAST_6 = get(RegexConstants.ID_CARD_LAST_6); + + /** + * QQ号码 + */ + public static final Pattern QQ_NUMBER = get(RegexConstants.QQ_NUMBER); + + /** + * 邮政编码 + */ + public static final Pattern POSTAL_CODE = get(RegexConstants.POSTAL_CODE); + + /** + * 注册账号 + */ + public static final Pattern ACCOUNT = get(RegexConstants.ACCOUNT); + + /** + * 密码:包含至少8个字符,包括大写字母、小写字母、数字和特殊字符 + */ + public static final Pattern PASSWORD = get(RegexConstants.PASSWORD); + + /** + * 通用状态(0表示正常,1表示停用) + */ + public static final Pattern STATUS = get(RegexConstants.STATUS); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/factory/YmlPropertySourceFactory.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/factory/YmlPropertySourceFactory.java new file mode 100644 index 00000000..3b356d82 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/factory/YmlPropertySourceFactory.java @@ -0,0 +1,32 @@ +package org.ruoyi.common.core.factory; + + +import org.ruoyi.common.core.utils.StringUtils; +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.support.DefaultPropertySourceFactory; +import org.springframework.core.io.support.EncodedResource; + +import java.io.IOException; + +/** + * yml 配置源工厂 + * + * @author Lion Li + */ +public class YmlPropertySourceFactory extends DefaultPropertySourceFactory { + + @Override + public PropertySource createPropertySource(String name, EncodedResource resource) throws IOException { + String sourceName = resource.getResource().getFilename(); + if (StringUtils.isNotBlank(sourceName) && StringUtils.endsWithAny(sourceName, ".yml", ".yaml")) { + YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); + factory.setResources(resource.getResource()); + factory.afterPropertiesSet(); + return new PropertiesPropertySource(sourceName, factory.getObject()); + } + return super.createPropertySource(name, resource); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/ObjectUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/ObjectUtils.java new file mode 100644 index 00000000..7f7d5910 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/ObjectUtils.java @@ -0,0 +1,60 @@ +package org.ruoyi.common.core.utils; + +import cn.hutool.core.util.ObjectUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.function.Function; + +/** + * 对象工具类 + * + * @author 秋辞未寒 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ObjectUtils extends ObjectUtil { + + /** + * 如果对象不为空,则获取对象中的某个字段 ObjectUtils.notNullGetter(user, User::getName); + * + * @param obj 对象 + * @param func 获取方法 + * @return 对象字段 + */ + public static E notNullGetter(T obj, Function func) { + if (isNotNull(obj) && isNotNull(func)) { + return func.apply(obj); + } + return null; + } + + /** + * 如果对象不为空,则获取对象中的某个字段,否则返回默认值 + * + * @param obj 对象 + * @param func 获取方法 + * @param defaultValue 默认值 + * @return 对象字段 + */ + public static E notNullGetter(T obj, Function func, E defaultValue) { + if (isNotNull(obj) && isNotNull(func)) { + return func.apply(obj); + } + return defaultValue; + } + + /** + * 如果值不为空,则返回值,否则返回默认值 + * + * @param obj 对象 + * @param defaultValue 默认值 + * @return 对象字段 + */ + public static T notNull(T obj, T defaultValue) { + if (isNotNull(obj)) { + return obj; + } + return defaultValue; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/SpringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/SpringUtils.java index 99937c79..bd5dc544 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/SpringUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/utils/SpringUtils.java @@ -1,9 +1,10 @@ package org.ruoyi.common.core.utils; import cn.hutool.extra.spring.SpringUtil; -import org.springframework.aop.framework.AopContext; import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.boot.autoconfigure.thread.Threading; import org.springframework.context.ApplicationContext; +import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; /** @@ -48,7 +49,7 @@ public final class SpringUtils extends SpringUtil { */ @SuppressWarnings("unchecked") public static T getAopProxy(T invoker) { - return (T) AopContext.currentProxy(); + return (T) getBean(invoker.getClass()); } @@ -59,4 +60,8 @@ public final class SpringUtils extends SpringUtil { return getApplicationContext(); } + public static boolean isVirtual() { + return Threading.VIRTUAL.isActive(getBean(Environment.class)); + } + } diff --git a/ruoyi-common/ruoyi-common-encrypt/pom.xml b/ruoyi-common/ruoyi-common-encrypt/pom.xml index da85259e..28608bd5 100644 --- a/ruoyi-common/ruoyi-common-encrypt/pom.xml +++ b/ruoyi-common/ruoyi-common-encrypt/pom.xml @@ -23,11 +23,6 @@ ruoyi-common-core - - org.mybatis.spring.boot - mybatis-spring-boot-starter - - org.bouncycastle bcprov-jdk15to18 @@ -38,6 +33,23 @@ hutool-crypto + + org.springframework + spring-webmvc + + + + com.baomidou + mybatis-plus-spring-boot3-starter + true + + + org.mybatis + mybatis-spring + + + + diff --git a/ruoyi-common/ruoyi-common-live/pom.xml b/ruoyi-common/ruoyi-common-live/pom.xml index 9b9db268..26082fcd 100644 --- a/ruoyi-common/ruoyi-common-live/pom.xml +++ b/ruoyi-common/ruoyi-common-live/pom.xml @@ -33,7 +33,7 @@ 1.13.0 2.16.0 - 5.8.24 + 5.8.35 4.1.104.Final 1.4.12 1.18.30 diff --git a/ruoyi-common/ruoyi-common-mybatis/pom.xml b/ruoyi-common/ruoyi-common-mybatis/pom.xml index 0f6505e0..138732c5 100644 --- a/ruoyi-common/ruoyi-common-mybatis/pom.xml +++ b/ruoyi-common/ruoyi-common-mybatis/pom.xml @@ -6,7 +6,6 @@ org.ruoyi ruoyi-common ${revision} - ../pom.xml 4.0.0 @@ -30,12 +29,17 @@ com.baomidou - dynamic-datasource-spring-boot-starter + dynamic-datasource-spring-boot3-starter com.baomidou - mybatis-plus-boot-starter + mybatis-plus-spring-boot3-starter + + + + com.baomidou + mybatis-plus-jsqlparser diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/com/baomidou/dynamic/datasource/processor/jakarta/DsJakartaHeaderProcessor.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/com/baomidou/dynamic/datasource/processor/jakarta/DsJakartaHeaderProcessor.java deleted file mode 100644 index f0a50a2d..00000000 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/com/baomidou/dynamic/datasource/processor/jakarta/DsJakartaHeaderProcessor.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright © 2018 organization baomidou - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.baomidou.dynamic.datasource.processor.jakarta; - -import com.baomidou.dynamic.datasource.processor.DsProcessor; -import jakarta.servlet.http.HttpServletRequest; -import org.aopalliance.intercept.MethodInvocation; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -/** - * @author TaoYu - * @since 3.6.0 - */ -public class DsJakartaHeaderProcessor extends DsProcessor { - - /** - * header prefix - */ - private static final String HEADER_PREFIX = "#header"; - - @Override - public boolean matches(String key) { - return key.startsWith(HEADER_PREFIX); - } - - @Override - public String doDetermineDatasource(MethodInvocation invocation, String key) { - HttpServletRequest request = (HttpServletRequest) ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); - return request.getHeader(key.substring(8)); - } -} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/com/baomidou/dynamic/datasource/processor/jakarta/DsJakartaSessionProcessor.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/com/baomidou/dynamic/datasource/processor/jakarta/DsJakartaSessionProcessor.java deleted file mode 100644 index 0ea8a130..00000000 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/com/baomidou/dynamic/datasource/processor/jakarta/DsJakartaSessionProcessor.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright © 2018 organization baomidou - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.baomidou.dynamic.datasource.processor.jakarta; - -import com.baomidou.dynamic.datasource.processor.DsProcessor; -import jakarta.servlet.http.HttpServletRequest; -import org.aopalliance.intercept.MethodInvocation; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - - -/** - * @author TaoYu - * @since 3.6.0 - */ -public class DsJakartaSessionProcessor extends DsProcessor { - - /** - * session开头 - */ - private static final String SESSION_PREFIX = "#session"; - - @Override - public boolean matches(String key) { - return key.startsWith(SESSION_PREFIX); - } - - @Override - public String doDetermineDatasource(MethodInvocation invocation, String key) { - HttpServletRequest request = (HttpServletRequest) ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); - return request.getSession().getAttribute(key.substring(9)).toString(); - } -} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/annotation/DataColumn.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/annotation/DataColumn.java new file mode 100644 index 00000000..706b1e8f --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/annotation/DataColumn.java @@ -0,0 +1,40 @@ +package org.ruoyi.annotation; + +import java.lang.annotation.*; + +/** + * 数据权限注解,用于标记数据权限的占位符关键字和替换值 + *

    + * 一个注解只能对应一个模板 + *

    + * + * @author Lion Li + * @version 3.5.0 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataColumn { + + /** + * 数据权限模板的占位符关键字,默认为 "deptName" + * + * @return 占位符关键字数组 + */ + String[] key() default "deptName"; + + /** + * 数据权限模板的占位符替换值,默认为 "dept_id" + * + * @return 占位符替换值数组 + */ + String[] value() default "dept_id"; + + /** + * 权限标识符 用于通过菜单权限标识符来获取数据权限 + * 拥有此标识符的角色 将不会拼接此角色的数据过滤sql + * + * @return 权限标识符 + */ + String permission() default ""; +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/annotation/DataPermission.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/annotation/DataPermission.java new file mode 100644 index 00000000..24170faa --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/annotation/DataPermission.java @@ -0,0 +1,30 @@ +package org.ruoyi.annotation; + +import java.lang.annotation.*; + +/** + * 数据权限组注解,用于标记数据权限配置数组 + * + * @author Lion Li + * @version 3.5.0 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataPermission { + + /** + * 数据权限配置数组,用于指定数据权限的占位符关键字和替换值 + * + * @return 数据权限配置数组 + */ + DataColumn[] value(); + + /** + * 权限拼接标识符(用于指定连接语句的sql符号) + * 如不填 默认 select 用 OR 其他语句用 AND + * 内容 OR 或者 AND + */ + String joinStr() default ""; + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/aspect/DataPermissionAspect.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/aspect/DataPermissionAspect.java new file mode 100644 index 00000000..f9026e91 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/aspect/DataPermissionAspect.java @@ -0,0 +1,50 @@ +package org.ruoyi.aspect; + +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.ruoyi.annotation.DataPermission; +import org.ruoyi.helper.DataPermissionHelper; + +/** + * 数据权限处理 + * + * @author Lion Li + */ +@Slf4j +@Aspect +public class DataPermissionAspect { + + /** + * 处理请求前执行 + */ + @Before(value = "@annotation(dataPermission)") + public void doBefore(JoinPoint joinPoint, DataPermission dataPermission) { + DataPermissionHelper.setPermission(dataPermission); + } + + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "@annotation(dataPermission)") + public void doAfterReturning(JoinPoint joinPoint, DataPermission dataPermission) { + DataPermissionHelper.removePermission(); + } + + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "@annotation(dataPermission)", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, DataPermission dataPermission, Exception e) { + DataPermissionHelper.removePermission(); + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/annotation/DataColumn.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/annotation/DataColumn.java deleted file mode 100644 index a3419da5..00000000 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/annotation/DataColumn.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.ruoyi.common.mybatis.annotation; - -import java.lang.annotation.*; - -/** - * 数据权限 - * - * 一个注解只能对应一个模板 - * - * @author Lion Li - * @version 3.5.0 - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface DataColumn { - - /** - * 占位符关键字 - */ - String[] key() default "deptName"; - - /** - * 占位符替换值 - */ - String[] value() default "dept_id"; - -} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/annotation/DataPermission.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/annotation/DataPermission.java deleted file mode 100644 index 037eb81a..00000000 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/annotation/DataPermission.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.ruoyi.common.mybatis.annotation; - -import java.lang.annotation.*; - -/** - * 数据权限组 - * - * @author Lion Li - * @version 3.5.0 - */ -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface DataPermission { - - DataColumn[] value(); - -} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/core/mapper/BaseMapperPlus.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/core/mapper/BaseMapperPlus.java deleted file mode 100644 index b14c14ef..00000000 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/core/mapper/BaseMapperPlus.java +++ /dev/null @@ -1,198 +0,0 @@ -package org.ruoyi.common.mybatis.core.mapper; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; -import com.baomidou.mybatisplus.core.conditions.Wrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.core.toolkit.ReflectionKit; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.toolkit.Db; -import org.apache.ibatis.logging.Log; -import org.apache.ibatis.logging.LogFactory; -import org.ruoyi.common.core.utils.MapstructUtils; - -import java.io.Serializable; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Function; -import java.util.stream.Collectors; - -/** - * 自定义 Mapper 接口, 实现 自定义扩展 - * - * @param table 泛型 - * @param vo 泛型 - * @author Lion Li - * @since 2021-05-13 - */ -@SuppressWarnings("unchecked") -public interface BaseMapperPlus extends BaseMapper { - - Log log = LogFactory.getLog(BaseMapperPlus.class); - - default Class currentVoClass() { - return (Class) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 1); - } - - default Class currentModelClass() { - return (Class) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 0); - } - - default List selectList() { - return this.selectList(new QueryWrapper<>()); - } - - /** - * 批量插入 - */ - default boolean insertBatch(Collection entityList) { - return Db.saveBatch(entityList); - } - - /** - * 批量更新 - */ - default boolean updateBatchById(Collection entityList) { - return Db.updateBatchById(entityList); - } - - /** - * 批量插入或更新 - */ - default boolean insertOrUpdateBatch(Collection entityList) { - return Db.saveOrUpdateBatch(entityList); - } - - /** - * 批量插入(包含限制条数) - */ - default boolean insertBatch(Collection entityList, int batchSize) { - return Db.saveBatch(entityList, batchSize); - } - - /** - * 批量更新(包含限制条数) - */ - default boolean updateBatchById(Collection entityList, int batchSize) { - return Db.updateBatchById(entityList, batchSize); - } - - /** - * 批量插入或更新(包含限制条数) - */ - default boolean insertOrUpdateBatch(Collection entityList, int batchSize) { - return Db.saveOrUpdateBatch(entityList, batchSize); - } - - /** - * 插入或更新(包含限制条数) - */ - default boolean insertOrUpdate(T entity) { - return Db.saveOrUpdate(entity); - } - - default V selectVoById(Serializable id) { - return selectVoById(id, this.currentVoClass()); - } - - /** - * 根据 ID 查询 - */ - default C selectVoById(Serializable id, Class voClass) { - T obj = this.selectById(id); - if (ObjectUtil.isNull(obj)) { - return null; - } - return MapstructUtils.convert(obj, voClass); - } - - default List selectVoBatchIds(Collection idList) { - return selectVoBatchIds(idList, this.currentVoClass()); - } - - /** - * 查询(根据ID 批量查询) - */ - default List selectVoBatchIds(Collection idList, Class voClass) { - List list = this.selectBatchIds(idList); - if (CollUtil.isEmpty(list)) { - return CollUtil.newArrayList(); - } - return MapstructUtils.convert(list, voClass); - } - - default List selectVoByMap(Map map) { - return selectVoByMap(map, this.currentVoClass()); - } - - /** - * 查询(根据 columnMap 条件) - */ - default List selectVoByMap(Map map, Class voClass) { - List list = this.selectByMap(map); - if (CollUtil.isEmpty(list)) { - return CollUtil.newArrayList(); - } - return MapstructUtils.convert(list, voClass); - } - - default V selectVoOne(Wrapper wrapper) { - return selectVoOne(wrapper, this.currentVoClass()); - } - - /** - * 根据 entity 条件,查询一条记录 - */ - default C selectVoOne(Wrapper wrapper, Class voClass) { - T obj = this.selectOne(wrapper); - if (ObjectUtil.isNull(obj)) { - return null; - } - return MapstructUtils.convert(obj, voClass); - } - - default List selectVoList() { - return selectVoList(new QueryWrapper<>(), this.currentVoClass()); - } - - default List selectVoList(Wrapper wrapper) { - return selectVoList(wrapper, this.currentVoClass()); - } - - /** - * 根据 entity 条件,查询全部记录 - */ - default List selectVoList(Wrapper wrapper, Class voClass) { - List list = this.selectList(wrapper); - if (CollUtil.isEmpty(list)) { - return CollUtil.newArrayList(); - } - return MapstructUtils.convert(list, voClass); - } - - default

    > P selectVoPage(IPage page, Wrapper wrapper) { - return selectVoPage(page, wrapper, this.currentVoClass()); - } - - /** - * 分页查询VO - */ - default > P selectVoPage(IPage page, Wrapper wrapper, Class voClass) { - IPage pageData = this.selectPage(page, wrapper); - IPage voPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal()); - if (CollUtil.isEmpty(pageData.getRecords())) { - return (P) voPage; - } - voPage.setRecords(MapstructUtils.convert(pageData.getRecords(), voClass)); - return (P) voPage; - } - - default List selectObjs(Wrapper wrapper, Function mapper) { - return this.selectObjs(wrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList()); - } - -} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/enums/DataScopeType.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/enums/DataScopeType.java deleted file mode 100644 index 65362ad0..00000000 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/enums/DataScopeType.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.ruoyi.common.mybatis.enums; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import org.ruoyi.common.core.utils.StringUtils; -import org.ruoyi.common.mybatis.helper.DataPermissionHelper; - -/** - * 数据权限类型 - *

    - * 语法支持 spel 模板表达式 - *

    - * 内置数据 user 当前用户 内容参考 LoginUser - * 如需扩展数据 可使用 {@link DataPermissionHelper} 操作 - * 内置服务 sdss 系统数据权限服务 内容参考 SysDataScopeService - * 如需扩展更多自定义服务 可以参考 sdss 自行编写 - * - * @author Lion Li - * @version 3.5.0 - */ -@Getter -@AllArgsConstructor -public enum DataScopeType { - - /** - * 全部数据权限 - */ - ALL("1", "", ""), - - /** - * 自定数据权限 - */ - CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", ""), - - /** - * 部门数据权限 - */ - DEPT("3", " #{#deptName} = #{#user.deptId} ", ""), - - /** - * 部门及以下数据权限 - */ - DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", ""), - - /** - * 仅本人数据权限 - */ - SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 "); - - private final String code; - - /** - * 语法 采用 spel 模板表达式 - */ - private final String sqlTemplate; - - /** - * 不满足 sqlTemplate 则填充 - */ - private final String elseSql; - - public static DataScopeType findCode(String code) { - if (StringUtils.isBlank(code)) { - return null; - } - for (DataScopeType type : values()) { - if (type.getCode().equals(code)) { - return type; - } - } - return null; - } -} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/handler/InjectionMetaObjectHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/handler/InjectionMetaObjectHandler.java deleted file mode 100644 index dfa24f0b..00000000 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/handler/InjectionMetaObjectHandler.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.ruoyi.common.mybatis.handler; - -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.http.HttpStatus; -import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; -import lombok.extern.slf4j.Slf4j; -import org.apache.ibatis.reflection.MetaObject; -import org.ruoyi.common.core.domain.model.LoginUser; -import org.ruoyi.common.core.exception.ServiceException; -import org.ruoyi.common.mybatis.core.domain.BaseEntity; -import org.ruoyi.common.satoken.utils.LoginHelper; - -import java.util.Date; - -/** - * MP注入处理器 - * - * @author Lion Li - * @date 2021/4/25 - */ -@Slf4j -public class InjectionMetaObjectHandler implements MetaObjectHandler { - - @Override - public void insertFill(MetaObject metaObject) { - try { - if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) { - Date current = ObjectUtil.isNotNull(baseEntity.getCreateTime()) - ? baseEntity.getCreateTime() : new Date(); - baseEntity.setCreateTime(current); - baseEntity.setUpdateTime(current); - LoginUser loginUser = getLoginUser(); - if (ObjectUtil.isNotNull(loginUser)) { - Long userId = ObjectUtil.isNotNull(baseEntity.getCreateBy()) - ? baseEntity.getCreateBy() : loginUser.getUserId(); - // 当前已登录 且 创建人为空 则填充 - baseEntity.setCreateBy(userId); - // 当前已登录 且 更新人为空 则填充 - baseEntity.setUpdateBy(userId); - baseEntity.setCreateDept(ObjectUtil.isNotNull(baseEntity.getCreateDept()) - ? baseEntity.getCreateDept() : loginUser.getDeptId()); - } - } - } catch (Exception e) { - throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); - } - } - - @Override - public void updateFill(MetaObject metaObject) { - try { - if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) { - Date current = new Date(); - // 更新时间填充(不管为不为空) - baseEntity.setUpdateTime(current); - LoginUser loginUser = getLoginUser(); - // 当前已登录 更新人填充(不管为不为空) - if (ObjectUtil.isNotNull(loginUser)) { - baseEntity.setUpdateBy(loginUser.getUserId()); - } - } - } catch (Exception e) { - throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); - } - } - - /** - * 获取登录用户名 - */ - private LoginUser getLoginUser() { - LoginUser loginUser; - try { - loginUser = LoginHelper.getLoginUser(); - } catch (Exception e) { - log.warn("自动注入警告 => 用户未登录"); - return null; - } - return loginUser; - } - -} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/handler/PlusDataPermissionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/handler/PlusDataPermissionHandler.java deleted file mode 100644 index f928f42a..00000000 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/handler/PlusDataPermissionHandler.java +++ /dev/null @@ -1,198 +0,0 @@ -package org.ruoyi.common.mybatis.handler; - -import cn.hutool.core.annotation.AnnotationUtil; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.ConcurrentHashSet; -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.ClassUtil; -import cn.hutool.core.util.ObjectUtil; -import lombok.extern.slf4j.Slf4j; -import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.expression.Expression; -import net.sf.jsqlparser.expression.Parenthesis; -import net.sf.jsqlparser.expression.operators.conditional.AndExpression; -import net.sf.jsqlparser.parser.CCJSqlParserUtil; -import org.ruoyi.common.core.domain.dto.RoleDTO; -import org.ruoyi.common.core.domain.model.LoginUser; -import org.ruoyi.common.core.exception.ServiceException; -import org.ruoyi.common.core.utils.SpringUtils; -import org.ruoyi.common.core.utils.StreamUtils; -import org.ruoyi.common.core.utils.StringUtils; -import org.ruoyi.common.mybatis.annotation.DataColumn; -import org.ruoyi.common.mybatis.annotation.DataPermission; -import org.ruoyi.common.mybatis.enums.DataScopeType; -import org.ruoyi.common.mybatis.helper.DataPermissionHelper; -import org.ruoyi.common.satoken.utils.LoginHelper; -import org.springframework.context.expression.BeanFactoryResolver; -import org.springframework.expression.BeanResolver; -import org.springframework.expression.ExpressionParser; -import org.springframework.expression.ParserContext; -import org.springframework.expression.common.TemplateParserContext; -import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.expression.spel.support.StandardEvaluationContext; - -import java.lang.reflect.Method; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; - -/** - * 数据权限过滤 - * - * @author Lion Li - * @version 3.5.0 - */ -@Slf4j -public class PlusDataPermissionHandler { - - /** - * 方法或类(名称) 与 注解的映射关系缓存 - */ - private final Map dataPermissionCacheMap = new ConcurrentHashMap<>(); - - /** - * 无效注解方法缓存用于快速返回 - */ - private final Set invalidCacheSet = new ConcurrentHashSet<>(); - - /** - * spel 解析器 - */ - private final ExpressionParser parser = new SpelExpressionParser(); - private final ParserContext parserContext = new TemplateParserContext(); - /** - * bean解析器 用于处理 spel 表达式中对 bean 的调用 - */ - private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory()); - - - public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) { - DataColumn[] dataColumns = findAnnotation(mappedStatementId); - if (ArrayUtil.isEmpty(dataColumns)) { - invalidCacheSet.add(mappedStatementId); - return where; - } - LoginUser currentUser = DataPermissionHelper.getVariable("user"); - if (ObjectUtil.isNull(currentUser)) { - currentUser = LoginHelper.getLoginUser(); - DataPermissionHelper.setVariable("user", currentUser); - } - // 如果是超级管理员或租户管理员,则不过滤数据 - if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) { - return where; - } - String dataFilterSql = buildDataFilter(dataColumns, isSelect); - if (StringUtils.isBlank(dataFilterSql)) { - return where; - } - try { - Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql); - // 数据权限使用单独的括号 防止与其他条件冲突 - Parenthesis parenthesis = new Parenthesis(expression); - if (ObjectUtil.isNotNull(where)) { - return new AndExpression(where, parenthesis); - } else { - return parenthesis; - } - } catch (JSQLParserException e) { - throw new ServiceException("数据权限解析异常 => " + e.getMessage()); - } - } - - /** - * 构造数据过滤sql - */ - private String buildDataFilter(DataColumn[] dataColumns, boolean isSelect) { - // 更新或删除需满足所有条件 - String joinStr = isSelect ? " OR " : " AND "; - LoginUser user = DataPermissionHelper.getVariable("user"); - StandardEvaluationContext context = new StandardEvaluationContext(); - context.setBeanResolver(beanResolver); - DataPermissionHelper.getContext().forEach(context::setVariable); - Set conditions = new HashSet<>(); - for (RoleDTO role : user.getRoles()) { - user.setRoleId(role.getRoleId()); - // 获取角色权限泛型 - DataScopeType type = DataScopeType.findCode(role.getDataScope()); - if (ObjectUtil.isNull(type)) { - throw new ServiceException("角色数据范围异常 => " + role.getDataScope()); - } - // 全部数据权限直接返回 - if (type == DataScopeType.ALL) { - return ""; - } - boolean isSuccess = false; - for (DataColumn dataColumn : dataColumns) { - if (dataColumn.key().length != dataColumn.value().length) { - throw new ServiceException("角色数据范围异常 => key与value长度不匹配"); - } - // 不包含 key 变量 则不处理 - if (!StringUtils.containsAny(type.getSqlTemplate(), - Arrays.stream(dataColumn.key()).map(key -> "#" + key).toArray(String[]::new) - )) { - continue; - } - // 设置注解变量 key 为表达式变量 value 为变量值 - for (int i = 0; i < dataColumn.key().length; i++) { - context.setVariable(dataColumn.key()[i], dataColumn.value()[i]); - } - - // 解析sql模板并填充 - String sql = parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class); - conditions.add(joinStr + sql); - isSuccess = true; - } - // 未处理成功则填充兜底方案 - if (!isSuccess && StringUtils.isNotBlank(type.getElseSql())) { - conditions.add(joinStr + type.getElseSql()); - } - } - - if (CollUtil.isNotEmpty(conditions)) { - String sql = StreamUtils.join(conditions, Function.identity(), ""); - return sql.substring(joinStr.length()); - } - return ""; - } - - private DataColumn[] findAnnotation(String mappedStatementId) { - StringBuilder sb = new StringBuilder(mappedStatementId); - int index = sb.lastIndexOf("."); - String clazzName = sb.substring(0, index); - String methodName = sb.substring(index + 1, sb.length()); - Class clazz = ClassUtil.loadClass(clazzName); - List methods = Arrays.stream(ClassUtil.getDeclaredMethods(clazz)) - .filter(method -> method.getName().equals(methodName)).toList(); - DataPermission dataPermission; - // 获取方法注解 - for (Method method : methods) { - dataPermission = dataPermissionCacheMap.get(mappedStatementId); - if (ObjectUtil.isNotNull(dataPermission)) { - return dataPermission.value(); - } - if (AnnotationUtil.hasAnnotation(method, DataPermission.class)) { - dataPermission = AnnotationUtil.getAnnotation(method, DataPermission.class); - dataPermissionCacheMap.put(mappedStatementId, dataPermission); - return dataPermission.value(); - } - } - dataPermission = dataPermissionCacheMap.get(clazz.getName()); - if (ObjectUtil.isNotNull(dataPermission)) { - return dataPermission.value(); - } - // 获取类注解 - if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) { - dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class); - dataPermissionCacheMap.put(clazz.getName(), dataPermission); - return dataPermission.value(); - } - return null; - } - - /** - * 是否为无效方法 无数据权限 - */ - public boolean isInvalid(String mappedStatementId) { - return invalidCacheSet.contains(mappedStatementId); - } -} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/helper/DataPermissionHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/helper/DataPermissionHelper.java deleted file mode 100644 index 8e3de7a3..00000000 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/helper/DataPermissionHelper.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.ruoyi.common.mybatis.helper; - -import cn.dev33.satoken.context.SaHolder; -import cn.dev33.satoken.context.model.SaStorage; -import cn.hutool.core.util.ObjectUtil; -import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy; -import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Supplier; - -/** - * 数据权限助手 - * - * @author Lion Li - * @version 3.5.0 - */ -@NoArgsConstructor(access = AccessLevel.PRIVATE) -@SuppressWarnings("unchecked cast") -public class DataPermissionHelper { - - private static final String DATA_PERMISSION_KEY = "data:permission"; - - public static T getVariable(String key) { - Map context = getContext(); - return (T) context.get(key); - } - - - public static void setVariable(String key, Object value) { - Map context = getContext(); - context.put(key, value); - } - - public static Map getContext() { - SaStorage saStorage = SaHolder.getStorage(); - Object attribute = saStorage.get(DATA_PERMISSION_KEY); - if (ObjectUtil.isNull(attribute)) { - saStorage.set(DATA_PERMISSION_KEY, new HashMap<>()); - attribute = saStorage.get(DATA_PERMISSION_KEY); - } - if (attribute instanceof Map map) { - return map; - } - throw new NullPointerException("data permission context type exception"); - } - - /** - * 开启忽略数据权限(开启后需手动调用 {@link #disableIgnore()} 关闭) - */ - public static void enableIgnore() { - InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build()); - } - - /** - * 关闭忽略数据权限 - */ - public static void disableIgnore() { - InterceptorIgnoreHelper.clearIgnoreStrategy(); - } - - /** - * 在忽略数据权限中执行 - * - * @param handle 处理执行方法 - */ - public static void ignore(Runnable handle) { - enableIgnore(); - try { - handle.run(); - } finally { - disableIgnore(); - } - } - - /** - * 在忽略数据权限中执行 - * - * @param handle 处理执行方法 - */ - public static T ignore(Supplier handle) { - enableIgnore(); - try { - return handle.get(); - } finally { - disableIgnore(); - } - } - -} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/interceptor/PlusDataPermissionInterceptor.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/interceptor/PlusDataPermissionInterceptor.java deleted file mode 100644 index 98895d0a..00000000 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/interceptor/PlusDataPermissionInterceptor.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.ruoyi.common.mybatis.interceptor; - -import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; -import com.baomidou.mybatisplus.core.toolkit.PluginUtils; -import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport; -import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; -import net.sf.jsqlparser.expression.Expression; -import net.sf.jsqlparser.statement.delete.Delete; -import net.sf.jsqlparser.statement.select.PlainSelect; -import net.sf.jsqlparser.statement.select.Select; -import net.sf.jsqlparser.statement.select.SelectBody; -import net.sf.jsqlparser.statement.select.SetOperationList; -import net.sf.jsqlparser.statement.update.Update; -import org.apache.ibatis.executor.Executor; -import org.apache.ibatis.executor.statement.StatementHandler; -import org.apache.ibatis.mapping.BoundSql; -import org.apache.ibatis.mapping.MappedStatement; -import org.apache.ibatis.mapping.SqlCommandType; -import org.apache.ibatis.session.ResultHandler; -import org.apache.ibatis.session.RowBounds; -import org.ruoyi.common.mybatis.handler.PlusDataPermissionHandler; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.List; - -/** - * 数据权限拦截器 - * - * @author Lion Li - * @version 3.5.0 - */ -public class PlusDataPermissionInterceptor extends JsqlParserSupport implements InnerInterceptor { - - private final PlusDataPermissionHandler dataPermissionHandler = new PlusDataPermissionHandler(); - - @Override - public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { - // 检查忽略注解 - if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) { - return; - } - // 检查是否无效 无数据权限注解 - if (dataPermissionHandler.isInvalid(ms.getId())) { - return; - } - // 解析 sql 分配对应方法 - PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql); - mpBs.sql(parserSingle(mpBs.sql(), ms.getId())); - } - - @Override - public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { - PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); - MappedStatement ms = mpSh.mappedStatement(); - SqlCommandType sct = ms.getSqlCommandType(); - if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) { - if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) { - return; - } - PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); - mpBs.sql(parserMulti(mpBs.sql(), ms.getId())); - } - } - - @Override - protected void processSelect(Select select, int index, String sql, Object obj) { - SelectBody selectBody = select.getSelectBody(); - if (selectBody instanceof PlainSelect plainSelect) { - this.setWhere(plainSelect, (String) obj); - } else if (selectBody instanceof SetOperationList setOperationList) { - List selectBodyList = setOperationList.getSelects(); - selectBodyList.forEach(s -> this.setWhere((PlainSelect) s, (String) obj)); - } - } - - @Override - protected void processUpdate(Update update, int index, String sql, Object obj) { - Expression sqlSegment = dataPermissionHandler.getSqlSegment(update.getWhere(), (String) obj, false); - if (null != sqlSegment) { - update.setWhere(sqlSegment); - } - } - - @Override - protected void processDelete(Delete delete, int index, String sql, Object obj) { - Expression sqlSegment = dataPermissionHandler.getSqlSegment(delete.getWhere(), (String) obj, false); - if (null != sqlSegment) { - delete.setWhere(sqlSegment); - } - } - - /** - * 设置 where 条件 - * - * @param plainSelect 查询对象 - * @param mappedStatementId 执行方法id - */ - protected void setWhere(PlainSelect plainSelect, String mappedStatementId) { - Expression sqlSegment = dataPermissionHandler.getSqlSegment(plainSelect.getWhere(), mappedStatementId, true); - if (null != sqlSegment) { - plainSelect.setWhere(sqlSegment); - } - } - -} - diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/jakarta/DsJakartaHeaderProcessor.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/jakarta/DsJakartaHeaderProcessor.java deleted file mode 100644 index fd67e07c..00000000 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/jakarta/DsJakartaHeaderProcessor.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright © 2018 organization baomidou - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.ruoyi.common.mybatis.jakarta; - -import com.baomidou.dynamic.datasource.processor.DsProcessor; -import jakarta.servlet.http.HttpServletRequest; -import org.aopalliance.intercept.MethodInvocation; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -/** - * @author TaoYu - * @since 3.6.0 - */ -public class DsJakartaHeaderProcessor extends DsProcessor { - - /** - * header prefix - */ - private static final String HEADER_PREFIX = "#header"; - - @Override - public boolean matches(String key) { - return key.startsWith(HEADER_PREFIX); - } - - @Override - public String doDetermineDatasource(MethodInvocation invocation, String key) { - HttpServletRequest request = (HttpServletRequest) ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); - return request.getHeader(key.substring(8)); - } -} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/jakarta/DsJakartaSessionProcessor.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/jakarta/DsJakartaSessionProcessor.java deleted file mode 100644 index f055b463..00000000 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/jakarta/DsJakartaSessionProcessor.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright © 2018 organization baomidou - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.ruoyi.common.mybatis.jakarta; - -import com.baomidou.dynamic.datasource.processor.DsProcessor; -import jakarta.servlet.http.HttpServletRequest; -import org.aopalliance.intercept.MethodInvocation; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - - -/** - * @author TaoYu - * @since 3.6.0 - */ -public class DsJakartaSessionProcessor extends DsProcessor { - - /** - * session开头 - */ - private static final String SESSION_PREFIX = "#session"; - - @Override - public boolean matches(String key) { - return key.startsWith(SESSION_PREFIX); - } - - @Override - public String doDetermineDatasource(MethodInvocation invocation, String key) { - HttpServletRequest request = (HttpServletRequest) ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); - return request.getSession().getAttribute(key.substring(9)).toString(); - } -} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/config/MybatisPlusConfig.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/config/MybatisPlusConfig.java similarity index 66% rename from ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/config/MybatisPlusConfig.java rename to ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/config/MybatisPlusConfig.java index 7f28b1f6..f5942b2e 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/config/MybatisPlusConfig.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/config/MybatisPlusConfig.java @@ -1,17 +1,25 @@ -package org.ruoyi.common.mybatis.config; +package org.ruoyi.config; import cn.hutool.core.net.NetUtil; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.baomidou.mybatisplus.core.handlers.PostInitTableInfoHandler; import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator; import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; -import org.ruoyi.common.mybatis.handler.InjectionMetaObjectHandler; -import org.ruoyi.common.mybatis.interceptor.PlusDataPermissionInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import org.ruoyi.aspect.DataPermissionAspect; +import org.ruoyi.common.core.factory.YmlPropertySourceFactory; +import org.ruoyi.common.core.utils.SpringUtils; +import org.ruoyi.handler.InjectionMetaObjectHandler; +import org.ruoyi.handler.MybatisExceptionHandler; +import org.ruoyi.handler.PlusPostInitTableInfoHandler; +import org.ruoyi.interceptor.PlusDataPermissionInterceptor; import org.mybatis.spring.annotation.MapperScan; -import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.beans.BeansException; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.PropertySource; import org.springframework.transaction.annotation.EnableTransactionManagement; /** @@ -20,13 +28,19 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; * @author Lion Li */ @EnableTransactionManagement(proxyTargetClass = true) -@AutoConfiguration @MapperScan("${mybatis-plus.mapperPackage}") +@PropertySource(value = "classpath:common-mybatis.yml", factory = YmlPropertySourceFactory.class) public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + // 多租户插件 必须放到第一位 + try { + TenantLineInnerInterceptor tenant = SpringUtils.getBean(TenantLineInnerInterceptor.class); + interceptor.addInnerInterceptor(tenant); + } catch (BeansException ignore) { + } // 数据权限处理 interceptor.addInnerInterceptor(dataPermissionInterceptor()); // 分页插件 @@ -40,7 +54,15 @@ public class MybatisPlusConfig { * 数据权限拦截器 */ public PlusDataPermissionInterceptor dataPermissionInterceptor() { - return new PlusDataPermissionInterceptor(); + return new PlusDataPermissionInterceptor(SpringUtils.getProperty("mybatis-plus.mapperPackage")); + } + + /** + * 数据权限切面处理器 + */ + @Bean + public DataPermissionAspect dataPermissionAspect() { + return new DataPermissionAspect(); } /** @@ -48,8 +70,6 @@ public class MybatisPlusConfig { */ public PaginationInnerInterceptor paginationInnerInterceptor() { PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(); - // 设置最大单页限制数量,默认 500 条,-1 不受限制 - paginationInnerInterceptor.setMaxLimit(-1L); // 分页合理化 paginationInnerInterceptor.setOverflow(true); return paginationInnerInterceptor; @@ -79,6 +99,22 @@ public class MybatisPlusConfig { return new DefaultIdentifierGenerator(NetUtil.getLocalhost()); } + /** + * 异常处理器 + */ + @Bean + public MybatisExceptionHandler mybatisExceptionHandler() { + return new MybatisExceptionHandler(); + } + + /** + * 初始化表对象处理器 + */ + @Bean + public PostInitTableInfoHandler postInitTableInfoHandler() { + return new PlusPostInitTableInfoHandler(); + } + /** * PaginationInnerInterceptor 分页插件,自动识别数据库类型 * https://baomidou.com/pages/97710a/ diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/core/domain/BaseEntity.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/domain/BaseEntity.java similarity index 96% rename from ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/core/domain/BaseEntity.java rename to ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/domain/BaseEntity.java index bfc43c54..5e362d60 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/core/domain/BaseEntity.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/domain/BaseEntity.java @@ -1,4 +1,4 @@ -package org.ruoyi.common.mybatis.core.domain; +package org.ruoyi.core.domain; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; @@ -17,7 +17,6 @@ import java.util.Map; * * @author Lion Li */ - @Data public class BaseEntity implements Serializable { diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/mapper/BaseMapperPlus.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/mapper/BaseMapperPlus.java new file mode 100644 index 00000000..097c7210 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/mapper/BaseMapperPlus.java @@ -0,0 +1,335 @@ +package org.ruoyi.core.mapper; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.toolkit.Db; +import org.apache.ibatis.logging.Log; +import org.apache.ibatis.logging.LogFactory; +import org.ruoyi.common.core.utils.MapstructUtils; +import org.ruoyi.common.core.utils.StreamUtils; + + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** + * 自定义 Mapper 接口, 实现 自定义扩展 + * + * @param table 泛型 + * @param vo 泛型 + * @author Lion Li + * @since 2021-05-13 + */ +@SuppressWarnings("unchecked") +public interface BaseMapperPlus extends BaseMapper { + + Log log = LogFactory.getLog(BaseMapperPlus.class); + + /** + * 获取当前实例对象关联的泛型类型 V 的 Class 对象 + * + * @return 返回当前实例对象关联的泛型类型 V 的 Class 对象 + */ + default Class currentVoClass() { + return (Class) GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class)[1]; + } + + /** + * 获取当前实例对象关联的泛型类型 T 的 Class 对象 + * + * @return 返回当前实例对象关联的泛型类型 T 的 Class 对象 + */ + default Class currentModelClass() { + return (Class) GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class)[0]; + } + + /** + * 使用默认的查询条件查询并返回结果列表 + * + * @return 返回查询结果的列表 + */ + default List selectList() { + return this.selectList(new QueryWrapper<>()); + } + + /** + * 批量插入实体对象集合 + * + * @param entityList 实体对象集合 + * @return 插入操作是否成功的布尔值 + */ + default boolean insertBatch(Collection entityList) { + return Db.saveBatch(entityList); + } + + /** + * 批量根据ID更新实体对象集合 + * + * @param entityList 实体对象集合 + * @return 更新操作是否成功的布尔值 + */ + default boolean updateBatchById(Collection entityList) { + return Db.updateBatchById(entityList); + } + + /** + * 批量插入或更新实体对象集合 + * + * @param entityList 实体对象集合 + * @return 插入或更新操作是否成功的布尔值 + */ + default boolean insertOrUpdateBatch(Collection entityList) { + return Db.saveOrUpdateBatch(entityList); + } + + /** + * 批量插入实体对象集合并指定批处理大小 + * + * @param entityList 实体对象集合 + * @param batchSize 批处理大小 + * @return 插入操作是否成功的布尔值 + */ + default boolean insertBatch(Collection entityList, int batchSize) { + return Db.saveBatch(entityList, batchSize); + } + + /** + * 批量根据ID更新实体对象集合并指定批处理大小 + * + * @param entityList 实体对象集合 + * @param batchSize 批处理大小 + * @return 更新操作是否成功的布尔值 + */ + default boolean updateBatchById(Collection entityList, int batchSize) { + return Db.updateBatchById(entityList, batchSize); + } + + /** + * 批量插入或更新实体对象集合并指定批处理大小 + * + * @param entityList 实体对象集合 + * @param batchSize 批处理大小 + * @return 插入或更新操作是否成功的布尔值 + */ + default boolean insertOrUpdateBatch(Collection entityList, int batchSize) { + return Db.saveOrUpdateBatch(entityList, batchSize); + } + + /** + * 根据ID查询单个VO对象 + * + * @param id 主键ID + * @return 查询到的单个VO对象 + */ + default V selectVoById(Serializable id) { + return selectVoById(id, this.currentVoClass()); + } + + /** + * 根据ID查询单个VO对象并将其转换为指定的VO类 + * + * @param id 主键ID + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @return 查询到的单个VO对象,经过转换为指定的VO类后返回 + */ + default C selectVoById(Serializable id, Class voClass) { + T obj = this.selectById(id); + if (ObjectUtil.isNull(obj)) { + return null; + } + return MapstructUtils.convert(obj, voClass); + } + + /** + * 根据ID集合批量查询VO对象列表 + * + * @param idList 主键ID集合 + * @return 查询到的VO对象列表 + */ + default List selectVoByIds(Collection idList) { + return selectVoByIds(idList, this.currentVoClass()); + } + + /** + * 根据ID集合批量查询实体对象列表,并将其转换为指定的VO对象列表 + * + * @param idList 主键ID集合 + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @return 查询到的VO对象列表,经过转换为指定的VO类后返回 + */ + default List selectVoByIds(Collection idList, Class voClass) { + List list = this.selectByIds(idList); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return MapstructUtils.convert(list, voClass); + } + + /** + * 根据查询条件Map查询VO对象列表 + * + * @param map 查询条件Map + * @return 查询到的VO对象列表 + */ + default List selectVoByMap(Map map) { + return selectVoByMap(map, this.currentVoClass()); + } + + /** + * 根据查询条件Map查询实体对象列表,并将其转换为指定的VO对象列表 + * + * @param map 查询条件Map + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @return 查询到的VO对象列表,经过转换为指定的VO类后返回 + */ + default List selectVoByMap(Map map, Class voClass) { + List list = this.selectByMap(map); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return MapstructUtils.convert(list, voClass); + } + + /** + * 根据条件查询单个VO对象 + * + * @param wrapper 查询条件Wrapper + * @return 查询到的单个VO对象 + */ + default V selectVoOne(Wrapper wrapper) { + return selectVoOne(wrapper, this.currentVoClass()); + } + + /** + * 根据条件查询单个VO对象,并根据需要决定是否抛出异常 + * + * @param wrapper 查询条件Wrapper + * @param throwEx 是否抛出异常的标志 + * @return 查询到的单个VO对象 + */ + default V selectVoOne(Wrapper wrapper, boolean throwEx) { + return selectVoOne(wrapper, this.currentVoClass(), throwEx); + } + + /** + * 根据条件查询单个VO对象,并指定返回的VO对象的类型 + * + * @param wrapper 查询条件Wrapper + * @param voClass 返回的VO对象的Class对象 + * @param 返回的VO对象的类型 + * @return 查询到的单个VO对象,经过类型转换为指定的VO类后返回 + */ + default C selectVoOne(Wrapper wrapper, Class voClass) { + return selectVoOne(wrapper, voClass, true); + } + + /** + * 根据条件查询单个实体对象,并将其转换为指定的VO对象 + * + * @param wrapper 查询条件Wrapper + * @param voClass 要转换的VO类的Class对象 + * @param throwEx 是否抛出异常的标志 + * @param VO类的类型 + * @return 查询到的单个VO对象,经过转换为指定的VO类后返回 + */ + default C selectVoOne(Wrapper wrapper, Class voClass, boolean throwEx) { + T obj = this.selectOne(wrapper, throwEx); + if (ObjectUtil.isNull(obj)) { + return null; + } + return MapstructUtils.convert(obj, voClass); + } + + /** + * 查询所有VO对象列表 + * + * @return 查询到的VO对象列表 + */ + default List selectVoList() { + return selectVoList(new QueryWrapper<>(), this.currentVoClass()); + } + + /** + * 根据条件查询VO对象列表 + * + * @param wrapper 查询条件Wrapper + * @return 查询到的VO对象列表 + */ + default List selectVoList(Wrapper wrapper) { + return selectVoList(wrapper, this.currentVoClass()); + } + + /** + * 根据条件查询实体对象列表,并将其转换为指定的VO对象列表 + * + * @param wrapper 查询条件Wrapper + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @return 查询到的VO对象列表,经过转换为指定的VO类后返回 + */ + default List selectVoList(Wrapper wrapper, Class voClass) { + List list = this.selectList(wrapper); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return MapstructUtils.convert(list, voClass); + } + + /** + * 根据条件分页查询VO对象列表 + * + * @param page 分页信息 + * @param wrapper 查询条件Wrapper + * @return 查询到的VO对象分页列表 + */ + default

    > P selectVoPage(IPage page, Wrapper wrapper) { + return selectVoPage(page, wrapper, this.currentVoClass()); + } + + /** + * 根据条件分页查询实体对象列表,并将其转换为指定的VO对象分页列表 + * + * @param page 分页信息 + * @param wrapper 查询条件Wrapper + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @param

    VO对象分页列表的类型 + * @return 查询到的VO对象分页列表,经过转换为指定的VO类后返回 + */ + default > P selectVoPage(IPage page, Wrapper wrapper, Class voClass) { + // 根据条件分页查询实体对象列表 + List list = this.selectList(page, wrapper); + // 创建一个新的VO对象分页列表,并设置分页信息 + IPage voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal()); + if (CollUtil.isEmpty(list)) { + return (P) voPage; + } + voPage.setRecords(MapstructUtils.convert(list, voClass)); + return (P) voPage; + } + + /** + * 根据条件查询符合条件的对象,并将其转换为指定类型的对象列表 + * + * @param wrapper 查询条件Wrapper + * @param mapper 转换函数,用于将查询到的对象转换为指定类型的对象 + * @param 要转换的对象的类型 + * @return 查询到的符合条件的对象列表,经过转换为指定类型的对象后返回 + */ + default List selectObjs(Wrapper wrapper, Function mapper) { + return StreamUtils.toList(this.selectObjs(wrapper), mapper); + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/core/page/PageQuery.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/page/PageQuery.java similarity index 90% rename from ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/core/page/PageQuery.java rename to ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/page/PageQuery.java index 33e0190d..a388cb4a 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/core/page/PageQuery.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/page/PageQuery.java @@ -1,9 +1,10 @@ -package org.ruoyi.common.mybatis.core.page; +package org.ruoyi.core.page; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.metadata.OrderItem; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import org.ruoyi.common.core.exception.ServiceException; import org.ruoyi.common.core.utils.StringUtils; @@ -19,7 +20,6 @@ import java.util.List; * * @author Lion Li */ - @Data public class PageQuery implements Serializable { @@ -56,6 +56,9 @@ public class PageQuery implements Serializable { */ public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE; + /** + * 构建分页对象 + */ public Page build() { Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM); Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE); @@ -111,4 +114,14 @@ public class PageQuery implements Serializable { return list; } + @JsonIgnore + public Integer getFirstNum() { + return (pageNum - 1) * pageSize; + } + + public PageQuery(Integer pageSize, Integer pageNum) { + this.pageSize = pageSize; + this.pageNum = pageNum; + } + } diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/core/page/TableDataInfo.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/page/TableDataInfo.java similarity index 85% rename from ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/core/page/TableDataInfo.java rename to ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/page/TableDataInfo.java index b4f7cd70..eb321ae9 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/core/page/TableDataInfo.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/core/page/TableDataInfo.java @@ -1,4 +1,4 @@ -package org.ruoyi.common.mybatis.core.page; +package org.ruoyi.core.page; import cn.hutool.http.HttpStatus; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -14,7 +14,6 @@ import java.util.List; * * @author Lion Li */ - @Data @NoArgsConstructor public class TableDataInfo implements Serializable { @@ -51,8 +50,13 @@ public class TableDataInfo implements Serializable { public TableDataInfo(List list, long total) { this.rows = list; this.total = total; + this.code = HttpStatus.HTTP_OK; + this.msg = "查询成功"; } + /** + * 根据分页对象构建表格分页数据对象 + */ public static TableDataInfo build(IPage page) { TableDataInfo rspData = new TableDataInfo<>(); rspData.setCode(HttpStatus.HTTP_OK); @@ -62,6 +66,9 @@ public class TableDataInfo implements Serializable { return rspData; } + /** + * 根据数据列表构建表格分页数据对象 + */ public static TableDataInfo build(List list) { TableDataInfo rspData = new TableDataInfo<>(); rspData.setCode(HttpStatus.HTTP_OK); @@ -71,6 +78,9 @@ public class TableDataInfo implements Serializable { return rspData; } + /** + * 构建表格分页数据对象 + */ public static TableDataInfo build() { TableDataInfo rspData = new TableDataInfo<>(); rspData.setCode(HttpStatus.HTTP_OK); diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/enums/DataBaseType.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/enums/DataBaseType.java similarity index 74% rename from ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/enums/DataBaseType.java rename to ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/enums/DataBaseType.java index fba59340..1b32cda4 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/enums/DataBaseType.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/enums/DataBaseType.java @@ -1,9 +1,10 @@ -package org.ruoyi.common.mybatis.enums; +package org.ruoyi.enums; import lombok.AllArgsConstructor; import lombok.Getter; import org.ruoyi.common.core.utils.StringUtils; + /** * 数据库类型 * @@ -33,8 +34,17 @@ public enum DataBaseType { */ SQL_SERVER("Microsoft SQL Server"); + /** + * 数据库类型 + */ private final String type; + /** + * 根据数据库产品名称查找对应的数据库类型 + * + * @param databaseProductName 数据库产品名称 + * @return 对应的数据库类型枚举值,如果未找到则返回 null + */ public static DataBaseType find(String databaseProductName) { if (StringUtils.isBlank(databaseProductName)) { return null; diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/enums/DataScopeType.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/enums/DataScopeType.java new file mode 100644 index 00000000..f478adbd --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/enums/DataScopeType.java @@ -0,0 +1,87 @@ +package org.ruoyi.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.ruoyi.common.core.domain.model.LoginUser; +import org.ruoyi.common.core.utils.StringUtils; +import org.ruoyi.helper.DataPermissionHelper; + +/** + * 数据权限类型枚举 + *

    + * 支持使用 SpEL 模板表达式定义 SQL 查询条件 + * 内置数据: + * - {@code user}: 当前登录用户信息,参考 {@link LoginUser} + * 内置服务: + * - {@code sdss}: 系统数据权限服务,参考 ISysDataScopeService + * 如需扩展数据,可以通过 {@link DataPermissionHelper} 进行操作 + * 如需扩展服务,可以通过 ISysDataScopeService 自行编写 + *

    + * + * @author Lion Li + * @version 3.5.0 + */ +@Getter +@AllArgsConstructor +public enum DataScopeType { + + /** + * 全部数据权限 + */ + ALL("1", "", ""), + + /** + * 自定数据权限 + */ + CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", " 1 = 0 "), + + /** + * 部门数据权限 + */ + DEPT("3", " #{#deptName} = #{#user.deptId} ", " 1 = 0 "), + + /** + * 部门及以下数据权限 + */ + DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", " 1 = 0 "), + + /** + * 仅本人数据权限 + */ + SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 "), + + /** + * 部门及以下或本人数据权限 + */ + DEPT_AND_CHILD_OR_SELF("6", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} ) OR #{#userName} = #{#user.userId} ", " 1 = 0 "); + + private final String code; + + /** + * SpEL 模板表达式,用于构建 SQL 查询条件 + */ + private final String sqlTemplate; + + /** + * 如果不满足 {@code sqlTemplate} 的条件,则使用此默认 SQL 表达式 + */ + private final String elseSql; + + /** + * 根据枚举代码查找对应的枚举值 + * + * @param code 枚举代码 + * @return 对应的枚举值,如果未找到则返回 null + */ + public static DataScopeType findCode(String code) { + if (StringUtils.isBlank(code)) { + return null; + } + for (DataScopeType type : values()) { + if (type.getCode().equals(code)) { + return type; + } + } + return null; + } +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/InjectionMetaObjectHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/InjectionMetaObjectHandler.java new file mode 100644 index 00000000..57843d35 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/InjectionMetaObjectHandler.java @@ -0,0 +1,103 @@ +package org.ruoyi.handler; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.HttpStatus; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.reflection.MetaObject; +import org.ruoyi.common.core.domain.model.LoginUser; +import org.ruoyi.common.core.exception.ServiceException; +import org.ruoyi.common.core.utils.ObjectUtils; +import org.ruoyi.common.satoken.utils.LoginHelper; +import org.ruoyi.core.domain.BaseEntity; + + +import java.util.Date; + +/** + * MP注入处理器 + * + * @author Lion Li + * @date 2021/4/25 + */ +@Slf4j +public class InjectionMetaObjectHandler implements MetaObjectHandler { + + /** + * 插入填充方法,用于在插入数据时自动填充实体对象中的创建时间、更新时间、创建人、更新人等信息 + * + * @param metaObject 元对象,用于获取原始对象并进行填充 + */ + @Override + public void insertFill(MetaObject metaObject) { + try { + if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) { + // 获取当前时间作为创建时间和更新时间,如果创建时间不为空,则使用创建时间,否则使用当前时间 + Date current = ObjectUtils.notNull(baseEntity.getCreateTime(), new Date()); + baseEntity.setCreateTime(current); + baseEntity.setUpdateTime(current); + + // 如果创建人为空,则填充当前登录用户的信息 + if (ObjectUtil.isNull(baseEntity.getCreateBy())) { + LoginUser loginUser = getLoginUser(); + if (ObjectUtil.isNotNull(loginUser)) { + Long userId = loginUser.getUserId(); + // 填充创建人、更新人和创建部门信息 + baseEntity.setCreateBy(userId); + baseEntity.setUpdateBy(userId); + baseEntity.setCreateDept(ObjectUtils.notNull(baseEntity.getCreateDept(), loginUser.getDeptId())); + } + } + } else { + Date date = new Date(); + this.strictInsertFill(metaObject, "createTime", Date.class, date); + this.strictInsertFill(metaObject, "updateTime", Date.class, date); + } + } catch (Exception e) { + throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); + } + } + + /** + * 更新填充方法,用于在更新数据时自动填充实体对象中的更新时间和更新人信息 + * + * @param metaObject 元对象,用于获取原始对象并进行填充 + */ + @Override + public void updateFill(MetaObject metaObject) { + try { + if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) { + // 获取当前时间作为更新时间,无论原始对象中的更新时间是否为空都填充 + Date current = new Date(); + baseEntity.setUpdateTime(current); + + // 获取当前登录用户的ID,并填充更新人信息 + Long userId = LoginHelper.getUserId(); + if (ObjectUtil.isNotNull(userId)) { + baseEntity.setUpdateBy(userId); + } + } else { + this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date()); + } + } catch (Exception e) { + throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); + } + } + + /** + * 获取当前登录用户信息 + * + * @return 当前登录用户的信息,如果用户未登录则返回 null + */ + private LoginUser getLoginUser() { + LoginUser loginUser; + try { + loginUser = LoginHelper.getLoginUser(); + } catch (Exception e) { + log.warn("自动注入警告 => 用户未登录"); + return null; + } + return loginUser; + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/handler/MybatisExceptionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/MybatisExceptionHandler.java similarity index 90% rename from ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/handler/MybatisExceptionHandler.java rename to ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/MybatisExceptionHandler.java index 281d172d..0cb338c2 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/handler/MybatisExceptionHandler.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/MybatisExceptionHandler.java @@ -1,9 +1,11 @@ -package org.ruoyi.common.mybatis.handler; +package org.ruoyi.handler; import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; -import org.ruoyi.common.core.domain.R; + import org.mybatis.spring.MyBatisSystemException; +import org.ruoyi.common.core.domain.R; +import org.ruoyi.common.core.utils.StringUtils; import org.springframework.dao.DuplicateKeyException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -34,7 +36,7 @@ public class MybatisExceptionHandler { public R handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) { String requestURI = request.getRequestURI(); String message = e.getMessage(); - if (message.contains("CannotFindDataSourceException")) { + if (StringUtils.contains("CannotFindDataSourceException", message)) { log.error("请求地址'{}', 未找到数据源", requestURI); return R.fail("未找到数据源,请联系管理员确认"); } diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/PlusDataPermissionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/PlusDataPermissionHandler.java new file mode 100644 index 00000000..46e0b2e9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/PlusDataPermissionHandler.java @@ -0,0 +1,359 @@ +package org.ruoyi.handler; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.operators.conditional.AndExpression; +import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import org.apache.ibatis.io.Resources; + +import org.ruoyi.annotation.DataColumn; +import org.ruoyi.annotation.DataPermission; +import org.ruoyi.common.core.domain.dto.RoleDTO; +import org.ruoyi.common.core.domain.model.LoginUser; +import org.ruoyi.common.core.exception.ServiceException; +import org.ruoyi.common.core.utils.SpringUtils; +import org.ruoyi.common.core.utils.StreamUtils; +import org.ruoyi.common.core.utils.StringUtils; +import org.ruoyi.common.satoken.utils.LoginHelper; +import org.ruoyi.enums.DataScopeType; +import org.ruoyi.helper.DataPermissionHelper; + +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.type.ClassMetadata; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.expression.*; +import org.springframework.expression.common.TemplateParserContext; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.util.ClassUtils; + +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +/** + * 数据权限过滤 + * + * @author Lion Li + * @version 3.5.0 + */ +@Slf4j +public class PlusDataPermissionHandler { + + /** + * 类名称与注解的映射关系缓存(由于aop无法拦截mybatis接口类上的注解 只能通过启动预扫描的方式进行) + */ + private final Map dataPermissionCacheMap = new ConcurrentHashMap<>(); + + /** + * spel 解析器 + */ + private final ExpressionParser parser = new SpelExpressionParser(); + private final ParserContext parserContext = new TemplateParserContext(); + /** + * bean解析器 用于处理 spel 表达式中对 bean 的调用 + */ + private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory()); + + /** + * 构造方法,扫描指定包下的 Mapper 类并初始化缓存 + * + * @param mapperPackage Mapper 类所在的包路径 + */ + public PlusDataPermissionHandler(String mapperPackage) { + scanMapperClasses(mapperPackage); + } + + /** + * 获取数据过滤条件的 SQL 片段 + * + * @param where 原始的查询条件表达式 + * @param mappedStatementId Mapper 方法的 ID + * @param isSelect 是否为查询语句 + * @return 数据过滤条件的 SQL 片段 + */ + public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) { + try { + // 获取数据权限配置 + DataPermission dataPermission = getDataPermission(mappedStatementId); + // 获取当前登录用户信息 + LoginUser currentUser = DataPermissionHelper.getVariable("user"); + if (ObjectUtil.isNull(currentUser)) { + currentUser = LoginHelper.getLoginUser(); + DataPermissionHelper.setVariable("user", currentUser); + } + // 如果是超级管理员或租户管理员,则不过滤数据 + if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) { + return where; + } + // 构造数据过滤条件的 SQL 片段 + String dataFilterSql = buildDataFilter(dataPermission, isSelect); + if (StringUtils.isBlank(dataFilterSql)) { + return where; + } + Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql); + // 数据权限使用单独的括号 防止与其他条件冲突 + ParenthesedExpressionList parenthesis = new ParenthesedExpressionList<>(expression); + if (ObjectUtil.isNotNull(where)) { + return new AndExpression(where, parenthesis); + } else { + return parenthesis; + } + } catch (JSQLParserException e) { + throw new ServiceException("数据权限解析异常 => " + e.getMessage()); + } finally { + DataPermissionHelper.removePermission(); + } + } + + /** + * 构建数据过滤条件的 SQL 语句 + * + * @param dataPermission 数据权限注解 + * @param isSelect 标志当前操作是否为查询操作,查询操作和更新或删除操作在处理过滤条件时会有不同的处理方式 + * @return 构建的数据过滤条件的 SQL 语句 + * @throws ServiceException 如果角色的数据范围异常或者 key 与 value 的长度不匹配,则抛出 ServiceException 异常 + */ + private String buildDataFilter(DataPermission dataPermission, boolean isSelect) { + // 更新或删除需满足所有条件 + String joinStr = isSelect ? " OR " : " AND "; + if (StringUtils.isNotBlank(dataPermission.joinStr())) { + joinStr = " " + dataPermission.joinStr() + " "; + } + LoginUser user = DataPermissionHelper.getVariable("user"); + Object defaultValue = "-1"; + NullSafeStandardEvaluationContext context = new NullSafeStandardEvaluationContext(defaultValue); + context.addPropertyAccessor(new NullSafePropertyAccessor(context.getPropertyAccessors().get(0), defaultValue)); + context.setBeanResolver(beanResolver); + DataPermissionHelper.getContext().forEach(context::setVariable); + Set conditions = new HashSet<>(); + // 优先设置变量 + List keys = new ArrayList<>(); + Map ignoreMap = new HashMap<>(); + for (DataColumn dataColumn : dataPermission.value()) { + if (dataColumn.key().length != dataColumn.value().length) { + throw new ServiceException("角色数据范围异常 => key与value长度不匹配"); + } + // 包含权限标识符 这直接跳过 + if (StringUtils.isNotBlank(dataColumn.permission()) && + CollUtil.contains(user.getMenuPermission(), dataColumn.permission()) + ) { + ignoreMap.put(dataColumn, Boolean.TRUE); + continue; + } + // 设置注解变量 key 为表达式变量 value 为变量值 + for (int i = 0; i < dataColumn.key().length; i++) { + context.setVariable(dataColumn.key()[i], dataColumn.value()[i]); + } + keys.addAll(Arrays.stream(dataColumn.key()).map(key -> "#" + key).toList()); + } + + for (RoleDTO role : user.getRoles()) { + user.setRoleId(role.getRoleId()); + // 获取角色权限泛型 + DataScopeType type = DataScopeType.findCode(role.getDataScope()); + if (ObjectUtil.isNull(type)) { + throw new ServiceException("角色数据范围异常 => " + role.getDataScope()); + } + // 全部数据权限直接返回 + if (type == DataScopeType.ALL) { + return StringUtils.EMPTY; + } + boolean isSuccess = false; + for (DataColumn dataColumn : dataPermission.value()) { + // 包含权限标识符 这直接跳过 + if (ignoreMap.containsKey(dataColumn)) { + // 修复多角色与权限标识符共用问题 https://gitee.com/dromara/RuoYi-Vue-Plus/issues/IB4CS4 + conditions.add(joinStr + " 1 = 1 "); + isSuccess = true; + continue; + } + // 不包含 key 变量 则不处理 + if (!StringUtils.containsAny(type.getSqlTemplate(), keys.toArray(String[]::new))) { + continue; + } + // 当前注解不满足模板 不处理 + if (!StringUtils.containsAny(type.getSqlTemplate(), dataColumn.key())) { + continue; + } + // 忽略数据权限 防止spel表达式内有其他sql查询导致死循环调用 + String sql = DataPermissionHelper.ignore(() -> + parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class) + ); + // 解析sql模板并填充 + conditions.add(joinStr + sql); + isSuccess = true; + } + // 未处理成功则填充兜底方案 + if (!isSuccess && StringUtils.isNotBlank(type.getElseSql())) { + conditions.add(joinStr + type.getElseSql()); + } + } + + if (CollUtil.isNotEmpty(conditions)) { + String sql = StreamUtils.join(conditions, Function.identity(), ""); + return sql.substring(joinStr.length()); + } + return StringUtils.EMPTY; + } + + /** + * 扫描指定包下的 Mapper 类,并查找其中带有特定注解的方法或类 + * + * @param mapperPackage Mapper 类所在的包路径 + */ + private void scanMapperClasses(String mapperPackage) { + // 创建资源解析器和元数据读取工厂 + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory(); + // 将 Mapper 包路径按分隔符拆分为数组 + String[] packagePatternArray = StringUtils.splitPreserveAllTokens(mapperPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); + String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX; + try { + for (String packagePattern : packagePatternArray) { + // 将包路径转换为资源路径 + String path = ClassUtils.convertClassNameToResourcePath(packagePattern); + // 获取指定路径下的所有 .class 文件资源 + Resource[] resources = resolver.getResources(classpath + path + "/*.class"); + for (Resource resource : resources) { + // 获取资源的类元数据 + ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata(); + // 获取资源对应的类对象 + Class clazz = Resources.classForName(classMetadata.getClassName()); + // 查找类中的特定注解 + findAnnotation(clazz); + } + } + } catch (Exception e) { + log.error("初始化数据安全缓存时出错:{}", e.getMessage()); + } + } + + /** + * 在指定的类中查找特定的注解 DataPermission,并将带有这个注解的方法或类存储到 dataPermissionCacheMap 中 + * + * @param clazz 要查找的类 + */ + private void findAnnotation(Class clazz) { + DataPermission dataPermission; + for (Method method : clazz.getMethods()) { + if (method.isDefault() || method.isVarArgs()) { + continue; + } + String mappedStatementId = clazz.getName() + "." + method.getName(); + if (AnnotationUtil.hasAnnotation(method, DataPermission.class)) { + dataPermission = AnnotationUtil.getAnnotation(method, DataPermission.class); + dataPermissionCacheMap.put(mappedStatementId, dataPermission); + } + } + if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) { + dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class); + dataPermissionCacheMap.put(clazz.getName(), dataPermission); + } + } + + /** + * 根据映射语句 ID 或类名获取对应的 DataPermission 注解对象 + * + * @param mapperId 映射语句 ID + * @return DataPermission 注解对象,如果不存在则返回 null + */ + public DataPermission getDataPermission(String mapperId) { + // 检查上下文中是否包含映射语句 ID 对应的 DataPermission 注解对象 + if (DataPermissionHelper.getPermission() != null) { + return DataPermissionHelper.getPermission(); + } + // 检查缓存中是否包含映射语句 ID 对应的 DataPermission 注解对象 + if (dataPermissionCacheMap.containsKey(mapperId)) { + return dataPermissionCacheMap.get(mapperId); + } + // 如果缓存中不包含映射语句 ID 对应的 DataPermission 注解对象,则尝试使用类名作为键查找 + String clazzName = mapperId.substring(0, mapperId.lastIndexOf(".")); + if (dataPermissionCacheMap.containsKey(clazzName)) { + return dataPermissionCacheMap.get(clazzName); + } + return null; + } + + /** + * 检查给定的映射语句 ID 是否有效,即是否能够找到对应的 DataPermission 注解对象 + * + * @param mapperId 映射语句 ID + * @return 如果找到对应的 DataPermission 注解对象,则返回 false;否则返回 true + */ + public boolean invalid(String mapperId) { + return getDataPermission(mapperId) == null; + } + + /** + * 对所有null变量找不到的变量返回默认值 + */ + @AllArgsConstructor + private static class NullSafeStandardEvaluationContext extends StandardEvaluationContext { + + private final Object defaultValue; + + @Override + public Object lookupVariable(String name) { + Object obj = super.lookupVariable(name); + // 如果读取到的值是 null,则返回默认值 + if (obj == null) { + return defaultValue; + } + return obj; + } + + } + + /** + * 对所有null变量找不到的变量返回默认值 委托模式 将不需要处理的方法委托给原处理器 + */ + @AllArgsConstructor + private static class NullSafePropertyAccessor implements PropertyAccessor { + + private final PropertyAccessor delegate; + private final Object defaultValue; + + @Override + public Class[] getSpecificTargetClasses() { + return delegate.getSpecificTargetClasses(); + } + + @Override + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + return delegate.canRead(context, target, name); + } + + @Override + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + TypedValue value = delegate.read(context, target, name); + // 如果读取到的值是 null,则返回默认值 + if (value.getValue() == null) { + return new TypedValue(defaultValue); + } + return value; + } + + @Override + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + return delegate.canWrite(context, target, name); + } + + @Override + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + delegate.write(context, target, name, newValue); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/PlusPostInitTableInfoHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/PlusPostInitTableInfoHandler.java new file mode 100644 index 00000000..aac6bb55 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/handler/PlusPostInitTableInfoHandler.java @@ -0,0 +1,28 @@ +package org.ruoyi.handler; + +import cn.hutool.core.convert.Convert; +import com.baomidou.mybatisplus.core.handlers.PostInitTableInfoHandler; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import org.apache.ibatis.session.Configuration; +import org.ruoyi.common.core.utils.SpringUtils; +import org.ruoyi.common.core.utils.reflect.ReflectUtils; + + +/** + * 修改表信息初始化方式 + * 目前用于全局修改是否使用逻辑删除 + * + * @author Lion Li + */ +public class PlusPostInitTableInfoHandler implements PostInitTableInfoHandler { + + @Override + public void postTableInfo(TableInfo tableInfo, Configuration configuration) { + String flag = SpringUtils.getProperty("mybatis-plus.enableLogicDelete", "true"); + // 只有关闭时 统一设置false 为true时mp自动判断不处理 + if (!Convert.toBool(flag)) { + ReflectUtils.setFieldValue(tableInfo, "withLogicDelete", false); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/helper/DataBaseHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/helper/DataBaseHelper.java similarity index 91% rename from ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/helper/DataBaseHelper.java rename to ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/helper/DataBaseHelper.java index f060e17a..16a16375 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/common/mybatis/helper/DataBaseHelper.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/helper/DataBaseHelper.java @@ -1,12 +1,13 @@ -package org.ruoyi.common.mybatis.helper; +package org.ruoyi.helper; import cn.hutool.core.convert.Convert; import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; import lombok.AccessLevel; import lombok.NoArgsConstructor; + import org.ruoyi.common.core.exception.ServiceException; import org.ruoyi.common.core.utils.SpringUtils; -import org.ruoyi.common.mybatis.enums.DataBaseType; +import org.ruoyi.enums.DataBaseType; import javax.sql.DataSource; import java.sql.Connection; @@ -62,8 +63,8 @@ public class DataBaseHelper { // charindex(',100,' , ',0,100,101,') <> 0 return "charindex(',%s,' , ','+%s+',') <> 0".formatted(var, var2); } else if (dataBasyType == DataBaseType.POSTGRE_SQL) { - // (select position(',100,' in ',0,100,101,')) <> 0 - return "(select position(',%s,' in ','||%s||',')) <> 0".formatted(var, var2); + // (select strpos(',0,100,101,' , ',100,')) <> 0 + return "(select strpos(','||%s||',' , ',%s,')) <> 0".formatted(var2, var); } else if (dataBasyType == DataBaseType.ORACLE) { // instr(',0,100,101,' , ',100,') <> 0 return "instr(','||%s||',' , ',%s,') <> 0".formatted(var2, var); @@ -71,6 +72,7 @@ public class DataBaseHelper { // find_in_set(100 , '0,100,101') return "find_in_set('%s' , %s) <> 0".formatted(var, var2); } + /** * 获取当前加载的数据库名 */ diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/helper/DataPermissionHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/helper/DataPermissionHelper.java new file mode 100644 index 00000000..3d8f99c8 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/helper/DataPermissionHelper.java @@ -0,0 +1,176 @@ +package org.ruoyi.helper; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.context.model.SaStorage; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy; +import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.ruoyi.annotation.DataPermission; +import org.ruoyi.common.core.utils.reflect.ReflectUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; +import java.util.function.Supplier; + +/** + * 数据权限助手 + * + * @author Lion Li + * @version 3.5.0 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@SuppressWarnings("unchecked cast") +public class DataPermissionHelper { + + private static final String DATA_PERMISSION_KEY = "data:permission"; + + private static final ThreadLocal> REENTRANT_IGNORE = ThreadLocal.withInitial(Stack::new); + + private static final ThreadLocal PERMISSION_CACHE = new ThreadLocal<>(); + + /** + * 获取当前执行mapper权限注解 + * + * @return 返回当前执行mapper权限注解 + */ + public static DataPermission getPermission() { + return PERMISSION_CACHE.get(); + } + + /** + * 设置当前执行mapper权限注解 + * + * @param dataPermission 数据权限注解 + */ + public static void setPermission(DataPermission dataPermission) { + PERMISSION_CACHE.set(dataPermission); + } + + /** + * 删除当前执行mapper权限注解 + */ + public static void removePermission() { + PERMISSION_CACHE.remove(); + } + + /** + * 从上下文中获取指定键的变量值,并将其转换为指定的类型 + * + * @param key 变量的键 + * @param 变量值的类型 + * @return 指定键的变量值,如果不存在则返回 null + */ + public static T getVariable(String key) { + Map context = getContext(); + return (T) context.get(key); + } + + /** + * 向上下文中设置指定键的变量值 + * + * @param key 要设置的变量的键 + * @param value 要设置的变量值 + */ + public static void setVariable(String key, Object value) { + Map context = getContext(); + context.put(key, value); + } + + /** + * 获取数据权限上下文 + * + * @return 存储在SaStorage中的Map对象,用于存储数据权限相关的上下文信息 + * @throws NullPointerException 如果数据权限上下文类型异常,则抛出NullPointerException + */ + public static Map getContext() { + SaStorage saStorage = SaHolder.getStorage(); + Object attribute = saStorage.get(DATA_PERMISSION_KEY); + if (ObjectUtil.isNull(attribute)) { + saStorage.set(DATA_PERMISSION_KEY, new HashMap<>()); + attribute = saStorage.get(DATA_PERMISSION_KEY); + } + if (attribute instanceof Map map) { + return map; + } + throw new NullPointerException("data permission context type exception"); + } + + private static IgnoreStrategy getIgnoreStrategy() { + Object ignoreStrategyLocal = ReflectUtils.getStaticFieldValue(ReflectUtils.getField(InterceptorIgnoreHelper.class, "IGNORE_STRATEGY_LOCAL")); + if (ignoreStrategyLocal instanceof ThreadLocal IGNORE_STRATEGY_LOCAL) { + if (IGNORE_STRATEGY_LOCAL.get() instanceof IgnoreStrategy ignoreStrategy) { + return ignoreStrategy; + } + } + return null; + } + + /** + * 开启忽略数据权限(开启后需手动调用 {@link #disableIgnore()} 关闭) + */ + public static void enableIgnore() { + IgnoreStrategy ignoreStrategy = getIgnoreStrategy(); + if (ObjectUtil.isNull(ignoreStrategy)) { + InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build()); + } else { + ignoreStrategy.setDataPermission(true); + } + Stack reentrantStack = REENTRANT_IGNORE.get(); + reentrantStack.push(reentrantStack.size() + 1); + } + + /** + * 关闭忽略数据权限 + */ + public static void disableIgnore() { + IgnoreStrategy ignoreStrategy = getIgnoreStrategy(); + if (ObjectUtil.isNotNull(ignoreStrategy)) { + boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName()) + && !Boolean.TRUE.equals(ignoreStrategy.getBlockAttack()) + && !Boolean.TRUE.equals(ignoreStrategy.getIllegalSql()) + && !Boolean.TRUE.equals(ignoreStrategy.getTenantLine()) + && CollectionUtil.isEmpty(ignoreStrategy.getOthers()); + Stack reentrantStack = REENTRANT_IGNORE.get(); + boolean empty = reentrantStack.isEmpty() || reentrantStack.pop() == 1; + if (noOtherIgnoreStrategy && empty) { + InterceptorIgnoreHelper.clearIgnoreStrategy(); + } else if (empty) { + ignoreStrategy.setDataPermission(false); + } + + } + } + + /** + * 在忽略数据权限中执行 + * + * @param handle 处理执行方法 + */ + public static void ignore(Runnable handle) { + enableIgnore(); + try { + handle.run(); + } finally { + disableIgnore(); + } + } + + /** + * 在忽略数据权限中执行 + * + * @param handle 处理执行方法 + */ + public static T ignore(Supplier handle) { + enableIgnore(); + try { + return handle.get(); + } finally { + disableIgnore(); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/interceptor/PlusDataPermissionInterceptor.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/interceptor/PlusDataPermissionInterceptor.java new file mode 100644 index 00000000..10a58e5a --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/ruoyi/interceptor/PlusDataPermissionInterceptor.java @@ -0,0 +1,181 @@ +package org.ruoyi.interceptor; + +import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; +import com.baomidou.mybatisplus.core.toolkit.PluginUtils; +import com.baomidou.mybatisplus.extension.plugins.handler.MultiDataPermissionHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.BaseMultiTableInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SetOperationList; +import net.sf.jsqlparser.statement.update.Update; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.ruoyi.handler.PlusDataPermissionHandler; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.List; + +/** + * 数据权限拦截器 + * + * @author Lion Li + * @version 3.5.0 + */ +@Slf4j +public class PlusDataPermissionInterceptor extends BaseMultiTableInnerInterceptor implements InnerInterceptor { + + private final PlusDataPermissionHandler dataPermissionHandler; + + /** + * 构造函数,初始化 PlusDataPermissionHandler 实例 + * + * @param mapperPackage 扫描的映射器包 + */ + public PlusDataPermissionInterceptor(String mapperPackage) { + this.dataPermissionHandler = new PlusDataPermissionHandler(mapperPackage); + } + + /** + * 在执行查询之前,检查并处理数据权限相关逻辑 + * + * @param executor MyBatis 执行器对象 + * @param ms 映射语句对象 + * @param parameter 方法参数 + * @param rowBounds 分页对象 + * @param resultHandler 结果处理器 + * @param boundSql 绑定的 SQL 对象 + * @throws SQLException 如果发生 SQL 异常 + */ + @Override + public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { + // 检查是否需要忽略数据权限处理 + if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) { + return; + } + // 检查是否缺少有效的数据权限注解 + if (dataPermissionHandler.invalid(ms.getId())) { + return; + } + // 解析 sql 分配对应方法 + PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql); + mpBs.sql(parserSingle(mpBs.sql(), ms.getId())); + } + + /** + * 在准备 SQL 语句之前,检查并处理更新和删除操作的数据权限相关逻辑 + * + * @param sh MyBatis StatementHandler 对象 + * @param connection 数据库连接对象 + * @param transactionTimeout 事务超时时间 + */ + @Override + public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { + PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); + MappedStatement ms = mpSh.mappedStatement(); + // 获取 SQL 命令类型(增、删、改、查) + SqlCommandType sct = ms.getSqlCommandType(); + + // 只处理更新和删除操作的 SQL 语句 + if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) { + if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) { + return; + } + // 检查是否缺少有效的数据权限注解 + if (dataPermissionHandler.invalid(ms.getId())) { + return; + } + PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); + mpBs.sql(parserMulti(mpBs.sql(), ms.getId())); + } + } + + /** + * 处理 SELECT 查询语句中的 WHERE 条件 + * + * @param select SELECT 查询对象 + * @param index 查询语句的索引 + * @param sql 查询语句 + * @param obj WHERE 条件参数 + */ + @Override + protected void processSelect(Select select, int index, String sql, Object obj) { + if (select instanceof PlainSelect) { + this.setWhere((PlainSelect) select, (String) obj); + } else if (select instanceof SetOperationList setOperationList) { + List - + select column_name, (case when (is_nullable = 'no' column_key != 'PRI') then '1' else null end) as is_required, (case when column_key = 'PRI' then '1' else '0' end) as is_pk, @@ -19,7 +19,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName}) order by ordinal_position - + select lower(temp.column_name) as column_name, (case when (temp.nullable = 'N' and temp.constraint_type != 'P') then '1' else null end) as is_required, (case when temp.constraint_type = 'P' then '1' else '0' end) as is_pk, @@ -39,7 +39,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" WHERE temp.row_flg = 1 ORDER BY temp.column_id - + SELECT column_name, is_required, is_pk, sort, column_comment, is_increment, column_type FROM ( SELECT c.relname AS table_name, @@ -73,7 +73,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" WHERE table_name = (#{tableName}) AND column_type ]]> '-' - + SELECT cast(A.NAME as nvarchar) as column_name, cast(B.NAME as nvarchar) + (case when B.NAME = 'numeric' then '(' + cast(A.prec as nvarchar) + ',' + cast(A.scale as nvarchar) + ')' else '' end) as column_type, diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml index a0a7695c..6c994d82 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml @@ -15,7 +15,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"