commit 5160544751d692eff02014aaa964eb6fbf02b0cd
Author: jiyufei <67400194@qq.com>
Date: Fri Aug 2 13:45:25 2024 +0800
feat():月月舒项目框架;
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..291be30
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,75 @@
+# For Java
+*.lck
+target/
+log/
+logback-test.xml
+
+
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+# Image snapshot diff
+__diff_output__/
+/jest-stare
+
+*.iml
+.idea/
+.ipr
+.iws
+*~
+~*
+*.diff
+*.patch
+*.bak
+.DS_Store
+Thumbs.db
+.project
+.*proj
+.svn/
+*.swp
+*.swo
+*.log
+*.log.*
+*.json.gzip
+node_modules/
+.buildpath
+.settings
+dist
+npm-debug.log
+nohup.out
+_site
+_data
+report.html
+/lib
+/es
+elasticsearch-*
+config/base.yaml
+/.vscode/
+/coverage
+/.history
+*.tmp
+!**/nacos/target
+**/nacos/data/*
+**/nacos/logs/*
+**/seata/bin/*
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..35f7bea
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,22 @@
+# 基础镜像
+FROM eclipse-temurin:8u362-b09-jre
+LABEL maintainer=jnpf-team
+
+# 设置时区
+RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
+ && echo 'Asia/Shanghai' >/etc/timezone
+
+# 解决连接SQLServer安全错误
+COPY security/java.security /opt/java/openjdk/lib/security
+
+# 指定运行时的工作目录
+WORKDIR /jnpfsoft/jnpf-server/jnpf-java-boot
+
+# 将构建产物jar包拷贝到运行时目录中
+COPY jnpf-admin/target/*.jar ./jnpf-admin.jar
+
+# 指定容器内运行端口
+EXPOSE 30000
+
+# 指定容器启动时要运行的命令
+ENTRYPOINT ["/bin/sh","-c","java -Dfile.encoding=utf8 -Djava.security.egd=file:/dev/./urandom -jar jnpf-admin.jar"]
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..95a3a33
--- /dev/null
+++ b/README.md
@@ -0,0 +1,369 @@
+> 特别说明:源码、JDK、MySQL、Redis等安装或存放路径禁止包含中文、空格、特殊字符等
+
+## 一 技术栈
+
+- 主框架:`Spring Boot` + `Spring Framework`
+- 持久层框架:`MyBatis-Plus`
+- 数据库连接池:`Alibaba Druid`
+- 多数据源:`Dynamic-Datasource`
+- 数据库兼容: `MySQL`(默认)、`SQLServer`、`Oracle`、`PostgreSQL`、`达数据库`、`人大金仓数据库`
+- 分库分表解决方案:`Apache ShardingSphere`
+- 权限认证框架:`Sa-Token`+`JWT`
+- 代码生成器:`MyBatis-Plus-Generator`
+- 模板引擎:`Velocity`
+- 任务调度:`XXL-JOB`
+- 分布式锁:`Lock4j`
+- JSON序列化: `Jackson`&`Fastjson`
+- 缓存数据库:`Redis`
+- 校验框架:`Validation`
+- 分布式文件存储:兼容`MinIO`及多个云对象存储,如阿里云 OSS、华为云 OBS、七牛云 Kodo、腾讯云 COS等
+- 工具类框架:`Hutool`、`Lombok`
+- 接口文档:`Knife4j`
+- 项目构建:`Maven`
+
+## 二 环境要求
+
+### 2.1 开发环境
+
+| 类目 | 版本说明或建议 |
+| --- |---------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| 电脑配置 | 建议开发电脑I3及以上CPU,内存16G及以上 |
+| 操作系统 | Windows 10/11,MacOS |
+| JDK | 建议使用`1.8.0_281`及以上版本,可使用`Eclipse Temurin JDK 8`、`Alibaba Dragonwell 8`、`BiSheng JDK 8`等 |
+| Maven | `3.6.3`及以上版本 |
+| 数据缓存 | Redis `3.2.100`(Windows)/`4.0.x`+ (Linux,Mac) 或 TongRDS `2.2.x` |
+| 数据库 | 兼容`MySQL 5.7.x/8.0.x`(默认)、`SQLServer 2012+`、`Oracle 11g`、`PostgreSQL 12+`、`达梦数据库(DM8)`、`人大金仓数据库(KingbaseES_V8R6)` |
+| 后端开发 | `IDEA2020`及以上版本、`Eclipse` 、 `Spring Tool Suite`等 |
+| 前端开发 | `Node.js` v16.15.0(某些情况下可能需要安装 `Python3`)及以上版本;
`Yarn` v1.22.x 版本;
`pnpm` v8.10及以上版本;
浏览器推荐使用`Chrome` 90及以上版本;
`Visual Studio Code`(简称VSCode) |
+| 移动端开发 | `Node.js` v12/v14/v16(某些情况下可能需要安装 Python3);
HBuilder X(最新版) |
+| 文件存储 | 默认使用本地存储,兼容 `MinIO` 及多个云对象存储,如`阿里云 OSS`、`华为云 OBS`、`七牛云 Kodo`、`腾讯云 COS`等 |
+
+### 2.2 运行环境
+
+> 适用于测试或生产环境
+
+| 类目 | 版本说明或建议 |
+| --- |-------------------------------------------------------------------------------------------------------------------|
+| 服务器配置 | 最低配置要求:4c/16G/50G; |
+| 操作系统 | 推荐使用`Ubuntu 18.0.4`及以上版本,兼容 `统信UOS`,`OpenEuler`,`麒麟服务器版`等国产信创环境; |
+| JRE | 建议使用`1.8.0_281`及以上版本,如`Eclipse Temurin JRE 8/11/17`、`Alibaba Dragonwell 8/11/17`、`BiSheng JRE 8/11/17`; |
+| 数据缓存 | Redis `4.0.x+` 或 TongRDS `2.2.x` |
+| 数据库 | 兼容`MySQL 5.7.x/8.0.x`(默认)、`SQLServer 2012+`、`Oracle 11g`、`PostgreSQL 12+`、`达梦数据库(DM8)`、`人大金仓数据库(KingbaseES_V8R6)` |
+| 中间件(可选) | 东方通 `Tong-web`、金蝶天燕-应用服务器`AAS` v10; |
+| 文件存储 | 默认使用本地存储,兼容`MinIO`及多个云对象存储,如阿里云 OSS、华为云 OBS、七牛云 Kodo、腾讯云 COS等 |
+| 前端服务器 | Nginx 建议使用`1.18.0`及以上版本 或 TongHttpServer `6.0` |
+
+## 三 IDEA插件
+
+- `Lombok`(必须)
+- `Alibaba Java Coding Guidelines`
+- `MybatisX`
+
+## 四 Maven私服配置
+
+> Apache Maven 3.6.3及以上版本
解决以下依赖无法从公共Maven仓库下载的问题
+
+- com.dm:DmJdbcDriver18:1.8.0
+- com.kingbase8:kingbase8-jdbc:2.0
+- dingtalk-sdk-java:taobao-sdk-java-source:1.0
+- dingtalk-sdk-java:taobao-sdk-java:1.0
+
+打开Maven安装目录中的 `conf/settings.xml` 文件,
+在 `` 中添加如下内容
+
+```xml
+
+ maven-releases
+ jnpf-user
+ HLrQ0MA%S1nE
+
+```
+在 `` 中添加
+
+```xml
+
+ maven-releases
+ *
+ maven-releases
+ https://repository.jnpfsoft.com/repository/maven-public/
+
+```
+
+## 五 配套项目
+
+| 项目 | 分支 | 分支(Coding) | 说明 |
+| --- | --- | --- | --- |
+| **后端** | | | |
+| jnpf-common | v3.5.x | v3.5.0-stable | java基础依赖项目源码 |
+| jnpf-file-core-starter | v3.5.x | v3.4.3-stable | 文件基础依赖项目源码 |
+| jnpf-scheduletask | v3.5.x | v3.5.0-stable | 任务调度客户端依赖及服务端项目源码 |
+| jnpf-datareport | v3.5.x | v3.4.7-stable | 报表后端项目源码 |
+| jnpf-file-preview | v3.4.3 | v3.0.0-stable | 本地文档预览项目源码 |
+| **前端** | | | |
+| jnpf-web | v3.5.x | v3.5.0-stable | 前端主项目(Vue2)源码 |
+| jnpf-web-vue3 | v3.5.x | v3.5.0-stable | 前端主项目(Vue3)源码 |
+| jnpf-web-datascreen | v3.5.x | v3.5.0-stable | 大屏前端项目(Vue2)源码 |
+| jnpf-web-datascreen-vue3 | v3.5.x | v3.5.0-stable | 大屏前端项目(Vue3)源码 |
+| jnpf-web-datareport | v3.4.7 | v3.4.7-stable | 报表前端项目源码 |
+| **移动端** | | | |
+| jnpf-app | v3.5.x | v3.5.0-stable | 移动端项目(Vue2)源码 |
+| **静态资源** | | | |
+| jnpf-resources | v3.5.x | v3.5.0-stable | 静态资源 |
+| **数据库** | | | |
+| jnpf-database | v3.5.x | v3.5.0-stable | 数据库脚本或文件 |
+
+## 六 开发环境
+
+### 6.1 导入数据库脚本
+
+> 以 MySQL数据库为例
字符集:utf8mb4
排序规则:utf8mb4_general_ci
+
+#### 6.1.1 创建平台数据库
+
+在MySQL创建 `jnpf_init` 数据库,并将 `jnpf-database/MySQL/jnpf_init.sql` 以【新建查询】方式导入
+
+#### 6.1.2 创建系统调度数据库
+
+在MySQL创建 `jnpf_xxjob` 数据库,并将 `jnpf-database/MySQL/jnpf_xxjob_init.sql` 以【新建查询】方式导入
+
+### 6.2 导入依赖
+
+#### 6.2.1 基础依赖
+
+详见 `jnpf-common` 项目中的 `README.md` 文档说明
+
+#### 6.2.2 文件基础依赖
+
+详见 `jnpf-file-starter` 项目中的 `README.md` 文档说明
+
+#### 6.2.3 导入系统调度服务端
+
+详见 `jnpf-scheduletask` 项目中的 `README.md` 文档说明
+
+### 6.3 项目配置
+
+打开编辑 `jnpf-admin/src/main/resources/application.yml`
+
+#### 6.3.1 指定环境配置
+
+- `application-dev.yml` 开发环境(默认)
+- `application-test.yml` 测试环境
+- `application-preview.yml` 预发布环境
+- `application-pro.yml` 生产环境
+
+```yaml
+# application.yml第5行,可选值:dev(默认)|test|pro|preview
+active: dev
+```
+#### 6.3.2 配置域名
+打开编辑 `jnpf-admin/src/main/resources/application.yml` ,修改以下配置
+
+```yaml
+ PreviewType: kkfile #文件预览方式 (1.yozo 2.kkfile)默认使用kkfile
+ kkFileUrl: http://127.0.0.1:30090/FileServer/ #kkfile文件预览服务地址
+ ApiDomain: http://127.0.0.1:30000 #后端域名(文档预览中使用)
+ FrontDomain: http://127.0.0.1:3000 #前端域名(文档预览中使用)
+ AppDomain: http://127.0.0.1:8080 #app/h5端域名配置(文档预览中使用)
+```
+
+#### 6.3.3 数据源配置
+
+打开编辑 `jnpf-admin/src/main/resources/application-dev.yml`,修改以下配置
+> 具体配置说明参考:[https://jnpfsoft.coding.net/p/jnpf-docs/wiki/2165](https://jnpfsoft.coding.net/p/jnpf-docs/wiki/2165)
+
+```yaml
+ datasource:
+ db-type: MySQL #数据库类型(可选值 MySQL、SQLServer、Oracle、DM8、KingbaseES、PostgreSQL,请严格按可选值填写)
+ host: 192.168.0.213
+ port: 3306
+ username: root
+ password: a26d27e6a6cd4538
+ db-name: java_boot_test
+ db-schema: #金仓达梦选填
+ prepare-url: #自定义url
+```
+#### 6.3.4 Redis配置
+
+打开编辑 `jnpf-admin/src/main/resources/application-dev.yml`,修改以下配置
+> 支持单机模式和集群模式,配置默认为单机模式
+
+**Redis单机模式**
+
+```yaml
+ redis:
+ database: 200 #缓存库编号
+ host: 192.168.0.213
+ port: 6379
+ password: ucfbVgZgyB0dBQdh # 密码为空时,请将本行注释
+ timeout: 3000 #超时时间(单位:秒)
+ lettuce: #Lettuce为Redis的Java驱动包
+ pool:
+ max-active: 8 # 连接池最大连接数
+ max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
+ min-idle: 0 # 连接池中的最小空闲连接
+ max-idle: 8 # 连接池中的最大空闲连接
+```
+
+**Redis集群模式**
+
+```yaml
+ redis:
+ cluster:
+ nodes:
+ - 192.168.0.225:6380
+ - 192.168.0.225:6381
+ - 192.168.0.225:6382
+ - 192.168.0.225:6383
+ - 192.168.0.225:6384
+ - 192.168.0.225:6385
+ password: 123456 # 密码为空时,请将本行注释
+ timeout: 3000 # 超时时间(单位:秒)
+ lettuce: #Lettuce为Redis的Java驱动包
+ pool:
+ max-active: 8 # 连接池最大连接数
+ max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
+ min-idle: 0 # 连接池中的最小空闲连接
+ max-idle: 8 # 连接池中的最大空闲连接
+```
+#### 6.3.5 静态资源配置
+
+打开编辑 `jnpf-admin/src/main/resources/application-dev.yml` ,修改以下配置
+> 默认使用本地存储,兼容`MinIO`及多个云对象存储,如阿里云 OSS、华为云 OBS、七牛云 Kodo、腾讯云 COS等
+
+```yaml
+ # ===================== 文件存储配置 =====================
+ file-storage: #文件存储配置,不使用的情况下可以不写
+ default-platform: local-plus-1 #默认使用的存储平台
+ thumbnail-suffix: ".min.jpg" #缩略图后缀,例如【.min.jpg】【.png】
+ local-plus: # 本地存储升级版
+ - platform: local-plus-1 # 存储平台标识
+ enable-storage: true #启用存储
+ enable-access: true #启用访问(线上请使用 Nginx 配置,效率更高)
+ domain: "" # 访问域名,例如:“http://127.0.0.1:8030/”,注意后面要和 path-patterns 保持一致,“/”结尾,本地存储建议使用相对路径,方便后期更换域名
+ base-path: D:/project/jnpf-resources/ # 基础路径
+ path-patterns: /** # 访问路径
+ storage-path: # 存储路径
+ aliyun-oss: # 阿里云 OSS ,不使用的情况下可以不写
+ - platform: aliyun-oss-1 # 存储平台标识
+ enable-storage: false # 启用存储
+ access-key: ??
+ secret-key: ??
+ end-point: ??
+ bucket-name: ??
+ domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.oss-cn-shanghai.aliyuncs.com/
+ base-path: hy/ # 基础路径
+ qiniu-kodo: # 七牛云 kodo ,不使用的情况下可以不写
+ - platform: qiniu-kodo-1 # 存储平台标识
+ enable-storage: false # 启用存储
+ access-key: ??
+ secret-key: ??
+ bucket-name: ??
+ domain: ?? # 访问域名,注意“/”结尾,例如:http://abc.hn-bkt.clouddn.com/
+ base-path: base/ # 基础路径
+ tencent-cos: # 腾讯云 COS
+ - platform: tencent-cos-1 # 存储平台标识
+ enable-storage: false # 启用存储
+ secret-id: ??
+ secret-key: ??
+ region: ?? #存仓库所在地域
+ bucket-name: ??
+ domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.cos.ap-nanjing.myqcloud.com/
+ base-path: hy/ # 基础路径
+ minio: # MinIO,由于 MinIO SDK 支持 AWS S3,其它兼容 AWS S3 协议的存储平台也都可配置在这里
+ - platform: minio-1 # 存储平台标识
+ enable-storage: true # 启用存储
+ access-key: Q9jJs2b6Tv
+ secret-key: Thj2WkpLu9DhmJyJ
+ end-point: http://192.168.0.207:9000/
+ bucket-name: jnpfsoftoss
+ domain: # 访问域名,注意“/”结尾,例如:http://minio.abc.com/abc/
+ base-path: # 基础路径
+```
+#### 6.3.6 第三方登录配置
+
+打开编辑 `jnpf-admin/src/main/resources/application-dev.yml` ,修改以下配置
+> 配置默认关闭
+
+```yaml
+socials:
+ # 第三方登录功能开关(false-关闭,true-开启)
+ socials-enabled: false
+ config:
+ - # 微信
+ provider: wechat_open
+ client-id: your-client-id
+ client-secret: your-client-secret
+ - # qq
+ provider: qq
+ client-id: your-client-id
+ client-secret: your-client-secret
+ - # 企业微信
+ provider: wechat_enterprise
+ client-id: your-client-id
+ client-secret: your-client-secret
+ agentId: your-agentId
+ - # 钉钉
+ provider: dingtalk
+ client-id: your-client-id
+ client-secret: your-client-secret
+ agentId: your-agentId
+ - # 飞书
+ provider: feishu
+ client-id: your-client-id
+ client-secret: your-client-secret
+ - # 小程序
+ provider: wechat_applets
+ client-id: your-client-id
+ client-secret: your-client-secret
+```
+#### 6.3.7 任务调度配置
+
+打开编辑 `jnpf-admin/src/main/resources/application-dev.yml` ,修改以下配置,调整 xxl.job.admin.addresses 地址
+
+```yaml
+xxl:
+ job:
+ accessToken: ''
+ i18n: zh_CN
+ logretentiondays: 30
+ triggerpool:
+ fast:
+ max: 200
+ slow:
+ max: 100
+ # xxl-job服务端地址
+ admin:
+ addresses: http://127.0.0.1:30020/xxl-job-admin/
+ executor:
+ address: ''
+ appname: xxl-job-executor-sample1
+ ip: ''
+ logpath: /data/applogs/xxl-job/jobhandler
+ logretentiondays: 30
+ port: 9999
+ # rest调用xxl-job接口地址
+ admin:
+ register:
+ handle-query-address: ${xxl.job.admin.addresses}api/handler/queryList
+ job-info-address: ${xxl.job.admin.addresses}api/jobinfo
+ log-query-address: ${xxl.job.admin.addresses}api/log
+ task-list-address: ${xxl.job.admin.addresses}api/ScheduleTask/List
+ task-info-address: ${xxl.job.admin.addresses}api/ScheduleTask/getInfo
+ task-save-address: ${xxl.job.admin.addresses}api/ScheduleTask
+ task-update-address: ${xxl.job.admin.addresses}api/ScheduleTask
+ task-remove-address: ${xxl.job.admin.addresses}api/ScheduleTask/remove
+ task-start-or-remove-address: ${xxl.job.admin.addresses}api/ScheduleTask/updateTask
+```
+## 七 启动项目
+
+找到`jnpf-admin/src/main/java/JnpfAdminApplication.java`,右击运行即可。
+
+## 八 项目发布
+
+- 在IDEA中,双击右侧Maven中 `jnpf-java-boot` > `Lifecycle` > `clean` 清理项目
+- 在IDEA中,双击右侧Maven中 `jnpf-java-boot` > `Lifecycle` > `package` 打包项目
+- 打开 `jnpf-java-boot\jnpf-admin\target`,将 `jnpf-admin-3.5.0-RELEASE.jar` 上传至服务器
+
+## 九 接口文档
+
+- `http://localhost:30000/doc.html`
diff --git a/jnpf-admin/pom.xml b/jnpf-admin/pom.xml
new file mode 100644
index 0000000..3fb593e
--- /dev/null
+++ b/jnpf-admin/pom.xml
@@ -0,0 +1,174 @@
+
+
+
+ jnpf-java-boot
+ com.jnpf
+ 3.5.0-RELEASE
+
+
+ 4.0.0
+ jnpf-admin
+ jar
+
+
+
+
+
+ org.projectlombok
+ lombok
+
+
+ com.jnpf
+ jnpf-file-controller
+ ${project.version}
+
+
+
+ com.jnpf
+ jnpf-extend-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-form-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-system-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-scheduletask-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-message-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-permission-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-visualdev-base-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-visualdev-onlinedev-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-visualdev-generater-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-visualdev-portal-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-visualdata-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-exception
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-workflow-engine-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-workflow-form-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-oauth-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-example-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-app-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-visualdev-integrate-controller
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-scm-controller
+ ${project.version}
+
+
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ jnpf.JnpfAdminApplication
+ ZIP
+
+
+
+
+ repackage
+
+
+
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/java/jnpf/JnpfAdminApplication.java b/jnpf-admin/src/main/java/jnpf/JnpfAdminApplication.java
new file mode 100644
index 0000000..6c84b8d
--- /dev/null
+++ b/jnpf-admin/src/main/java/jnpf/JnpfAdminApplication.java
@@ -0,0 +1,29 @@
+package jnpf;
+
+import cn.xuyanwu.spring.file.storage.EnableFileStorage;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+
+/**
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021/3/15 17:12
+ */
+@SpringBootApplication(scanBasePackages = {"jnpf"},exclude={DataSourceAutoConfiguration.class})
+@EnableFileStorage
+public class JnpfAdminApplication extends SpringBootServletInitializer {
+
+ public static void main(String[] args) {
+ SpringApplication springApplication = new SpringApplication(JnpfAdminApplication.class);
+ //添加监听器
+// springApplication.addListeners(new JnpfListener());
+ springApplication.run(args);
+ System.out.println("JnpfAdmin启动完成");
+ }
+
+}
diff --git a/jnpf-admin/src/main/java/jnpf/aop/DataSourceBindAspect.java b/jnpf-admin/src/main/java/jnpf/aop/DataSourceBindAspect.java
new file mode 100644
index 0000000..201517e
--- /dev/null
+++ b/jnpf-admin/src/main/java/jnpf/aop/DataSourceBindAspect.java
@@ -0,0 +1,86 @@
+package jnpf.aop;
+
+import cn.dev33.satoken.context.SaHolder;
+import jnpf.base.UserInfo;
+import jnpf.config.ConfigValueUtil;
+import jnpf.database.util.NotTenantPluginHolder;
+import jnpf.util.data.DataSourceContextHolder;
+import jnpf.util.StringUtil;
+import jnpf.util.UserProvider;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+/**
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021/3/15 17:12
+ */
+@Slf4j
+@Aspect
+@Component
+@Order(1)
+public class DataSourceBindAspect {
+
+ @Autowired
+ private ConfigValueUtil configValueUtil;
+
+ @Pointcut("((execution(* jnpf.*.controller.*.*(..)) || execution(* jnpf.controller.*.*(..))) " +
+ "&& !execution(* jnpf.controller.LoginController.login(..)))" +
+ "|| execution(* jnpf.message.websocket.WebSocket.*(..))")
+ public void bindDataSource() {
+
+ }
+
+ /**
+ * NoDataSourceBind 不需要绑定数据库的注解
+ *
+ * @param pjp
+ * @return
+ * @throws Throwable
+ */
+ @Around("bindDataSource() && !@annotation(jnpf.util.NoDataSourceBind)")
+ public Object doAroundService(ProceedingJoinPoint pjp) throws Throwable {
+ if (configValueUtil.isMultiTenancy()) {
+ if(StringUtil.isEmpty(DataSourceContextHolder.getDatasourceId()) || StringUtil.isEmpty(DataSourceContextHolder.getDatasourceName())){
+ UserInfo userInfo = UserProvider.getUser();
+ String url = null;
+ try{
+ url = SaHolder.getRequest().getRequestPath();
+ }catch (Exception ee){ }
+ log.error("租户" + userInfo.getTenantId() + "数据库不存在, URL: {}, TOKEN: {}", url, userInfo.getToken());
+ return null;
+ }
+ return pjp.proceed();
+ }
+ Object obj = pjp.proceed();
+ return obj;
+ }
+
+
+ /**
+ * NoDataSourceBind 不需要绑定数据库的注解 加入不切租户库标记
+ *
+ * @param pjp
+ * @return
+ * @throws Throwable
+ */
+ @Around("bindDataSource() && @annotation(jnpf.util.NoDataSourceBind)")
+ public Object doAroundService2(ProceedingJoinPoint pjp) throws Throwable {
+ try{
+ NotTenantPluginHolder.setNotSwitchAlwaysFlag();
+ //Filter中提前设置租户信息, 不需要切库的方法进行清除切库
+ DataSourceContextHolder.clearDatasourceType();
+ return pjp.proceed();
+ }finally {
+ NotTenantPluginHolder.clearNotSwitchAlwaysFlag();
+ }
+ }
+}
diff --git a/jnpf-admin/src/main/java/jnpf/aop/PermissionAdminAspect.java b/jnpf-admin/src/main/java/jnpf/aop/PermissionAdminAspect.java
new file mode 100644
index 0000000..adf22d1
--- /dev/null
+++ b/jnpf-admin/src/main/java/jnpf/aop/PermissionAdminAspect.java
@@ -0,0 +1,111 @@
+package jnpf.aop;
+
+import jnpf.annotation.OrganizeAdminIsTrator;
+import jnpf.base.ActionResult;
+import jnpf.base.UserInfo;
+import jnpf.constant.MsgCode;
+import jnpf.constant.PermissionConstant;
+import jnpf.permission.entity.OrganizeRelationEntity;
+import jnpf.permission.model.authorize.SaveBatchForm;
+import jnpf.permission.service.OrganizeRelationService;
+import jnpf.util.PermissionAspectUtil;
+import jnpf.util.UserProvider;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021/3/15 17:12
+ */
+@Slf4j
+@Aspect
+@Component
+public class PermissionAdminAspect implements PermissionAdminBase{
+
+ @Autowired
+ private UserProvider userProvider;
+ @Autowired
+ private OrganizeRelationService organizeRelationService;
+
+ /**
+ * 分级管理切点
+ */
+ @Pointcut("@annotation(jnpf.annotation.OrganizeAdminIsTrator)")
+ public void pointcut() {
+ }
+
+ /**
+ * 分级管理切点
+ *
+ * @param pjp
+ * @return
+ * @throws Throwable
+ */
+ @Around("pointcut()")
+ public Object around(ProceedingJoinPoint pjp) throws Throwable {
+ return PermissionAdminBase.permissionCommon(pjp, userProvider, this);
+ }
+
+ @Override
+ public Boolean detailPermission(ProceedingJoinPoint pjp, String operatorUserId, String methodName){
+ switch (methodName) {
+ case PermissionConstant.METHOD_SAVE:
+ if(userProvider.get().getIsAdministrator()){
+ return true;
+ }
+ String roleId = (String) pjp.getArgs()[0];
+ List orgIdList = organizeRelationService.getRelationListByRoleId(roleId).stream().map(OrganizeRelationEntity::getOrganizeId).collect(Collectors.toList());
+ StringBuilder orgId = new StringBuilder();
+ orgIdList.stream().forEach(t->{
+ orgId.append(t + ",");
+ });
+ return PermissionAspectUtil.getPermitByOrgId(
+ // 操作目标对象组织ID集合
+ orgId.toString(),
+ operatorUserId,
+ PermissionConstant.METHOD_UPDATE);
+ case PermissionConstant.METHOD_SAVE_BATCH:
+ // 修改为只有超管才能操作
+ if(userProvider.get().getIsAdministrator()){
+ return true;
+ }
+ // 得到角色id
+ SaveBatchForm saveBatchForm = (SaveBatchForm) pjp.getArgs()[0];
+ List list = Arrays.asList(saveBatchForm.getRoleIds());
+ if (list.size() == 0) {
+ list = new ArrayList<>();
+ list.add("");
+ }
+ // 得到组织id
+ List orgIdLists = organizeRelationService.getRelationListByRoleIdList(list).stream().map(OrganizeRelationEntity::getOrganizeId).collect(Collectors.toList());
+ StringBuilder orgIds = new StringBuilder();
+ orgIdLists.stream().forEach(t->{
+ orgIds.append(t + ",");
+ });
+ return PermissionAspectUtil.getPermitByOrgId(
+ // 操作目标对象组织ID集合
+ orgIds.toString(),
+ operatorUserId,
+ PermissionConstant.METHOD_UPDATE);
+ case PermissionConstant.METHOD_UPDATE:
+ //判断是否有当前组织的修改权限
+ String organizeId = String.valueOf(pjp.getArgs()[0]);
+ return PermissionAspectUtil.containPermission(organizeId, operatorUserId, methodName);
+ default:
+ return false;
+ }
+ }
+
+}
diff --git a/jnpf-admin/src/main/java/jnpf/aop/PermissionAdminBase.java b/jnpf-admin/src/main/java/jnpf/aop/PermissionAdminBase.java
new file mode 100644
index 0000000..492ecc3
--- /dev/null
+++ b/jnpf-admin/src/main/java/jnpf/aop/PermissionAdminBase.java
@@ -0,0 +1,40 @@
+package jnpf.aop;
+
+import jnpf.base.ActionResult;
+import jnpf.base.UserInfo;
+import jnpf.constant.MsgCode;
+import jnpf.util.UserProvider;
+import org.aspectj.lang.ProceedingJoinPoint;
+
+public interface PermissionAdminBase{
+
+ /**
+ * 详细的权限判断
+ * @param pjp AOP切点参数
+ * @param operatorUserId 操作者对象
+ */
+ Boolean detailPermission(ProceedingJoinPoint pjp, String operatorUserId, String methodName);
+
+ /**
+ * 管理者权限判断
+ *
+ * @param userProvider 操作者对象
+ */
+ static Object permissionCommon(ProceedingJoinPoint pjp, UserProvider userProvider, PermissionAdminBase permissionAdminBase) throws Throwable {
+ // 获取用户信息
+ UserInfo operatorUser = userProvider.get();
+ // 是否是管理员
+ if(operatorUser.getIsAdministrator()){
+ return pjp.proceed();
+ }else {
+ // 获取方法名
+ String methodName = pjp.getSignature().getName();
+ // 具体方法权限
+ if(permissionAdminBase.detailPermission(pjp, operatorUser.getUserId(),methodName)){
+ return pjp.proceed();
+ }
+ }
+ return ActionResult.fail(MsgCode.FA021.get());
+ }
+
+}
diff --git a/jnpf-admin/src/main/java/jnpf/aop/PermissionOrgAspect.java b/jnpf-admin/src/main/java/jnpf/aop/PermissionOrgAspect.java
new file mode 100644
index 0000000..c40a6bc
--- /dev/null
+++ b/jnpf-admin/src/main/java/jnpf/aop/PermissionOrgAspect.java
@@ -0,0 +1,121 @@
+package jnpf.aop;
+
+import jnpf.constant.PermissionConstant;
+import jnpf.permission.entity.OrganizeEntity;
+import jnpf.permission.model.organize.OrganizeCrForm;
+import jnpf.permission.model.organize.OrganizeDepartCrForm;
+import jnpf.permission.model.organize.OrganizeDepartUpForm;
+import jnpf.permission.model.organize.OrganizeUpForm;
+import jnpf.permission.service.OrganizeService;
+import jnpf.util.PermissionAspectUtil;
+import jnpf.util.UserProvider;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.StringJoiner;
+
+/**
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021/3/15 17:12
+ */
+@Slf4j
+@Aspect
+@Component
+public class PermissionOrgAspect implements PermissionAdminBase {
+
+ @Autowired
+ private UserProvider userProvider;
+ @Autowired
+ private OrganizeService organizeService;
+
+ /**
+ * 分级管理切点
+ */
+ @Pointcut("@annotation(jnpf.annotation.OrganizePermission)")
+ public void pointcut() {
+ }
+
+ /**
+ * 分级管理切点
+ *
+ * @param pjp
+ * @return
+ * @throws Throwable
+ */
+ @Around("pointcut()")
+ public Object around(ProceedingJoinPoint pjp) throws Throwable {
+ return PermissionAdminBase.permissionCommon(pjp, userProvider, this);
+ }
+
+ @Override
+ public Boolean detailPermission(ProceedingJoinPoint pjp, String operatorUserId, String methodName) {
+ switch (methodName) {
+ case PermissionConstant.METHOD_CREATE:
+ return PermissionAspectUtil.getPermitByOrgIds(
+ // 操作目标对象表单对象
+ ((OrganizeCrForm) pjp.getArgs()[0]).getParentId(),
+ operatorUserId,
+ PermissionConstant.METHOD_CREATE);
+ case PermissionConstant.METHOD_CREATE_DEPARTMENT:
+ return PermissionAspectUtil.getPermitByOrgIds(
+ // 操作目标对象表单对象
+ ((OrganizeDepartCrForm) pjp.getArgs()[0]).getParentId(),
+ operatorUserId,
+ PermissionConstant.METHOD_CREATE);
+ case PermissionConstant.METHOD_UPDATE:
+ // 当前组织id
+ String orgId = (String) pjp.getArgs()[0];
+ // 当前组织父级id
+ OrganizeEntity info = organizeService.getInfo(orgId);
+ // 修改后的id
+ OrganizeUpForm organizeUpForm = (OrganizeUpForm) pjp.getArgs()[1];
+ StringJoiner stringJoiner = new StringJoiner(",");
+ stringJoiner.add(orgId);
+ if (!organizeUpForm.getParentId().equals(info.getParentId()) && !"-1".equals(info.getParentId())) {
+ stringJoiner.add(info.getParentId());
+ }
+ if (!organizeUpForm.getParentId().equals(info.getParentId()) && !"-1".equals(organizeUpForm.getParentId())) {
+ stringJoiner.add(organizeUpForm.getParentId());
+ }
+ return PermissionAspectUtil.getPermitByOrgIds(
+ // 操作目标对象ID
+ stringJoiner.toString(),
+ operatorUserId,
+ PermissionConstant.METHOD_UPDATE);
+ case PermissionConstant.METHOD_UPDATE_DEPARTMENT:
+ // 当前组织id
+ String orgIds = (String) pjp.getArgs()[0];
+ // 当前组织父级id
+ OrganizeEntity infos = organizeService.getInfo(orgIds);
+ // 修改后的id
+ OrganizeDepartUpForm organizeDepartUpForm = (OrganizeDepartUpForm) pjp.getArgs()[1];
+ StringJoiner stringJoiners = new StringJoiner(",");
+ stringJoiners.add(orgIds);
+ if (!organizeDepartUpForm.getParentId().equals(infos.getParentId())) {
+ stringJoiners.add(infos.getParentId());
+ stringJoiners.add(organizeDepartUpForm.getParentId());
+ }
+ return PermissionAspectUtil.getPermitByOrgIds(
+ // 操作目标对象ID
+ stringJoiners.toString(),
+ operatorUserId,
+ PermissionConstant.METHOD_UPDATE);
+ case PermissionConstant.METHOD_DELETE:
+ case PermissionConstant.METHOD_DELETE_DEPARTMENT:
+ return PermissionAspectUtil.getPermitByOrgIds(
+ // 操作目标对象ID
+ pjp.getArgs()[0].toString(),
+ operatorUserId,
+ PermissionConstant.METHOD_DELETE);
+ default:
+ return false;
+ }
+ }
+}
diff --git a/jnpf-admin/src/main/java/jnpf/aop/PermissionPositionAspect.java b/jnpf-admin/src/main/java/jnpf/aop/PermissionPositionAspect.java
new file mode 100644
index 0000000..388d0dc
--- /dev/null
+++ b/jnpf-admin/src/main/java/jnpf/aop/PermissionPositionAspect.java
@@ -0,0 +1,93 @@
+package jnpf.aop;
+
+import jnpf.constant.PermissionConstant;
+import jnpf.permission.entity.PositionEntity;
+import jnpf.permission.model.position.PositionCrForm;
+import jnpf.permission.model.position.PositionUpForm;
+import jnpf.permission.service.OrganizeService;
+import jnpf.permission.service.PositionService;
+import jnpf.util.PermissionAspectUtil;
+import jnpf.util.UserProvider;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021/3/15 17:12
+ */
+@Slf4j
+@Aspect
+@Component
+public class PermissionPositionAspect implements PermissionAdminBase{
+
+ @Autowired
+ private UserProvider userProvider;
+ @Autowired
+ private PositionService positionService;
+ @Autowired
+ private OrganizeService organizeService;
+
+ /**
+ * 分级管理切点
+ */
+ @Pointcut("@annotation(jnpf.annotation.PositionPermission)")
+ public void pointcut() {
+ }
+
+ /**
+ * 分级管理切点
+ *
+ * @param pjp
+ * @return
+ * @throws Throwable
+ */
+ @Around("pointcut()")
+ public Object around(ProceedingJoinPoint pjp) throws Throwable {
+ return PermissionAdminBase.permissionCommon(pjp, userProvider, this);
+ }
+
+ @Override
+ public Boolean detailPermission(ProceedingJoinPoint pjp, String operatorUserId, String methodName) {
+ switch (methodName){
+ case PermissionConstant.METHOD_CREATE:
+ return PermissionAspectUtil.getPermitByOrgId(
+ // 操作目标对象组织ID集合
+ ((PositionCrForm) pjp.getArgs()[0]).getOrganizeId(),
+ operatorUserId,
+ methodName);
+ case PermissionConstant.METHOD_UPDATE:
+ // 得到岗位信息后,判断是否有修改前的权限
+ PositionEntity info = positionService.getInfo(((String) pjp.getArgs()[0]));
+ if (PermissionAspectUtil.getPermitByOrgId(
+ // 操作目标对象组织ID集合
+ info.getOrganizeId(),
+ operatorUserId,
+ methodName)) {
+ return PermissionAspectUtil.getPermitByOrgId(
+ // 操作目标对象组织ID集合
+ ((PositionUpForm) pjp.getArgs()[1]).getOrganizeId(),
+ operatorUserId,
+ methodName);
+ }
+ return false;
+ case PermissionConstant.METHOD_DELETE:
+ // 获取岗位所关联的组织ID字符串
+ String positionId = String.valueOf(pjp.getArgs()[0]);
+ String orgIds = organizeService.getInfo(positionService.getInfo(positionId).getOrganizeId()).getId();
+ return PermissionAspectUtil.getPermitByOrgId(
+ // 操作目标对象组织ID集合
+ orgIds,
+ operatorUserId,
+ PermissionConstant.METHOD_DELETE);
+ default:
+ return false;
+ }
+ }
+}
diff --git a/jnpf-admin/src/main/java/jnpf/aop/PermissionRoleAspect.java b/jnpf-admin/src/main/java/jnpf/aop/PermissionRoleAspect.java
new file mode 100644
index 0000000..7db8191
--- /dev/null
+++ b/jnpf-admin/src/main/java/jnpf/aop/PermissionRoleAspect.java
@@ -0,0 +1,155 @@
+package jnpf.aop;
+
+import jnpf.constant.PermissionConstant;
+import jnpf.permission.entity.OrganizeRelationEntity;
+import jnpf.permission.entity.RoleEntity;
+import jnpf.permission.model.role.RoleCrForm;
+import jnpf.permission.model.role.RoleUpForm;
+import jnpf.permission.service.OrganizeRelationService;
+import jnpf.permission.service.PositionService;
+import jnpf.permission.service.RoleService;
+import jnpf.util.PermissionAspectUtil;
+import jnpf.util.UserProvider;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
+/**
+ * 角色操作权限
+ *
+ * @author JNPF开发平台组 YanYu
+ * @version V3.2.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2022/2/10
+ */
+@Slf4j
+@Aspect
+@Component
+public class PermissionRoleAspect implements PermissionAdminBase {
+
+ @Autowired
+ private UserProvider userProvider;
+ @Autowired
+ private RoleService roleService;
+ @Autowired
+ private OrganizeRelationService organizeRelationService;
+
+ /**
+ * 分级管理切点
+ */
+ @Pointcut("@annotation(jnpf.annotation.RolePermission)")
+ public void pointcut() {
+ }
+
+ /**
+ * 分级管理切点
+ *
+ * @param pjp
+ * @return
+ * @throws Throwable
+ */
+ @Around("pointcut()")
+ public Object around(ProceedingJoinPoint pjp) throws Throwable {
+ return PermissionAdminBase.permissionCommon(pjp, userProvider, this);
+ }
+
+ @Override
+ public Boolean detailPermission(ProceedingJoinPoint pjp, String operatorUserId, String methodName) {
+ boolean flag = false;
+ switch (methodName) {
+ case PermissionConstant.METHOD_CREATE:
+ RoleCrForm roleCrForm = (RoleCrForm) pjp.getArgs()[0];
+ if (!checkAdminGlobal(roleCrForm.getGlobalMark(), userProvider)) {
+ return PermissionAspectUtil.getPermitByOrgId(
+ // 操作目标对象组织ID集合
+ getOrganize(roleCrForm.getOrganizeIdsTree()),
+ operatorUserId,
+ PermissionConstant.METHOD_CREATE);
+ }
+ return true;
+ case PermissionConstant.METHOD_UPDATE:
+ RoleUpForm roleUpForm = (RoleUpForm) pjp.getArgs()[0];
+ // 非管理员情况下
+ if (!checkAdminGlobal(roleUpForm.getGlobalMark(), userProvider)) {
+ // 得到以前的组织id
+ String roleId = (String) pjp.getArgs()[1];
+ List relationListByRoleId = organizeRelationService.getRelationListByRoleId(roleId).stream().map(OrganizeRelationEntity::getOrganizeId).collect(Collectors.toList());
+ StringJoiner stringJoiners = new StringJoiner(",");
+ relationListByRoleId.forEach(t -> {
+ stringJoiners.add(t);
+ });
+ if (PermissionAspectUtil.getPermitByOrgId(
+ // 操作目标对象组织ID集合
+ stringJoiners.toString(),
+ operatorUserId,
+ PermissionConstant.METHOD_UPDATE)) {
+ return PermissionAspectUtil.getPermitByOrgId(
+ // 操作目标对象组织ID集合
+ getOrganize(roleUpForm.getOrganizeIdsTree()),
+ operatorUserId,
+ PermissionConstant.METHOD_UPDATE);
+ }
+ return false;
+ }
+ return true;
+ case PermissionConstant.METHOD_DELETE:
+ String roleId = pjp.getArgs()[0].toString();
+ RoleEntity roleEntity = roleService.getInfo(roleId);
+ // 获取角色关联的组织信息
+ List relationListByRoleId = organizeRelationService.getRelationListByRoleId(roleId);
+ StringBuilder orgId = new StringBuilder();
+ relationListByRoleId.stream().forEach(t->{
+ orgId.append(t.getOrganizeId() + ",");
+ });
+ if (roleEntity != null && !checkAdminGlobal(roleEntity.getGlobalMark(), userProvider)) {
+ return PermissionAspectUtil.getPermitByOrgId(
+ // 操作目标对象组织ID集合
+ orgId.toString(),
+ operatorUserId,
+ PermissionConstant.METHOD_DELETE);
+ }
+ return true;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * 转成组织id字符串
+ * @param orgIdsTree
+ * @return
+ */
+ private String getOrganize(List> orgIdsTree) {
+ StringBuilder orgIds = new StringBuilder();
+ for (List list : orgIdsTree) {
+ if (list.size() > 0) {
+ String orgId = list.get(list.size() - 1);
+ orgIds.append(orgId + ",");
+ }
+ }
+ return orgIds.toString();
+ }
+
+ /**
+ * 全局角色只能超管来操作
+ *
+ * @param globalMark 全局标识 1:全局 0: 非全局
+ * @param userProvider 操作者
+ */
+ private Boolean checkAdminGlobal(Integer globalMark, UserProvider userProvider) {
+ if (globalMark != null && globalMark == 1) {
+ return userProvider.get().getIsAdministrator();
+ }
+ return false;
+ }
+
+}
diff --git a/jnpf-admin/src/main/java/jnpf/aop/PermissionUserAspect.java b/jnpf-admin/src/main/java/jnpf/aop/PermissionUserAspect.java
new file mode 100644
index 0000000..6208ef2
--- /dev/null
+++ b/jnpf-admin/src/main/java/jnpf/aop/PermissionUserAspect.java
@@ -0,0 +1,151 @@
+package jnpf.aop;
+
+import jnpf.constant.PermissionConst;
+import jnpf.constant.PermissionConstant;
+import jnpf.permission.entity.OrganizeRelationEntity;
+import jnpf.permission.entity.UserRelationEntity;
+import jnpf.permission.model.user.form.UserCrForm;
+import jnpf.permission.model.user.form.UserUpForm;
+import jnpf.permission.model.userrelation.UserRelationForm;
+import jnpf.permission.service.*;
+import jnpf.util.PermissionAspectUtil;
+import jnpf.util.UserProvider;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
+/**
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021/3/15 17:12
+ */
+@Slf4j
+@Aspect
+@Component
+public class PermissionUserAspect implements PermissionAdminBase{
+
+ @Autowired
+ private UserProvider userProvider;
+ @Autowired
+ private OrganizeRelationService organizeRelationService;
+ @Autowired
+ private PositionService positionService;
+ @Autowired
+ private UserRelationService userRelationService;
+
+ /**
+ * 分级管理切点
+ */
+ @Pointcut("@annotation(jnpf.annotation.UserPermission)")
+ public void pointcut() {
+ }
+
+ /**
+ * 分级管理切点
+ *
+ * @param pjp
+ * @return
+ * @throws Throwable
+ */
+ @Around("pointcut()")
+ public Object around(ProceedingJoinPoint pjp) throws Throwable {
+ return PermissionAdminBase.permissionCommon(pjp, userProvider, this);
+ }
+
+ @Override
+ public Boolean detailPermission(ProceedingJoinPoint pjp, String operatorUserId, String methodName) {
+ switch (methodName){
+ case PermissionConstant.METHOD_CREATE:
+ UserCrForm userCrForm = (UserCrForm) pjp.getArgs()[0];
+ return PermissionAspectUtil.getPermitByOrgId(
+ // 操作目标对象组织ID集合
+ userCrForm.getOrganizeId(),
+ operatorUserId,
+ PermissionConstant.METHOD_CREATE);
+ case PermissionConstant.METHOD_UPDATE:
+ // 得到修改的用户以前的信息
+ String userId = (String) pjp.getArgs()[0];
+ List collect = userRelationService.getListByUserId(userId, PermissionConst.ORGANIZE).stream().map(UserRelationEntity::getObjectId).collect(Collectors.toList());
+ StringJoiner stringJoiner = new StringJoiner(",");
+ collect.forEach(t -> {
+ stringJoiner.add(t);
+ });
+ if (PermissionAspectUtil.getPermitByOrgId(
+ // 操作目标对象组织ID集合
+ stringJoiner.toString(),
+ operatorUserId,
+ PermissionConstant.METHOD_UPDATE)) {
+ return PermissionAspectUtil.getPermitByOrgId(
+ // 操作目标对象组织ID集合
+ ((UserUpForm) pjp.getArgs()[1]).getOrganizeId(),
+ operatorUserId,
+ PermissionConstant.METHOD_UPDATE);
+ }
+ return false;
+ case PermissionConstant.METHOD_MODIFY_PW:
+ return PermissionAspectUtil.getPermitByUserId(
+ // 操作目标对象的ID
+ String.valueOf(pjp.getArgs()[0]),
+ operatorUserId,
+ PermissionConstant.METHOD_UPDATE);
+ case PermissionConstant.METHOD_DELETE:
+ return PermissionAspectUtil.getPermitByUserId(
+ // 操作目标对象的ID
+ pjp.getArgs()[0].toString(),
+ operatorUserId,
+ PermissionConstant.METHOD_DELETE);
+ case PermissionConstant.METHOD_SAVE:
+ String objId = pjp.getArgs()[0].toString();
+ UserRelationForm userRelationForm = (UserRelationForm)pjp.getArgs()[1];
+
+ List orgIds = new ArrayList<>();
+ if(userRelationForm.getObjectType().equals(PermissionConst.ROLE)){
+ // 角色目前修改为只有超管才能够修改
+ if(userProvider.get().getIsAdministrator()){
+ return true;
+ }
+ orgIds.addAll(organizeRelationService.getRelationListByRoleId(objId).stream().map(OrganizeRelationEntity::getOrganizeId).collect(Collectors.toList()));
+ return PermissionAspectUtil.getPermitByOrgId(
+ // 操作目标对象组织ID集合
+ String.join(",", orgIds),
+ operatorUserId,
+ PermissionConstant.METHOD_UPDATE);
+ }else {
+ if(userRelationForm.getObjectType().equals(PermissionConst.GROUP)) {
+ return true;
+ }
+ if(userRelationForm.getObjectType().equals(PermissionConst.POSITION)) {
+ orgIds.add(positionService.getInfo(objId).getOrganizeId());
+ }
+ return PermissionAspectUtil.getPermitByOrgId(
+ String.join(",", orgIds),
+ operatorUserId,
+ PermissionConstant.METHOD_UPDATE);
+ }
+ case PermissionConstant.METHOD_DELETE_SOCIALS:
+ if(pjp.getArgs()[0].toString().equals(operatorUserId)){return true;}
+ return PermissionAspectUtil.getPermitByUserId(
+ // 操作目标对象的ID
+ pjp.getArgs()[0].toString(),
+ operatorUserId,
+ PermissionConstant.METHOD_UPDATE);
+ default:
+ return false;
+ }
+ }
+
+
+
+
+
+}
diff --git a/jnpf-admin/src/main/java/jnpf/aop/RequestLogAspect.java b/jnpf-admin/src/main/java/jnpf/aop/RequestLogAspect.java
new file mode 100644
index 0000000..c1a9be3
--- /dev/null
+++ b/jnpf-admin/src/main/java/jnpf/aop/RequestLogAspect.java
@@ -0,0 +1,202 @@
+package jnpf.aop;
+
+import jnpf.base.LogSortEnum;
+import jnpf.base.UserInfo;
+import jnpf.config.ConfigValueUtil;
+import jnpf.entity.LogEntity;
+import jnpf.service.LogService;
+import jnpf.util.*;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+import jnpf.annotation.HandleLog;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.lang.reflect.Method;
+import java.util.Date;
+import java.util.concurrent.Executor;
+
+/**
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021/3/15 17:12
+ */
+@Slf4j
+@Aspect
+@Component
+@Order(2)
+public class RequestLogAspect {
+
+ @Autowired
+ private ConfigValueUtil configValueUtil;
+ @Autowired
+ private LogService logService;
+ @Autowired
+ private Executor executor;
+
+ @Pointcut("(execution(* jnpf.*.controller.*.*(..)) || execution(* jnpf.message.websocket.WebSocket.*(..)))&&!execution(* jnpf.controller.UtilsController.*(..)) ")
+ public void requestLog() {
+
+ }
+
+ @Around("requestLog()")
+ public Object doAroundService(ProceedingJoinPoint pjp) throws Throwable {
+ long startTime = System.currentTimeMillis();
+ Object obj = pjp.proceed();
+ long costTime = System.currentTimeMillis() - startTime;
+ UserInfo userInfo = UserProvider.getUser();
+ if(userInfo.getUserId() != null) {
+ printLog(userInfo, costTime);
+ try {
+ // 判断是否需要操作日志
+ MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
+ // 得到请求参数
+ Object[] args = pjp.getArgs();
+ // 得到请求方法
+ Method method = methodSignature.getMethod();
+ HandleLog methodAnnotation = method.getAnnotation(HandleLog.class);
+ if (methodAnnotation != null) {
+ String moduleName = methodAnnotation.moduleName();
+ String requestMethod = methodAnnotation.requestMethod();
+ handleLog(userInfo, costTime, obj, moduleName, requestMethod, args);
+ }
+ } catch (Exception e) {
+ log.error("记录操作日志发生错误:" + e.getMessage());
+ }
+ }
+ return obj;
+ }
+
+ /**
+ * 请求日志
+ *
+ * @param userInfo
+ * @param costTime
+ */
+ private void printLog(UserInfo userInfo, long costTime) {
+ LogEntity entity = new LogEntity();
+ entity.setId(RandomUtil.uuId());
+ entity.setType(LogSortEnum.Request.getCode());
+ entity.setUserId(userInfo.getUserId());
+ entity.setUserName(userInfo.getUserName() + "/" + userInfo.getUserAccount());
+ //请求耗时
+ entity.setRequestDuration((int) costTime);
+ entity.setRequestUrl(ServletUtil.getRequest().getServletPath());
+ entity.setRequestMethod(ServletUtil.getRequest().getMethod());
+ entity.setIpAddress(IpUtil.getIpAddr());
+ entity.setCreatorTime(new Date());
+ entity.setPlatForm(ServletUtil.getUserAgent());
+ executor.execute(()->{
+ logService.save(entity);
+ });
+ }
+
+ /**
+ * 添加操作日志
+ *
+ * @param userInfo 用户信息
+ * @param costTime 操作耗时
+ * @param obj 请求结果
+ * @param moduleName 模块名称
+ * @param requestMethod 请求方法
+ * @param arg 请求参数
+ */
+ private void handleLog(UserInfo userInfo, long costTime, Object obj, String moduleName, String requestMethod, Object[] arg) {
+ LogEntity entity = new LogEntity();
+ entity.setId(RandomUtil.uuId());
+ entity.setType(LogSortEnum.Operate.getCode());
+ entity.setUserId(userInfo.getUserId());
+ entity.setUserName(userInfo.getUserName() + "/" + userInfo.getUserAccount());
+ //请求耗时
+ entity.setRequestDuration((int) costTime);
+ entity.setRequestMethod(requestMethod);
+ entity.setIpAddress(IpUtil.getIpAddr());
+ entity.setCreatorTime(new Date());
+ // 请求设备
+ entity.setPlatForm(ServletUtil.getUserAgent());
+ // 操作模块
+ entity.setModuleName(moduleName);
+ // 操作记录
+ try {
+ // 定义字符串
+ StringBuilder stringBuilder = new StringBuilder();
+ for (Object o : arg) {
+ // 如果是MultipartFile则为导入
+ if (o instanceof MultipartFile) {
+ stringBuilder.append("{\"originalFilename\":\"" + ((MultipartFile) o).getOriginalFilename() + "\",");
+ stringBuilder.append("\"contentType\":\"" + ((MultipartFile) o).getContentType() + "\",");
+ stringBuilder.append("\"name\":\"" + ((MultipartFile) o).getName() + "\",");
+ stringBuilder.append("\"resource\":\"" + ((MultipartFile) o).getResource() + "\",");
+ stringBuilder.append("\"size\":\"" + ((MultipartFile) o).getSize() + "\"}");
+ }
+ }
+ if (stringBuilder.length() > 0) {
+ entity.setJsons(requestMethod + "应用【" + stringBuilder + "】【" + obj + "】" );
+ } else {
+ entity.setJsons(requestMethod + "应用【" + JsonUtil.getObjectToString(arg) + "】【" + obj + "】" );
+ }
+ } catch (Exception e) {
+ entity.setJsons(requestMethod + "应用【" + arg + "】【" + obj + "】" );
+ }
+ executor.execute(()->{
+ logService.save(entity);
+ });
+ }
+
+/// 后面可能会用
+// /**
+// * 判断是否为导入导出
+// *
+// * @return
+// */
+// private String getRequestMethod() {
+// //得到请求方式
+// String methodType = ServletUtil.getRequest().getMethod();
+// // 得到当前请求的尾缀
+// String endWith = null;
+// String servletPath = ServletUtil.getServletPath();
+// if (StringUtil.isNotEmpty(servletPath)) {
+// String[] path = servletPath.split("/");
+// int length = path.length;
+// if (length > 5) {
+// endWith = path[length - 2] + "/" + path[length - 1];
+// }
+// }
+// // 如果是GET请求且请求后缀是'/Action/Export'则判定为导出
+// if (HandleMethodEnum.GET.getRequestType().equals(methodType)) {
+// methodType = "Action/Export".equals(endWith) ? "EXPORT" : "GET";
+// } else if (HandleMethodEnum.POST.getRequestType().equals(methodType)) {
+// methodType = "Action/Import".equals(endWith) ? "IMPORT" : "GET";
+// }
+// return methodType;
+// }
+// /**
+// * 判断是否为导入导出
+// *
+// * @return
+// */
+// private String getRequestModuleName() {
+// //得到Url
+// String requestURI = ServletUtil.getRequest().getRequestURI();
+// // 取模块名
+// if (StringUtil.isNotEmpty(requestURI)) {
+// String[] split = requestURI.split("/");
+// if (split.length > 2) {
+// String url = split[1];
+// // 得到所在模块
+// String moduleName = HandleModuleEnum.getModuleByURL(url);
+// return moduleName;
+// }
+// }
+// return "";
+// }
+///
+
+}
diff --git a/jnpf-admin/src/main/java/jnpf/aop/VisiualOpaAspect.java b/jnpf-admin/src/main/java/jnpf/aop/VisiualOpaAspect.java
new file mode 100644
index 0000000..5ab4503
--- /dev/null
+++ b/jnpf-admin/src/main/java/jnpf/aop/VisiualOpaAspect.java
@@ -0,0 +1,49 @@
+package jnpf.aop;
+
+import jnpf.util.RedisUtil;
+import jnpf.util.ServletUtil;
+import jnpf.util.UserProvider;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.annotation.After;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * 可视化开发缓存数据处理
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021/3/15 17:12
+ */
+@Slf4j
+@Aspect
+@Component
+public class VisiualOpaAspect {
+
+ @Autowired
+ UserProvider userProvider;
+ @Autowired
+ private RedisUtil redisUtil;
+ @Pointcut("(execution(* jnpf.onlinedev.controller.VisualdevModelDataController.*(..))) || execution(* jnpf.onlinedev.controller.VisualdevModelAppController.*(..)))" +
+ "|| execution(* jnpf.generater.controller.VisualdevGenController.*(..)))")
+ public void visiualOpa() {
+
+ }
+
+ @After("visiualOpa()")
+ public void doAroundService(){
+ String method=ServletUtil.getRequest().getMethod().toLowerCase();
+ if("put".equals(method)||"delete".equals(method)||"post".equals(method)){
+ Set allKey=new HashSet<>(16);
+ allKey.addAll(redisUtil.getAllVisiualKeys());
+ for(String key:allKey){
+ redisUtil.remove(key);
+ }
+ }
+ }
+ }
diff --git a/jnpf-admin/src/main/java/jnpf/constant/PermissionConstant.java b/jnpf-admin/src/main/java/jnpf/constant/PermissionConstant.java
new file mode 100644
index 0000000..6b25535
--- /dev/null
+++ b/jnpf-admin/src/main/java/jnpf/constant/PermissionConstant.java
@@ -0,0 +1,73 @@
+package jnpf.constant;
+
+/**
+ * 分级管理常量
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司(https://www.jnpfsoft.com)
+ * @date 2021-11-01
+ */
+public class PermissionConstant {
+
+ /**
+ * 创建方法
+ */
+ public static final String METHOD_CREATE = "create";
+
+ /**
+ * 编辑方法
+ */
+ public static final String METHOD_UPDATE = "update";
+
+ /**
+ * 删除方法
+ */
+ public static final String METHOD_DELETE = "delete";
+
+ /**
+ * 更新状态
+ */
+ public static final String METHOD_DISABLE = "disable";
+
+ /**
+ * 创建方法
+ */
+ public static final String METHOD_CREATE_DEPARTMENT = "createDepartment";
+
+ /**
+ * 编辑方法
+ */
+ public static final String METHOD_UPDATE_DEPARTMENT = "updateDepartment";
+
+ /**
+ * 删除方法
+ */
+ public static final String METHOD_DELETE_DEPARTMENT = "deleteDepartment";
+
+ /**
+ * 保存方法
+ */
+ public static final String METHOD_SAVE = "save";
+ public static final String METHOD_SAVE_BATCH = "saveBatch";
+ /**
+ * 修改用户密码
+ */
+ public static final String METHOD_MODIFY_PW = "modifyPassword";
+
+ /**
+ * 拼接方法名
+ */
+ public static final String GET_METHOD_CREATE = "Add";
+ public static final String GET_METHOD_UPDATE = "Edit";
+ public static final String GET_METHOD_DELETE = "Delete";
+ public static final String GET_METHOD_SELECT = "Select";
+ public static final String GET_METHOD_THIS = "getThisLayer";
+ public static final String GET_METHOD_SUB = "getSubLayer";
+
+ /**
+ * 解除绑定方法
+ */
+ public static final String METHOD_DELETE_SOCIALS = "deleteSocials";
+
+}
diff --git a/jnpf-admin/src/main/java/jnpf/filter/AuthFilter.java b/jnpf-admin/src/main/java/jnpf/filter/AuthFilter.java
new file mode 100644
index 0000000..f509473
--- /dev/null
+++ b/jnpf-admin/src/main/java/jnpf/filter/AuthFilter.java
@@ -0,0 +1,115 @@
+package jnpf.filter;
+
+import cn.dev33.satoken.context.SaHolder;
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.filter.SaServletFilter;
+import cn.dev33.satoken.router.SaHttpMethod;
+import cn.dev33.satoken.router.SaRouter;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.util.SaResult;
+import jnpf.base.ActionResultCode;
+import jnpf.config.ConfigValueUtil;
+import jnpf.util.GatewayWhite;
+import jnpf.util.IpUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpHeaders;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * 网关验证token
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司(https://www.jnpfsoft.com)
+ * @date 2021-03-24
+ */
+@Slf4j
+@Configuration
+public class AuthFilter {
+
+ private static final String ALL = "*";
+ private static final String MAX_AGE = "18000L";
+
+ @Autowired
+ private ConfigValueUtil configValueUtil;
+
+ @Autowired
+ private GatewayWhite gatewayWhite;
+
+ // 注册 Sa-Token全局过滤器
+ @Bean
+ public SaServletFilter getSaReactorFilter(GatewayWhite gatewayWhite) {
+ return new SaServletFilter()
+ // 拦截地址
+ .addInclude("/**")
+ .setExcludeList(gatewayWhite.excludeUrl)
+ // 鉴权方法:每次访问进入
+ .setAuth(obj -> {
+ if(log.isInfoEnabled()){
+ log.info("请求路径: {}", SaHolder.getRequest().getRequestPath());
+ }
+ //拦截路径
+ SaRouter.match(gatewayWhite.blockUrl).match(o -> {
+ //禁止访问URL 排除白名单
+ String ip = getIpAddr();
+ for (String o1 : gatewayWhite.whiteIp) {
+ if(ip.startsWith(o1)){
+ return false;
+ }
+ }
+ log.info("非白名单IP访问限制接口:{}, {}", SaHolder.getRequest().getRequestPath(), ip);
+ return true;
+ }).back("接口无法访问");
+ //测试不验证 鉴权服务重启测试模式不清除Token就够了
+ //SaRouter.match((r)->"true".equals(configValueUtil.getTestVersion())).stop();
+ //白名单不拦截
+ SaRouter.match(gatewayWhite.whiteUrl).stop();
+ // 登录校验 -- 校验多租户管理模块TOKEN
+ //SaRouter.match("/api/tenant/**", r -> {
+ // SaManager.getStpLogic(AuthConsts.ACCOUNT_TYPE_TENANT).checkLogin();
+ //}).stop();
+ // 登录校验 -- 拦截所有路由
+ SaRouter.match("/**", r -> {
+ StpUtil.checkLogin();
+ }).stop();
+ }).setError(e -> {
+ SaHolder.getResponse().addHeader("Content-Type","application/json; charset=utf-8");
+ if(e instanceof NotLoginException){
+ return SaResult.error(ActionResultCode.SessionOverdue.getMessage()).setCode(ActionResultCode.SessionOverdue.getCode());
+ }
+ log.error(e.getMessage(), e);
+ return SaResult.error("系统异常.").setCode(ActionResultCode.Exception.getCode());
+ })
+ // 前置函数:在每次认证函数之前执行
+ .setBeforeAuth(obj -> {
+ HttpServletRequest request = (HttpServletRequest) SaHolder.getRequest().getSource();
+ // ---------- 设置跨域响应头 ----------
+ SaHolder.getResponse()
+ // 允许指定域访问跨域资源
+ .setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, request.getHeader(HttpHeaders.ORIGIN))
+ // 允许的header参数
+ .setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, ALL)
+ // 允许所有请求方式
+ .setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, ALL)
+ .setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true")
+ .setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, ALL)
+ // 有效时间
+ .setHeader(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
+
+ // 如果是预检请求,则立即返回到前端
+ SaRouter.match(SaHttpMethod.OPTIONS)
+ .back();
+ });
+ }
+
+ public static String getIpAddr() {
+ return IpUtil.getIpAddr();
+ }
+
+
+}
diff --git a/jnpf-admin/src/main/java/jnpf/util/GatewayWhite.java b/jnpf-admin/src/main/java/jnpf/util/GatewayWhite.java
new file mode 100644
index 0000000..160e2a4
--- /dev/null
+++ b/jnpf-admin/src/main/java/jnpf/util/GatewayWhite.java
@@ -0,0 +1,181 @@
+package jnpf.util;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 放行的url
+ * 由下方的URL列表加上配置里的URL组合
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司(https://www.jnpfsoft.com)
+ * @date 2021-03-24
+ */
+@Component
+@ConfigurationProperties("gateway")
+public class GatewayWhite {
+
+
+ /**
+ * 放行不记录
+ */
+ public List excludeUrl = new ArrayList<>();
+
+ /**
+ * 不验证Token, 记录访问
+ */
+ public List whiteUrl = new ArrayList<>();
+
+ /**
+ * 禁止访问
+ */
+ public List blockUrl = new ArrayList<>();
+
+ /**
+ * 禁止访问地址的白名单IP
+ * startsWith匹配, 访问IP.startsWith(whiteIP)
+ */
+ public List whiteIp = new ArrayList<>();
+
+ public GatewayWhite(){
+ interceptPath();
+ whitePath();
+ excludePath();
+ whiteIp();
+ }
+
+
+ public List getWhiteUrl() {
+ return new ArrayList<>(whiteUrl);
+ }
+
+ public List getBlockUrl() {
+ return new ArrayList<>(blockUrl);
+ }
+
+ public List getExcludeUrl() {
+ return new ArrayList<>(excludeUrl);
+ }
+
+ public List getWhiteIp() {
+ return new ArrayList<>(whiteIp);
+ }
+
+ public void setWhiteUrl(List whiteUrl) {
+ whitePath();
+ this.whiteUrl.addAll(whiteUrl);
+ }
+
+ public void setBlockUrl(List blockUrl) {
+ interceptPath();
+ this.blockUrl.addAll(blockUrl);
+ }
+
+ public void setExcludeUrl(List excludeUrl) {
+ excludePath();
+ this.excludeUrl.addAll(excludeUrl);
+ }
+
+ public void setWhiteIp(List whiteIp) {
+ whiteIp();
+ this.whiteIp.addAll(whiteIp);
+ }
+
+ private void interceptPath() {
+ blockUrl.clear();
+ blockUrl.add("/actuator/**");
+ blockUrl.add("/api/*/actuator/**");
+ blockUrl.add("/doc.html");
+ blockUrl.add("/swagger-resources/**");
+ blockUrl.add("/swagger-ui/**");
+ blockUrl.add("/api/*/v?/api-docs/*");
+ blockUrl.add("/v?/api-docs/*");
+ }
+
+ private void whitePath() {
+ whiteUrl.clear();
+ //oauth
+ whiteUrl.add("/api/oauth/Login/**");
+ whiteUrl.add("/api/oauth/Logout/**");
+ // APP
+ whiteUrl.add("/api/app/Version");
+
+ //websocket
+ whiteUrl.add("/api/message/websocket/*");
+ //大屏图片
+ whiteUrl.add("/api/file/VisusalImg/**");
+ whiteUrl.add("/api/blade-visual/map/data");
+ whiteUrl.add("/api/blade-visual/category/list");
+ whiteUrl.add("/api/blade-visual/visual/put-file/**");
+ //数据地图
+ whiteUrl.add("/api/system/DataMap/**");
+ //代码下载接口
+ whiteUrl.add("/api/visualdev/Generater/DownloadVisCode");
+ //多租户
+ whiteUrl.add("/api/tenant/DbName/**");
+ whiteUrl.add("/api/tenant/login");
+ whiteUrl.add("/api/tenant/logout");
+ //extend KK
+ whiteUrl.add("/api/extend/DocumentPreview/**");
+ //file模块不拦截
+ //文件下载接口
+ whiteUrl.add("/api/file/filedownload/**");
+ whiteUrl.add("/api/file/VisusalImg/**");
+ whiteUrl.add("/api/file/AppStartInfo/*");
+ whiteUrl.add("/api/file/IMVoice/*");
+ whiteUrl.add("/api/file/{type}/{fileName}");
+ whiteUrl.add("/api/file/IMImage/*");
+ whiteUrl.add("/api/file/Image/**");
+ whiteUrl.add("/api/file/DownloadModel");
+ whiteUrl.add("/api/file/Download/**");
+ whiteUrl.add("/api/file/ImageCode/**");
+
+ whiteUrl.add("/api/system/DictionaryData/*/Data/Selector");
+ whiteUrl.add("/api/datareport/pdf/show");
+ whiteUrl.add("/api/datareport/preview/loadPagePaper");
+ whiteUrl.add("/api/datareport/pdf");
+ whiteUrl.add("/api/datareport/word");
+ whiteUrl.add("/api/datareport/excel/**");
+ whiteUrl.add("/api/datareport/Data/*/Actions/Export");
+ //报表模板导入
+ whiteUrl.add("/api/datareport/import");
+ whiteUrl.add("/api/system/DataInterface/*/Actions/Response");
+ whiteUrl.add("/api/system/DataInterface/Actions/GetAuth");
+ //swagger3
+ whiteUrl.add("/doc.html");
+ whiteUrl.add("/webjars/**");
+ whiteUrl.add("/api/*/v?/api-docs/*");
+ whiteUrl.add("/v?/api-docs/*");
+ whiteUrl.add("/swagger-ui/**");
+ whiteUrl.add("/swagger-resources/**");
+
+ whiteUrl.add("/csrf");
+ whiteUrl.add("/api/oauth/ImageCode/**");
+ whiteUrl.add("/api/oauth/getConfig/*");
+ whiteUrl.add("/api/oauth/getLoginConfig");
+ whiteUrl.add("/api/oauth/getTicketStatus/*");
+ whiteUrl.add("/api/oauth/getTicket");
+
+ whiteUrl.add("/api/message/ShortLink/**");
+ whiteUrl.add("/api/message/WechatOpen/token/**");
+
+ //在线表单外链触发接口
+ whiteUrl.add("/api/visualdev/ShortLink/**");
+ }
+
+ private void excludePath(){
+ excludeUrl.clear();
+ excludeUrl.add("/favicon.ico");
+ excludeUrl.add("/api/message/websocket/*");
+ }
+
+ private void whiteIp(){
+ whiteIp.clear();
+ whiteIp.add("127.0.0.1");
+ }
+
+}
diff --git a/jnpf-admin/src/main/java/jnpf/util/PermissionAspectUtil.java b/jnpf-admin/src/main/java/jnpf/util/PermissionAspectUtil.java
new file mode 100644
index 0000000..169240a
--- /dev/null
+++ b/jnpf-admin/src/main/java/jnpf/util/PermissionAspectUtil.java
@@ -0,0 +1,165 @@
+package jnpf.util;
+
+import jnpf.constant.PermissionConstant;
+import jnpf.permission.entity.OrganizeAdministratorEntity;
+import jnpf.permission.entity.OrganizeEntity;
+import jnpf.permission.service.OrganizeAdministratorService;
+import jnpf.permission.service.OrganizeService;
+import jnpf.util.context.SpringContext;
+
+/**
+ * 分级管理工具类
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司(https://www.jnpfsoft.com)
+ * @date 2021-11-01
+ */
+public class PermissionAspectUtil {
+
+ private static final OrganizeService organizeService;
+ private static final OrganizeAdministratorService organizeAdministratorService;
+
+ static {
+ organizeService = SpringContext.getBean(OrganizeService.class);
+ organizeAdministratorService = SpringContext.getBean(OrganizeAdministratorService.class);
+ }
+
+ /**
+ * 判断是否存在修改前所在的组织的操作
+ *
+ * @param targetUserId 被操作目标对象ID
+ * @param operatorUsrId 操作者ID
+ * @param methodName 操作方法
+ */
+ public static Boolean getPermitByUserId(String targetUserId, String operatorUsrId, String methodName) {
+ for(OrganizeEntity organizeEntity : organizeService.getAllOrgByUserId(targetUserId)){
+ if (PermissionAspectUtil.containPermission(organizeEntity.getId(), operatorUsrId, methodName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 判断 操作者是否含有该组织的操作权限
+ *
+ * @param organizeId 被操作者所在组织ID
+ * @param operatorUserId 当前操作者用户对象ID
+ * @param methodName 操作类型:创建、编辑、删除
+ */
+ public static boolean containPermission(String organizeId, String operatorUserId, String methodName) {
+ OrganizeEntity organizeEntity = organizeService.getInfo(organizeId);
+ if (organizeEntity != null) {
+ // 当前用户的所有分级权限
+ OrganizeAdministratorEntity adminEntity = organizeAdministratorService.getOne(operatorUserId, organizeId);
+ if(permissionFlag(adminEntity, methodName, true)){
+ return true;
+ }
+ // 查看父级的组织权限是否含有子集权限
+ return parentPermission(organizeEntity.getParentId(), methodName, operatorUserId);
+ }
+ return false;
+ }
+
+ /**
+ * 判断是否存在修改前所在的组织的操作(拥有所有的组织权限才能操作)
+ *
+ * @param organizeIds 组织ID集合字符串
+ * @param operatorUsrId 操作者ID
+ * @param methodName 操作方法
+ */
+ public static Boolean getPermitByOrgIds(String organizeIds, String operatorUsrId, String methodName) {
+ boolean flag = true;
+ for (String organizeId : organizeIds.split(",")) {
+ flag = true;
+ flag = PermissionAspectUtil.containPermission(organizeId, operatorUsrId, methodName);
+ if (!flag) {
+ break;
+ }
+ }
+ return flag;
+ }
+
+ /**
+ * 判断是否可修改所在的组织的操作(只要有一个权限即可操作)
+ *
+ * @param organizeIds 组织ID集合字符串
+ * @param operatorUsrId 操作者ID
+ * @param methodName 操作方法
+ */
+ public static Boolean getPermitByOrgId(String organizeIds, String operatorUsrId, String methodName) {
+ for (String organizeId : organizeIds.split(",")) {
+ if (PermissionAspectUtil.containPermission(organizeId,operatorUsrId, methodName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 判断组织新建权限(从父级给的子集新建操作权限)
+ *
+ * @param organizeParentId
+ * @param methodName
+ * @param userId
+ * @return
+ */
+ private static boolean parentPermission(String organizeParentId, String methodName, String userId) {
+ // 得到父级组织
+ OrganizeEntity parentOrganizeEntity = organizeService.getInfo(organizeParentId);
+
+ if (parentOrganizeEntity != null) {
+ // 得到父级的权限
+ if(permissionFlag(organizeAdministratorService.getOne(userId, parentOrganizeEntity.getId()), methodName, false)){
+ return true;
+ }
+ // 当前正在判断的组织已经是顶级则无需递归
+ if (!"-1".equals(parentOrganizeEntity.getParentId())) {
+ return parentPermission(parentOrganizeEntity.getParentId(), methodName, userId);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 判断是否具有权限
+ * @param adminEntity 分级管理对象
+ * @param methodName 操作类型:创建、编辑、删除
+ * @param thisFlag true:当前组织 false:子组织
+ */
+ private static boolean permissionFlag(OrganizeAdministratorEntity adminEntity, String methodName, Boolean thisFlag) {
+ if (adminEntity != null) {
+ String methodType = "";
+ // 存在则验证是否有当前组织分级管理
+ try {
+ switch (methodName) {
+ case PermissionConstant.METHOD_CREATE:
+ // 创建权限
+ methodType = PermissionConstant.GET_METHOD_CREATE;
+ break;
+ case PermissionConstant.METHOD_UPDATE:
+ // 编辑权限
+ methodType = PermissionConstant.GET_METHOD_UPDATE;
+ break;
+ case PermissionConstant.METHOD_DELETE:
+ // 删除权限
+ methodType = PermissionConstant.GET_METHOD_DELETE;
+ break;
+ default:
+ break;
+ }
+ // 拼接方法名
+ String method = (thisFlag ? PermissionConstant.GET_METHOD_THIS : PermissionConstant.GET_METHOD_SUB) + methodType;
+ String selectMethod = (thisFlag ? PermissionConstant.GET_METHOD_THIS : PermissionConstant.GET_METHOD_SUB) + PermissionConstant.GET_METHOD_SELECT;
+ if ((int)OrganizeAdministratorEntity.class.getMethod(method).invoke(adminEntity) == 1 && (int)OrganizeAdministratorEntity.class.getMethod(selectMethod).invoke(adminEntity) == 1) {
+ return true;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/jnpf-admin/src/main/resources/AntiSamy_zh_CN.properties b/jnpf-admin/src/main/resources/AntiSamy_zh_CN.properties
new file mode 100644
index 0000000..fb19076
--- /dev/null
+++ b/jnpf-admin/src/main/resources/AntiSamy_zh_CN.properties
@@ -0,0 +1,34 @@
+# General
+error.size.toolarge=\u8F93\u5165\u592A\u5927\u3002\u5B9E\u9645\u7684\u8F93\u5165\u4E3A{0}\u5B57\u8282\u3002\u5141\u8BB8\u7684\u6700\u5927\u8F93\u5165\u4E3A{1}\u5B57\u8282\u3002
+error.comment.removed=\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6CE8\u91CA\u57DF\u5DF2\u88AB\u8FC7\u6EE4\u3002\u6CE8\u91CA\u57DF\u7684\u503C\u4E3A{0}
+# Tag related
+error.tag.notfound=\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6807\u8BB0{0}\u5DF2\u88AB\u8FC7\u6EE4\u3002\u6807\u8BB0\u7684\u5185\u5BB9\u4FDD\u5B58\u4E0D\u53D8\u3002
+error.tag.removed=\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6807\u8BB0{0}\u4E0D\u88AB\u5141\u8BB8\u3002\u6B64\u6807\u8BB0\u4E0D\u5E94\u8BE5\u5F71\u54CD\u8F93\u5165\u7684\u663E\u793A\u3002
+error.tag.filtered=\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6807\u8BB0{0}\u5DF2\u88AB\u8FC7\u6EE4\u3002\u6807\u8BB0\u7684\u5185\u5BB9\u4FDD\u5B58\u4E0D\u53D8\u3002
+error.tag.encoded=The {0} tag has been encoded for security reasons. The contents of the tag will remain in place.
+error.tag.empty=\u5728{0}\u7684\u6807\u7B7E\u662F\u7A7A\u7684\uFF0C\u56E0\u6B64\u6211\u4EEC\u65E0\u6CD5\u5904\u7406\u5B83\u3002\u8BE5\u90AE\u4EF6\u7684\u5176\u4F59\u90E8\u5206\u662F\u5B8C\u6574\u7684\uFF0C\u5176\u642C\u8FC1\u5E94\u8BE5\u6CA1\u6709\u4EFB\u4F55\u526F\u4F5C\u7528\u3002
+error.cdata.found=\u4E00\u4E2ACDATA\u90E8\u5206\u88AB\u53D1\u73B0\uFF0C\u8FD9\u662F\u4E0D\u5141\u8BB8\u7684\u3002\u8BE5\u90AE\u4EF6\u7684\u5176\u4F59\u90E8\u5206\u662F\u5B8C\u6574\u7684\uFF0C\u5176\u642C\u8FC1\u4E0D\u5E94\u8BE5\u6709\u4EFB\u4F55\u526F\u4F5C\u7528\u3002\u5728CDATA\u7684\u5185\u5BB9\u662F \"{0}\"\u3002
+error.pi.found=XML\u5904\u7406\u6307\u4EE4\u88AB\u53D1\u73B0\uFF0C\u8FD9\u662F\u4E0D\u5141\u8BB8\u7684\u3002\u6D88\u606F\u7684\u5176\u4F59\u90E8\u5206\u662F\u5B8C\u6574\u7684\uFF0C\u5176\u642C\u8FC1\u5E94\u8BE5\u4E0D\u4F1A\u6709\u4EFB\u4F55\u526F\u4F5C\u7528\u3002\u8BE5\u6307\u4EE4\u7684\u5185\u5BB9\u4E3A \"{0}\"\u3002
+# Attribute related
+error.attribute.notfound=\u6807\u8BB0{0}\u5305\u542B\u4E00\u4E2A\u6CA1\u6CD5\u5904\u7406\u7684\u5C5E\u6027\u3002\u5C5E\u6027{1}\u5DF2\u88AB\u8FC7\u6EE4\uFF0C\u4F46\u6807\u8BB0\u4FDD\u5B58\u4E0D\u53D8\u3002
+error.attribute.invalid=\u6807\u8BB0{0}\u5305\u542B\u4E00\u4E2A\u6CA1\u6CD5\u5904\u7406\u7684\u5C5E\u6027\u3002\u5C5E\u6027{1}\u5305\u542B\u4E00\u4E2A\u503C\"{2}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u8FD9\u4E2A\u503C\u6CA1\u6CD5\u88AB\u63A5\u53D7\u3002\u4E3A\u4E86\u5904\u7406\u8FD9\u4E2A\u8F93\u5165\uFF0C\u8FD9\u4E2A\u5C5E\u6027\u5DF2\u88AB\u4ECE\u8FD9\u4E2A\u6807\u8BB0\u4E2D\u53BB\u6389\uFF0C\u6807\u8BB0\u5176\u4ED6\u90E8\u5206\u4FDD\u6301\u4E0D\u53D8\u3002
+error.attribute.invalid.filtered=\u6807\u8BB0{0}\u5305\u542B\u4E00\u4E2A\u6CA1\u6CD5\u5904\u7406\u7684\u5C5E\u3002\u5C5E\u6027{1}\u5305\u542B\u4E00\u4E2A\u503C\"{2}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u8FD9\u4E2A\u503C\u6CA1\u6CD5\u88AB\u63A5\u53D7\u3002\u4E3A\u4E86\u8FDB\u4E00\u6B65\u5904\u7406\u8FD9\u4E2A\u8F93\u5165\uFF0C\u6807\u8BB0{0}\u5DF2\u88AB\u8FC7\u6EE4\u3002
+error.attribute.invalid.encoded=The {0} tag contained an attribute that we could not process. The {1} attribute had a value of \"{2}\". This value could not be accepted for security reasons. We have chosen to encode the {0} tag in order to continue processing the input.
+error.attribute.invalid.removed=\u6807\u8BB0{0}\u5305\u542B\u4E00\u4E2A\u6CA1\u6CD5\u5904\u7406\u7684\u5C5E\u6027\u3002\u5C5E\u6027{1}\u5305\u542B\u4E00\u4E2A\u503C\"{2}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u8FD9\u4E2A\u503C\u6CA1\u6CD5\u88AB\u63A5\u53D7\u3002\u4E3A\u4E86\u8FDB\u4E00\u6B65\u5904\u7406\u8FD9\u4E2A\u8F93\u5165\uFF0C\u6574\u4E2A\u6807\u8BB0{0}\u5DF2\u88AB\u53BB\u6389\u3002
+# CSS related
+error.css.tag.malformed=The stylesheet code \"{0}\" could not be parsed.
+error.css.import.disabled=\u6837\u5F0F\u8868\u7684\u5BFC\u5165\u8FD8\u6CA1\u6709\u88AB\u6FC0\u6D3B\u3002
+error.css.import.exceeded=\u4F4D\u4E8E{0}\u7684\u6837\u5F0F\u8868\u8D85\u8FC7\u5141\u8BB8\u5BFC\u5165\u7684\u6837\u5F0F\u8868\u7684\u603B\u6570\uFF0C\u56E0\u6B64\u8BE5\u6837\u5F0F\u8868\u6CA1\u6709\u88AB\u8BFB\u53D6\u3002\u5141\u8BB8\u5BFC\u5165\u7684\u6837\u5F0F\u8868\u7684\u6700\u5927\u6570\u76EE\u4E3A{1}\u3002
+error.css.import.failure=\u8F93\u5165\u4E2D\u542B\u6709\u7684\u8FDC\u7A0B\u6837\u5F0F\u8868\u4F4D\u4E8E{0}\uFF0C\u6B64\u6837\u5F0F\u8868\u6CA1\u6CD5\u88AB\u8BFB\u53D6\u3002\u7F51\u7AD9\u53EF\u80FD\u5173\u95ED\u6216\u8005\u4E3B\u673A\u6CA1\u6CD5\u88AB\u8BBF\u95EE\u3002\u8FD9\u4E0D\u5E94\u8BE5\u5F71\u54CD\u8F93\u5165\u7684\u683C\u5F0F\u3002
+error.css.import.toolarge=\u4F4D\u4E8E{0}\u7684\u6837\u5F0F\u8868\u4F7F\u5F97\u603B\u8F93\u5165\u592A\u5927\uFF0C\u56E0\u6B64\u6CA1\u6709\u88AB\u5BFC\u5165\u3002\u5141\u8BB8\u7684\u6700\u5927\u8F93\u5165\u4E3A{1}\u5B57\u8282\u3002
+error.css.import.url.invalid=\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u7528\u4E8E\u5BFC\u5165\u6837\u5F0F\u8868\u7684url\u6CA1\u6CD5\u88AB\u63A5\u53D7\u3002\u6B64url\u662F{1}\u3002
+error.css.stylesheet.relative=\u6837\u5F0F\u8868\u5F15\u7528\u4E86\u4E00\u4E2A\u6CA1\u6CD5\u8BFB\u53D6\u7684\u76F8\u5BF9\u6837\u5F0F\u8868\"{0}\"\u3002
+error.css.tag.relative=\u6807\u8BB0{0}\u4E2D\u7684\u4E00\u4E2A\u6837\u5F0F\u5C5E\u6027\u6307\u5B9A\u4E86\u4E00\u4E2A\u6CA1\u6CD5\u8BFB\u53D6\u7684\u76F8\u5BF9\u6837\u5F0F\u8868\u5E94\u7528\"{0}\"\u3002
+error.css.stylesheet.rule.notfound=\u6837\u5F0F\u8868\u4F7F\u7528\u4E86\u4E00\u4E2A\u4E0D\u88AB\u652F\u6301\u7684\u89C4\u5219\"{0}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u89C4\u5219\u5DF2\u88AB\u53BB\u6389\u3002
+error.css.tag.rule.notfound=\u6807\u8BB0{0}\u4E2D\u7684\u4E00\u4E2A\u6837\u5F0F\u5C5E\u6027\u4F7F\u7528\u4E86\u4E00\u4E2A\u4E0D\u88AB\u652F\u6301\u7684\u89C4\u5219\"{0}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u89C4\u5219\u5DF2\u88AB\u53BB\u6389\u3002
+error.css.stylesheet.selector.notfound=\u6837\u5F0F\u8868\u4F7F\u7528\u4E86\u4E00\u4E2A\u6CA1\u6CD5\u5904\u7406\u7684\u9009\u62E9\u5668\"{0}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u9009\u62E9\u5668\u5DF2\u88AB\u53BB\u6389\u3002
+error.css.tag.selector.notfound=\u6807\u8BB0{0}\u4E2D\u7684\u4E00\u4E2A\u6837\u5F0F\u5C5E\u6027\u4F7F\u7528\u4E86\u4E00\u4E2A\u6CA1\u6CD5\u5904\u7406\u7684\u9009\u62E9\u5668\"{0}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u89C4\u5219\u5DF2\u88AB\u53BB\u6389\u3002
+error.css.stylesheet.selector.disallowed=\u6837\u5F0F\u8868\u4F7F\u7528\u4E86\u4E00\u4E2A\u9009\u62E9\u5668\"{0}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u9009\u62E9\u5668\u4E0D\u88AB\u5141\u8BB8\u3002
+error.css.tag.selector.disallowed=\u6807\u8BB0{0}\u4E2D\u7684\u4E00\u4E2A\u6837\u5F0F\u5C5E\u6027\u4F7F\u7528\u4E86\u4E00\u4E2A\u9009\u62E9\u5668\"{1}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u9009\u62E9\u5668\u4E0D\u88AB\u5141\u8BB8\u3002
+error.css.stylesheet.property.invalid=\u6837\u5F0F\u8868\u542B\u6709\u4E00\u4E2A\u5C5E\uFF08property)\"{0}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u5C5E\u6027\u4E0D\u88AB\u5141\u8BB8\u3002
+error.css.tag.property.invalid=\u6807\u8BB0{0}\u4E2D\u542B\u6709\u4E00\u4E2A\u6837\u5F0F\u5C5E\u6027\"{1}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u5C5E\u6027\u4E0D\u88AB\u5141\u8BB8\u3002
diff --git a/jnpf-admin/src/main/resources/antisamy-ebay-imgonlybase64.xml b/jnpf-admin/src/main/resources/antisamy-ebay-imgonlybase64.xml
new file mode 100644
index 0000000..a3794be
--- /dev/null
+++ b/jnpf-admin/src/main/resources/antisamy-ebay-imgonlybase64.xml
@@ -0,0 +1,2453 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ g
+ grin
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/antisamy-ebay.xml b/jnpf-admin/src/main/resources/antisamy-ebay.xml
new file mode 100644
index 0000000..46f7f89
--- /dev/null
+++ b/jnpf-admin/src/main/resources/antisamy-ebay.xml
@@ -0,0 +1,2455 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ g
+ grin
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/antisamy-empty.xml b/jnpf-admin/src/main/resources/antisamy-empty.xml
new file mode 100644
index 0000000..24f851c
--- /dev/null
+++ b/jnpf-admin/src/main/resources/antisamy-empty.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/application-dev.yml b/jnpf-admin/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..a61c384
--- /dev/null
+++ b/jnpf-admin/src/main/resources/application-dev.yml
@@ -0,0 +1,233 @@
+# 应用服务器
+server:
+ tomcat:
+ uri-encoding: UTF-8 #tomcat编码
+ port: 30000 #tomcat端口
+
+spring:
+ devtools: #spring开发者工具模块
+ restart:
+ enabled: true #热部署开关
+ freemarker:
+ cache: false #spring内置freemarker缓存
+ thymeleaf:
+ cache: false #spring内置thymeleaf缓存
+
+ # ===================== 数据源配置 =====================
+ exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure #排除自动配置,手动配置druid
+ datasource:
+ db-type: MySQL #数据库类型(可选值 MySQL、SQLServer、Oracle、DM8、KingbaseES、PostgreSQL,请严格按可选值填写)
+ host: 222.71.165.188
+ port: 3309
+ username: root
+ password: linus,.123
+ db-name: jnpf_zhihui
+ db-schema: #金仓达梦选填
+ prepare-url: #自定义url
+
+ # ===================== 动态多数据源 =====================
+ dynamic:
+ primary: master #设置默认的数据源或者数据源组,默认值即为master
+ strict: true #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
+ druid:
+ # 空闲时执行连接测试
+ test-while-idle: true
+ # 连接测试最小间隔
+ time-between-eviction-runs-millis: 60000
+ # 获取连接等待3秒 根据网络情况设定
+ max-wait: 3000
+ # 初始化4个连接
+ initial-size: 4
+ # 最大20个连接
+ max-active: 20
+ # 最少保持4个空闲连接
+ min-idle: 4
+ # 空闲连接保活, 超过配置的空闲时间会进行连接检查完成保活操作(数据库自身会断开达到空闲时间的连接, 程序使用断开的连接会报错)
+ keep-alive: true
+ # 解除注释后Druid连接池打印SQL语句 忽略日志等级配置
+ #filters: slf4j
+ slf4j:
+ statementLogEnabled: true
+ resultSetLogEnabled: false
+ connectionLogEnabled: false
+ dataSourceLogEnabled: false
+ statementCreateAfterLogEnabled: false
+ statementCloseAfterLogEnabled: false
+ statementExecuteAfterLogEnabled: false
+ #打印SQL替换参数
+ statementExecutableSqlLogEnable: true
+ statementPrepareAfterLogEnabled: false
+ statementPrepareCallAfterLogEnabled: false
+ statementParameterSetLogEnabled: false
+ # datasource:
+ # master:
+ # url: jdbc:mysql://${spring.datasource.host}:${spring.datasource.port}/${spring.datasource.dbname}?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&serverTimezone=UTC
+ # username: ${spring.datasource.username}
+ # password: ${spring.datasource.password}
+ # driver-class-name: com.mysql.cj.jdbc.Driver
+
+ # ===================== Redis配置 =====================
+ # redis单机模式
+ redis:
+ database: 1 #缓存库编号
+# host: 222.71.165.188
+ host: 127.0.0.1
+ port: 6379
+# password: qweasd,.123 # 密码为空时,请将本行注释
+ timeout: 3000 #超时时间(单位:秒)
+ lettuce: #Lettuce为Redis的Java驱动包
+ pool:
+ max-active: 8 # 连接池最大连接数
+ max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
+ min-idle: 0 # 连接池中的最小空闲连接
+ max-idle: 8 # 连接池中的最大空闲连接
+
+# redis集群模式
+# redis:
+# cluster:
+# nodes:
+# - 192.168.0.225:6380
+# - 192.168.0.225:6381
+# - 192.168.0.225:6382
+# - 192.168.0.225:6383
+# - 192.168.0.225:6384
+# - 192.168.0.225:6385
+# password: 123456 # 密码为空时,请将本行注释
+# timeout: 3000 # 超时时间(单位:秒)
+# lettuce: #Lettuce为Redis的Java驱动包
+# pool:
+# max-active: 8 # 连接池最大连接数
+# max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
+# min-idle: 0 # 连接池中的最小空闲连接
+# max-idle: 8 # 连接池中的最大空闲连接
+
+# SpringDoc接口文档 访问地址:http://127.0.0.1:30000/doc.html
+springdoc:
+ default-flat-param-object: true
+ api-docs:
+ enabled: true
+#SpringDoc增强
+#knife4j:
+# basic: #接口文档访问鉴权
+# enable: true
+# username: jnpf
+# password: 123456
+
+config:
+ # ===================== 是否开启测试环境 =====================
+ TestVersion: false
+ # ===================== ApacheShardingSphere 配置开关 =====================
+ sharding-sphere-enabled: false
+ # ===================== 文件存储配置 =====================
+ file-storage: #文件存储配置,不使用的情况下可以不写
+ default-platform: local-plus-1 #默认使用的存储平台
+ thumbnail-suffix: ".min.jpg" #缩略图后缀,例如【.min.jpg】【.png】
+ local-plus: # 本地存储升级版
+ - platform: local-plus-1 # 存储平台标识
+ enable-storage: true #启用存储
+ enable-access: true #启用访问(线上请使用 Nginx 配置,效率更高)
+ domain: "" # 访问域名,例如:“http://127.0.0.1:8030/”,注意后面要和 path-patterns 保持一致,“/”结尾,本地存储建议使用相对路径,方便后期更换域名
+ base-path: D:/project/jnpf-resources/ # 基础路径
+ path-patterns: /** # 访问路径
+ storage-path: # 存储路径
+ aliyun-oss: # 阿里云 OSS ,不使用的情况下可以不写
+ - platform: aliyun-oss-1 # 存储平台标识
+ enable-storage: false # 启用存储
+ access-key: ??
+ secret-key: ??
+ end-point: ??
+ bucket-name: ??
+ domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.oss-cn-shanghai.aliyuncs.com/
+ base-path: hy/ # 基础路径
+ qiniu-kodo: # 七牛云 kodo ,不使用的情况下可以不写
+ - platform: qiniu-kodo-1 # 存储平台标识
+ enable-storage: false # 启用存储
+ access-key: ??
+ secret-key: ??
+ bucket-name: ??
+ domain: ?? # 访问域名,注意“/”结尾,例如:http://abc.hn-bkt.clouddn.com/
+ base-path: base/ # 基础路径
+ tencent-cos: # 腾讯云 COS
+ - platform: tencent-cos-1 # 存储平台标识
+ enable-storage: false # 启用存储
+ secret-id: ??
+ secret-key: ??
+ region: ?? #存仓库所在地域
+ bucket-name: ??
+ domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.cos.ap-nanjing.myqcloud.com/
+ base-path: hy/ # 基础路径
+ minio: # MinIO,由于 MinIO SDK 支持 AWS S3,其它兼容 AWS S3 协议的存储平台也都可配置在这里
+ - platform: minio-1 # 存储平台标识
+ enable-storage: true # 启用存储
+ access-key: Q9jJs2b6Tv
+ secret-key: Thj2WkpLu9DhmJyJ
+ end-point: http://192.168.0.207:9000/
+ bucket-name: jnpfsoftoss
+ domain: # 访问域名,注意“/”结尾,例如:http://minio.abc.com/abc/
+ base-path: # 基础路径
+
+# ===================== 第三方登录配置 =====================
+socials:
+ # 第三方登录功能开关(false-关闭,true-开启)
+ socials-enabled: false
+ config:
+ - # 微信
+ provider: wechat_open
+ client-id: your-client-id
+ client-secret: your-client-secret
+ - # qq
+ provider: qq
+ client-id: your-client-id
+ client-secret: your-client-secret
+ - # 企业微信
+ provider: wechat_enterprise
+ client-id: your-client-id
+ client-secret: your-client-secret
+ agentId: your-agentId
+ - # 钉钉
+ provider: dingtalk
+ client-id: your-client-id
+ client-secret: your-client-secret
+ agentId: your-agentId
+ - # 飞书
+ provider: feishu
+ client-id: your-client-id
+ client-secret: your-client-secret
+ - # 小程序
+ provider: wechat_applets
+ client-id: your-client-id
+ client-secret: your-client-secret
+
+# ===================== 任务调度配置 =====================
+xxl:
+ job:
+ accessToken: ''
+ i18n: zh_CN
+ logretentiondays: 30
+ triggerpool:
+ fast:
+ max: 200
+ slow:
+ max: 100
+ # xxl-job服务端地址
+ admin:
+ addresses: http://127.0.0.1:30020/xxl-job-admin/
+ executor:
+ address: ''
+ appname: xxl-job-executor-sample1
+ ip: ''
+ logpath: /data/applogs/xxl-job/jobhandler
+ logretentiondays: 30
+ port: 9999
+ # rest调用xxl-job接口地址
+ admin:
+ register:
+ handle-query-address: ${xxl.job.admin.addresses}api/handler/queryList
+ job-info-address: ${xxl.job.admin.addresses}api/jobinfo
+ log-query-address: ${xxl.job.admin.addresses}api/log
+ task-list-address: ${xxl.job.admin.addresses}api/ScheduleTask/List
+ task-info-address: ${xxl.job.admin.addresses}api/ScheduleTask/getInfo
+ task-save-address: ${xxl.job.admin.addresses}api/ScheduleTask
+ task-update-address: ${xxl.job.admin.addresses}api/ScheduleTask
+ task-remove-address: ${xxl.job.admin.addresses}api/ScheduleTask/remove
+ task-start-or-remove-address: ${xxl.job.admin.addresses}api/ScheduleTask/updateTask
diff --git a/jnpf-admin/src/main/resources/application-preview.yml b/jnpf-admin/src/main/resources/application-preview.yml
new file mode 100644
index 0000000..6b1dd9a
--- /dev/null
+++ b/jnpf-admin/src/main/resources/application-preview.yml
@@ -0,0 +1,194 @@
+# 应用服务器
+server:
+ tomcat:
+ uri-encoding: UTF-8 #tomcat编码
+ port: 30000 #tomcat端口
+
+spring:
+ devtools: #spring开发者工具模块
+ restart:
+ enabled: true #热部署开关
+ freemarker:
+ cache: false #spring内置freemarker缓存
+ thymeleaf:
+ cache: false #spring内置thymeleaf缓存
+
+ # ===================== 数据源配置 =====================
+ exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure #排除自动配置,手动配置druid
+ datasource:
+ db-type: MySQL #数据库类型(可选值 MySQL、SQLServer、Oracle、DM8、KingbaseES、PostgreSQL,请严格按可选值填写)
+ host: 192.168.0.210
+ port: 3306
+ username: java_boot_test
+ password: pBx5HaW6WMGSTdDf
+ db-name: java_boot_test
+ db-schema: #金仓达梦选填
+ prepare-url: #自定义url
+
+ # ===================== 动态多数据源 =====================
+ dynamic:
+ primary: master #设置默认的数据源或者数据源组,默认值即为master
+ strict: true #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
+ druid:
+ #定时执行数据链接检测语句 防止数据库闲时超时断开链接
+ test-while-idle: true #空闲时执行
+ time-between-eviction-runs-millis: 60000 #执行间隔
+ # datasource:
+ # master:
+ # url: jdbc:mysql://${spring.datasource.host}:${spring.datasource.port}/${spring.datasource.dbname}?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&serverTimezone=UTC
+ # username: ${spring.datasource.username}
+ # password: ${spring.datasource.password}
+ # driver-class-name: com.mysql.cj.jdbc.Driver
+
+ # ===================== Redis配置 =====================
+ # redis单机模式
+ redis:
+ database: 1 #缓存库编号
+ host: 192.168.0.220
+ port: 6379
+ password: 123456 # 密码为空时,请将本行注释
+ timeout: 3000 #超时时间(单位:秒)
+ lettuce: #Lettuce为Redis的Java驱动包
+ pool:
+ max-active: 8 # 连接池最大连接数
+ max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
+ min-idle: 0 # 连接池中的最小空闲连接
+ max-idle: 8 # 连接池中的最大空闲连接
+
+# redis集群模式
+# redis:
+# cluster:
+# nodes:
+# - 192.168.0.225:6380
+# - 192.168.0.225:6381
+# - 192.168.0.225:6382
+# - 192.168.0.225:6383
+# - 192.168.0.225:6384
+# - 192.168.0.225:6385
+# password: 123456 # 密码为空时,请将本行注释
+# timeout: 3000 # 超时时间(单位:秒)
+# lettuce: #Lettuce为Redis的Java驱动包
+# pool:
+# max-active: 8 # 连接池最大连接数
+# max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
+# min-idle: 0 # 连接池中的最小空闲连接
+# max-idle: 8 # 连接池中的最大空闲连接
+
+config:
+ # ===================== 是否开启测试环境 =====================
+ TestVersion: false
+ # ===================== ApacheShardingSphere 配置开关 =====================
+ sharding-sphere-enabled: false
+ # ===================== 文件存储配置 =====================
+ file-storage: #文件存储配置,不使用的情况下可以不写
+ default-platform: local-plus-1 #默认使用的存储平台
+ thumbnail-suffix: ".min.jpg" #缩略图后缀,例如【.min.jpg】【.png】
+ local-plus: # 本地存储升级版
+ - platform: local-plus-1 # 存储平台标识
+ enable-storage: true #启用存储
+ enable-access: true #启用访问(线上请使用 Nginx 配置,效率更高)
+ domain: "" # 访问域名,例如:“http://127.0.0.1:8030/”,注意后面要和 path-patterns 保持一致,“/”结尾,本地存储建议使用相对路径,方便后期更换域名
+ base-path: F:/work/jnpf-resources/ # 基础路径
+ path-patterns: /** # 访问路径
+ storage-path: # 存储路径
+ aliyun-oss: # 阿里云 OSS ,不使用的情况下可以不写
+ - platform: aliyun-oss-1 # 存储平台标识
+ enable-storage: false # 启用存储
+ access-key: ??
+ secret-key: ??
+ end-point: ??
+ bucket-name: ??
+ domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.oss-cn-shanghai.aliyuncs.com/
+ base-path: hy/ # 基础路径
+ qiniu-kodo: # 七牛云 kodo ,不使用的情况下可以不写
+ - platform: qiniu-kodo-1 # 存储平台标识
+ enable-storage: false # 启用存储
+ access-key: ??
+ secret-key: ??
+ bucket-name: ??
+ domain: ?? # 访问域名,注意“/”结尾,例如:http://abc.hn-bkt.clouddn.com/
+ base-path: base/ # 基础路径
+ tencent-cos: # 腾讯云 COS
+ - platform: tencent-cos-1 # 存储平台标识
+ enable-storage: false # 启用存储
+ secret-id: ??
+ secret-key: ??
+ region: ?? #存仓库所在地域
+ bucket-name: ??
+ domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.cos.ap-nanjing.myqcloud.com/
+ base-path: hy/ # 基础路径
+ minio: # MinIO,由于 MinIO SDK 支持 AWS S3,其它兼容 AWS S3 协议的存储平台也都可配置在这里
+ - platform: minio-1 # 存储平台标识
+ enable-storage: true # 启用存储
+ access-key: Q9jJs2b6Tv
+ secret-key: Thj2WkpLu9DhmJyJ
+ end-point: http://192.168.0.207:9000/
+ bucket-name: jnpfsoftoss
+ domain: # 访问域名,注意“/”结尾,例如:http://minio.abc.com/abc/
+ base-path: # 基础路径
+
+# ===================== 第三方登录配置 =====================
+socials:
+ # 第三方登录功能开关(false-关闭,true-开启)
+ socials-enabled: false
+ config:
+ - # 微信
+ provider: wechat_open
+ client-id: your-client-id
+ client-secret: your-client-secret
+ - # qq
+ provider: qq
+ client-id: your-client-id
+ client-secret: your-client-secret
+ - # 企业微信
+ provider: wechat_enterprise
+ client-id: your-client-id
+ client-secret: your-client-secret
+ agentId: your-agentId
+ - # 钉钉
+ provider: dingtalk
+ client-id: your-client-id
+ client-secret: your-client-secret
+ agentId: your-agentId
+ - # 飞书
+ provider: feishu
+ client-id: your-client-id
+ client-secret: your-client-secret
+ - # 小程序
+ provider: wechat_applets
+ client-id: your-client-id
+ client-secret: your-client-secret
+
+# ===================== 任务调度配置 =====================
+xxl:
+ job:
+ accessToken: ''
+ i18n: zh_CN
+ logretentiondays: 30
+ triggerpool:
+ fast:
+ max: 200
+ slow:
+ max: 100
+ # xxl-job服务端地址
+ admin:
+ addresses: http://127.0.0.1:30020/xxl-job-admin/
+ executor:
+ address: ''
+ appname: xxl-job-executor-sample1
+ ip: ''
+ logpath: /data/applogs/xxl-job/jobhandler
+ logretentiondays: 30
+ port: 9999
+ # rest调用xxl-job接口地址
+ admin:
+ register:
+ handle-query-address: ${xxl.job.admin.addresses}api/handler/queryList
+ job-info-address: ${xxl.job.admin.addresses}api/jobinfo
+ log-query-address: ${xxl.job.admin.addresses}api/log
+ task-list-address: ${xxl.job.admin.addresses}api/ScheduleTask/List
+ task-info-address: ${xxl.job.admin.addresses}api/ScheduleTask/getInfo
+ task-save-address: ${xxl.job.admin.addresses}api/ScheduleTask
+ task-update-address: ${xxl.job.admin.addresses}api/ScheduleTask
+ task-remove-address: ${xxl.job.admin.addresses}api/ScheduleTask/remove
+ task-start-or-remove-address: ${xxl.job.admin.addresses}api/ScheduleTask/updateTask
\ No newline at end of file
diff --git a/jnpf-admin/src/main/resources/application-pro.yml b/jnpf-admin/src/main/resources/application-pro.yml
new file mode 100644
index 0000000..58dd00d
--- /dev/null
+++ b/jnpf-admin/src/main/resources/application-pro.yml
@@ -0,0 +1,194 @@
+# 应用服务器
+server:
+ tomcat:
+ uri-encoding: UTF-8 #tomcat编码
+ port: 30000 #tomcat端口
+
+spring:
+ devtools: #spring开发者工具模块
+ restart:
+ enabled: true #热部署开关
+ freemarker:
+ cache: false #spring内置freemarker缓存
+ thymeleaf:
+ cache: false #spring内置thymeleaf缓存
+
+ # ===================== 数据源配置 =====================
+ exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure #排除自动配置,手动配置druid
+ datasource:
+ db-type: MySQL #数据库类型(可选值 MySQL、SQLServer、Oracle、DM8、KingbaseES、PostgreSQL,请严格按可选值填写)
+ host: 192.168.0.210
+ port: 3306
+ username: java_boot_test
+ password: pBx5HaW6WMGSTdDf
+ db-name: java_boot_test
+ db-schema: #金仓达梦选填
+ prepare-url: #自定义url
+
+ # ===================== 动态多数据源 =====================
+ dynamic:
+ primary: master #设置默认的数据源或者数据源组,默认值即为master
+ strict: true #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
+ druid:
+ #定时执行数据链接检测语句 防止数据库闲时超时断开链接
+ test-while-idle: true #空闲时执行
+ time-between-eviction-runs-millis: 60000 #执行间隔
+ # datasource:
+ # master:
+ # url: jdbc:mysql://${spring.datasource.host}:${spring.datasource.port}/${spring.datasource.dbname}?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&serverTimezone=UTC
+ # username: ${spring.datasource.username}
+ # password: ${spring.datasource.password}
+ # driver-class-name: com.mysql.cj.jdbc.Driver
+
+ # ===================== Redis配置 =====================
+ # redis单机模式
+ redis:
+ database: 1 #缓存库编号
+ host: 192.168.0.220
+ port: 6379
+ password: 123456 # 密码为空时,请将本行注释
+ timeout: 3000 #超时时间(单位:秒)
+ lettuce: #Lettuce为Redis的Java驱动包
+ pool:
+ max-active: 8 # 连接池最大连接数
+ max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
+ min-idle: 0 # 连接池中的最小空闲连接
+ max-idle: 8 # 连接池中的最大空闲连接
+
+# redis集群模式
+# redis:
+# cluster:
+# nodes:
+# - 192.168.0.225:6380
+# - 192.168.0.225:6381
+# - 192.168.0.225:6382
+# - 192.168.0.225:6383
+# - 192.168.0.225:6384
+# - 192.168.0.225:6385
+# password: 123456 # 密码为空时,请将本行注释
+# timeout: 3000 # 超时时间(单位:秒)
+# lettuce: #Lettuce为Redis的Java驱动包
+# pool:
+# max-active: 8 # 连接池最大连接数
+# max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
+# min-idle: 0 # 连接池中的最小空闲连接
+# max-idle: 8 # 连接池中的最大空闲连接
+
+config:
+ # ===================== 是否开启测试环境 =====================
+ TestVersion: false
+ # ===================== ApacheShardingSphere 配置开关 =====================
+ sharding-sphere-enabled: false
+ # ===================== 文件存储配置 =====================
+ file-storage: #文件存储配置,不使用的情况下可以不写
+ default-platform: local-plus-1 #默认使用的存储平台
+ thumbnail-suffix: ".min.jpg" #缩略图后缀,例如【.min.jpg】【.png】
+ local-plus: # 本地存储升级版
+ - platform: local-plus-1 # 存储平台标识
+ enable-storage: true #启用存储
+ enable-access: true #启用访问(线上请使用 Nginx 配置,效率更高)
+ domain: "" # 访问域名,例如:“http://127.0.0.1:8030/”,注意后面要和 path-patterns 保持一致,“/”结尾,本地存储建议使用相对路径,方便后期更换域名
+ base-path: F:/work/jnpf-resources/ # 基础路径
+ path-patterns: /** # 访问路径
+ storage-path: # 存储路径
+ aliyun-oss: # 阿里云 OSS ,不使用的情况下可以不写
+ - platform: aliyun-oss-1 # 存储平台标识
+ enable-storage: false # 启用存储
+ access-key: ??
+ secret-key: ??
+ end-point: ??
+ bucket-name: ??
+ domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.oss-cn-shanghai.aliyuncs.com/
+ base-path: hy/ # 基础路径
+ qiniu-kodo: # 七牛云 kodo ,不使用的情况下可以不写
+ - platform: qiniu-kodo-1 # 存储平台标识
+ enable-storage: false # 启用存储
+ access-key: ??
+ secret-key: ??
+ bucket-name: ??
+ domain: ?? # 访问域名,注意“/”结尾,例如:http://abc.hn-bkt.clouddn.com/
+ base-path: base/ # 基础路径
+ tencent-cos: # 腾讯云 COS
+ - platform: tencent-cos-1 # 存储平台标识
+ enable-storage: false # 启用存储
+ secret-id: ??
+ secret-key: ??
+ region: ?? #存仓库所在地域
+ bucket-name: ??
+ domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.cos.ap-nanjing.myqcloud.com/
+ base-path: hy/ # 基础路径
+ minio: # MinIO,由于 MinIO SDK 支持 AWS S3,其它兼容 AWS S3 协议的存储平台也都可配置在这里
+ - platform: minio-1 # 存储平台标识
+ enable-storage: true # 启用存储
+ access-key: Q9jJs2b6Tv
+ secret-key: Thj2WkpLu9DhmJyJ
+ end-point: http://192.168.0.207:9000/
+ bucket-name: jnpfsoftoss
+ domain: # 访问域名,注意“/”结尾,例如:http://minio.abc.com/abc/
+ base-path: # 基础路径
+
+# ===================== 第三方登录配置 =====================
+socials:
+ # 第三方登录功能开关(false-关闭,true-开启)
+ socials-enabled: false
+ config:
+ - # 微信
+ provider: wechat_open
+ client-id: your-client-id
+ client-secret: your-client-secret
+ - # qq
+ provider: qq
+ client-id: your-client-id
+ client-secret: your-client-secret
+ - # 企业微信
+ provider: wechat_enterprise
+ client-id: your-client-id
+ client-secret: your-client-secret
+ agentId: your-agentId
+ - # 钉钉
+ provider: dingtalk
+ client-id: your-client-id
+ client-secret: your-client-secret
+ agentId: your-agentId
+ - # 飞书
+ provider: feishu
+ client-id: your-client-id
+ client-secret: your-client-secret
+ - # 小程序
+ provider: wechat_applets
+ client-id: your-client-id
+ client-secret: your-client-secret
+
+# ===================== 任务调度配置 =====================
+xxl:
+ job:
+ accessToken: ''
+ i18n: zh_CN
+ logretentiondays: 30
+ triggerpool:
+ fast:
+ max: 200
+ slow:
+ max: 100
+ # xxl-job服务端地址
+ admin:
+ addresses: http://127.0.0.1:30020/xxl-job-admin/
+ executor:
+ address: ''
+ appname: xxl-job-executor-sample1
+ ip: ''
+ logpath: /data/applogs/xxl-job/jobhandler
+ logretentiondays: 30
+ port: 9999
+ # rest调用xxl-job接口地址
+ admin:
+ register:
+ handle-query-address: ${xxl.job.admin.addresses}api/handler/queryList
+ job-info-address: ${xxl.job.admin.addresses}api/jobinfo
+ log-query-address: ${xxl.job.admin.addresses}api/log
+ task-list-address: ${xxl.job.admin.addresses}api/ScheduleTask/List
+ task-info-address: ${xxl.job.admin.addresses}api/ScheduleTask/getInfo
+ task-save-address: ${xxl.job.admin.addresses}api/ScheduleTask
+ task-update-address: ${xxl.job.admin.addresses}api/ScheduleTask
+ task-remove-address: ${xxl.job.admin.addresses}api/ScheduleTask/remove
+ task-start-or-remove-address: ${xxl.job.admin.addresses}api/ScheduleTask/updateTask
diff --git a/jnpf-admin/src/main/resources/application-test.yml b/jnpf-admin/src/main/resources/application-test.yml
new file mode 100644
index 0000000..58dd00d
--- /dev/null
+++ b/jnpf-admin/src/main/resources/application-test.yml
@@ -0,0 +1,194 @@
+# 应用服务器
+server:
+ tomcat:
+ uri-encoding: UTF-8 #tomcat编码
+ port: 30000 #tomcat端口
+
+spring:
+ devtools: #spring开发者工具模块
+ restart:
+ enabled: true #热部署开关
+ freemarker:
+ cache: false #spring内置freemarker缓存
+ thymeleaf:
+ cache: false #spring内置thymeleaf缓存
+
+ # ===================== 数据源配置 =====================
+ exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure #排除自动配置,手动配置druid
+ datasource:
+ db-type: MySQL #数据库类型(可选值 MySQL、SQLServer、Oracle、DM8、KingbaseES、PostgreSQL,请严格按可选值填写)
+ host: 192.168.0.210
+ port: 3306
+ username: java_boot_test
+ password: pBx5HaW6WMGSTdDf
+ db-name: java_boot_test
+ db-schema: #金仓达梦选填
+ prepare-url: #自定义url
+
+ # ===================== 动态多数据源 =====================
+ dynamic:
+ primary: master #设置默认的数据源或者数据源组,默认值即为master
+ strict: true #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
+ druid:
+ #定时执行数据链接检测语句 防止数据库闲时超时断开链接
+ test-while-idle: true #空闲时执行
+ time-between-eviction-runs-millis: 60000 #执行间隔
+ # datasource:
+ # master:
+ # url: jdbc:mysql://${spring.datasource.host}:${spring.datasource.port}/${spring.datasource.dbname}?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&serverTimezone=UTC
+ # username: ${spring.datasource.username}
+ # password: ${spring.datasource.password}
+ # driver-class-name: com.mysql.cj.jdbc.Driver
+
+ # ===================== Redis配置 =====================
+ # redis单机模式
+ redis:
+ database: 1 #缓存库编号
+ host: 192.168.0.220
+ port: 6379
+ password: 123456 # 密码为空时,请将本行注释
+ timeout: 3000 #超时时间(单位:秒)
+ lettuce: #Lettuce为Redis的Java驱动包
+ pool:
+ max-active: 8 # 连接池最大连接数
+ max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
+ min-idle: 0 # 连接池中的最小空闲连接
+ max-idle: 8 # 连接池中的最大空闲连接
+
+# redis集群模式
+# redis:
+# cluster:
+# nodes:
+# - 192.168.0.225:6380
+# - 192.168.0.225:6381
+# - 192.168.0.225:6382
+# - 192.168.0.225:6383
+# - 192.168.0.225:6384
+# - 192.168.0.225:6385
+# password: 123456 # 密码为空时,请将本行注释
+# timeout: 3000 # 超时时间(单位:秒)
+# lettuce: #Lettuce为Redis的Java驱动包
+# pool:
+# max-active: 8 # 连接池最大连接数
+# max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
+# min-idle: 0 # 连接池中的最小空闲连接
+# max-idle: 8 # 连接池中的最大空闲连接
+
+config:
+ # ===================== 是否开启测试环境 =====================
+ TestVersion: false
+ # ===================== ApacheShardingSphere 配置开关 =====================
+ sharding-sphere-enabled: false
+ # ===================== 文件存储配置 =====================
+ file-storage: #文件存储配置,不使用的情况下可以不写
+ default-platform: local-plus-1 #默认使用的存储平台
+ thumbnail-suffix: ".min.jpg" #缩略图后缀,例如【.min.jpg】【.png】
+ local-plus: # 本地存储升级版
+ - platform: local-plus-1 # 存储平台标识
+ enable-storage: true #启用存储
+ enable-access: true #启用访问(线上请使用 Nginx 配置,效率更高)
+ domain: "" # 访问域名,例如:“http://127.0.0.1:8030/”,注意后面要和 path-patterns 保持一致,“/”结尾,本地存储建议使用相对路径,方便后期更换域名
+ base-path: F:/work/jnpf-resources/ # 基础路径
+ path-patterns: /** # 访问路径
+ storage-path: # 存储路径
+ aliyun-oss: # 阿里云 OSS ,不使用的情况下可以不写
+ - platform: aliyun-oss-1 # 存储平台标识
+ enable-storage: false # 启用存储
+ access-key: ??
+ secret-key: ??
+ end-point: ??
+ bucket-name: ??
+ domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.oss-cn-shanghai.aliyuncs.com/
+ base-path: hy/ # 基础路径
+ qiniu-kodo: # 七牛云 kodo ,不使用的情况下可以不写
+ - platform: qiniu-kodo-1 # 存储平台标识
+ enable-storage: false # 启用存储
+ access-key: ??
+ secret-key: ??
+ bucket-name: ??
+ domain: ?? # 访问域名,注意“/”结尾,例如:http://abc.hn-bkt.clouddn.com/
+ base-path: base/ # 基础路径
+ tencent-cos: # 腾讯云 COS
+ - platform: tencent-cos-1 # 存储平台标识
+ enable-storage: false # 启用存储
+ secret-id: ??
+ secret-key: ??
+ region: ?? #存仓库所在地域
+ bucket-name: ??
+ domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.cos.ap-nanjing.myqcloud.com/
+ base-path: hy/ # 基础路径
+ minio: # MinIO,由于 MinIO SDK 支持 AWS S3,其它兼容 AWS S3 协议的存储平台也都可配置在这里
+ - platform: minio-1 # 存储平台标识
+ enable-storage: true # 启用存储
+ access-key: Q9jJs2b6Tv
+ secret-key: Thj2WkpLu9DhmJyJ
+ end-point: http://192.168.0.207:9000/
+ bucket-name: jnpfsoftoss
+ domain: # 访问域名,注意“/”结尾,例如:http://minio.abc.com/abc/
+ base-path: # 基础路径
+
+# ===================== 第三方登录配置 =====================
+socials:
+ # 第三方登录功能开关(false-关闭,true-开启)
+ socials-enabled: false
+ config:
+ - # 微信
+ provider: wechat_open
+ client-id: your-client-id
+ client-secret: your-client-secret
+ - # qq
+ provider: qq
+ client-id: your-client-id
+ client-secret: your-client-secret
+ - # 企业微信
+ provider: wechat_enterprise
+ client-id: your-client-id
+ client-secret: your-client-secret
+ agentId: your-agentId
+ - # 钉钉
+ provider: dingtalk
+ client-id: your-client-id
+ client-secret: your-client-secret
+ agentId: your-agentId
+ - # 飞书
+ provider: feishu
+ client-id: your-client-id
+ client-secret: your-client-secret
+ - # 小程序
+ provider: wechat_applets
+ client-id: your-client-id
+ client-secret: your-client-secret
+
+# ===================== 任务调度配置 =====================
+xxl:
+ job:
+ accessToken: ''
+ i18n: zh_CN
+ logretentiondays: 30
+ triggerpool:
+ fast:
+ max: 200
+ slow:
+ max: 100
+ # xxl-job服务端地址
+ admin:
+ addresses: http://127.0.0.1:30020/xxl-job-admin/
+ executor:
+ address: ''
+ appname: xxl-job-executor-sample1
+ ip: ''
+ logpath: /data/applogs/xxl-job/jobhandler
+ logretentiondays: 30
+ port: 9999
+ # rest调用xxl-job接口地址
+ admin:
+ register:
+ handle-query-address: ${xxl.job.admin.addresses}api/handler/queryList
+ job-info-address: ${xxl.job.admin.addresses}api/jobinfo
+ log-query-address: ${xxl.job.admin.addresses}api/log
+ task-list-address: ${xxl.job.admin.addresses}api/ScheduleTask/List
+ task-info-address: ${xxl.job.admin.addresses}api/ScheduleTask/getInfo
+ task-save-address: ${xxl.job.admin.addresses}api/ScheduleTask
+ task-update-address: ${xxl.job.admin.addresses}api/ScheduleTask
+ task-remove-address: ${xxl.job.admin.addresses}api/ScheduleTask/remove
+ task-start-or-remove-address: ${xxl.job.admin.addresses}api/ScheduleTask/updateTask
diff --git a/jnpf-admin/src/main/resources/application.yml b/jnpf-admin/src/main/resources/application.yml
new file mode 100644
index 0000000..3f61acc
--- /dev/null
+++ b/jnpf-admin/src/main/resources/application.yml
@@ -0,0 +1,128 @@
+spring:
+ application:
+ name: jnpf-boot
+ profiles:
+ # 指定环境配置 dev(开发环境-默认)、test(测试环境)、preview(预生产)、pro(生产环境)
+ active: dev
+ servlet:
+ multipart: #文件传输配置
+ max-file-size: 100MB #单个数据大小限制
+ max-request-size: 100MB #请求总数据大小限制
+ enabled: true #是否启用分段上传支持
+ mvc:
+ hiddenmethod: #隐式方法过滤器
+ filter:
+ enabled: true #默认开启。开启以支持:PUT,DELETE表单提交方法
+ jackson: #序列化和反序列化json框架
+ serialization:
+ write-dates-as-timestamps: true #是否写入日期时间时间戳格式
+ time-zone: GMT+8 #指定日期格式化时区
+ main:
+ allow-bean-definition-overriding: true #允许同名bean后者覆盖,默认:true
+ allow-circular-references: true #允许Bean相互引用,默认:false
+config:
+ # ===============静态资源目录映射==================
+ WebAnnexFilePath: WebAnnexFile
+ DataBackupFilePath: DataBackupFile
+ TemporaryFilePath: TemporaryFile
+ SystemFilePath: SystemFile
+ TemplateFilePath: TemplateFile
+ EmailFilePath: EmailFile
+ DocumentFilePath: DocumentFile
+ DocumentPreviewPath: DocumentPreview
+ UserAvatarFilePath: UserAvatar
+ IMContentFilePath: IMContentFile
+ MPMaterialFilePath: MPMaterial
+ TemplateCodePath: TemplateCode
+ BiVisualPath: BiVisualPath
+ # ===============功能格式限制==================
+ MPUploadFileType: bmp,png,jpeg,jpg,gif,mp3,wma,wav,amr,mp4
+ WeChatUploadFileType: jpg,png,doc,docx,ppt,pptx,xls,xlsx,pdf,txt,rar,zip,csv,amr,mp4
+
+ AllowUploadImageType: jpg,gif,png,bmp,jpeg,tiff,psd,swf,svg,pcx,dxf,wmf,emf,lic,eps,tga #允许上传图片类型
+ AllowUploadFileType: jpg,gif,png,bmp,jpeg,doc,docx,ppt,pptx,xls,xlsx,pdf,txt,rar,zip,csv,mp3 #允许上传文件类型
+ AllowPreviewFileType: doc,docx,xls,xlsx,ppt,pptx,pdf,jpg,gif,png,bmp,jpeg #允许预览文件类型
+ PreviewType: kkfile #文件预览方式 (1.yozo 2.kkfile)默认使用kkfile
+ kkFileUrl: http://127.0.0.1:30090/FileServer/ #kkfile文件预览服务地址
+ ApiDomain: http://127.0.0.1:30000 #后端域名(文档预览中使用)
+ FrontDomain: http://127.0.0.1:3000 #前端域名(文档预览中使用)
+ AppDomain: http://127.0.0.1:8080 #app/h5端域名配置(文档预览中使用)
+
+ CodeAreasName: example #代码生成器模块命名
+
+
+ #===================== unipush =====================
+ AppPushUrl: https://8e84eea8-6922-4033-8e86-67ad7442e692.bspapp.com/unipush
+
+ #===================== 多租户 =====================
+ MultiTenancy: false #是否开启
+ MultiTenancyUrl: http://127.0.0.1:30006/api/tenant/DbName/ #多租户项目地址
+ #COLUMN、SCHEMA模式
+ MultiTenantType: SCHEMA
+
+ #===================== 系统及错误报告反馈相关 =====================
+ SoftName: jnpf-java-boot #项目名
+ SoftFullName: JNPF快速开发平台 #项目全名
+ SoftVersion: v3.5.0 #版本号
+
+ RecordLog: true #系统日志启用
+ ErrorReport: false #软件错误报告
+ ErrorReportTo: surrpot@yinmaisoft.com #软件错误报告接收者
+ IgexinEnabled: true #推送启动
+
+ #===================== APP =====================
+ AppVersion: V3.5.0 #APP版本号
+ IgexinAppid: HLFY9T2d1z7MySY8hwGwh4 #APPID:应用的唯一标识
+ IgexinAppkey: 6Uiduugq648YDChhCjAt59 #APPKEY:公匙(相当于账号)
+ IgexinMastersecret: pEyQm156SJ9iS7PbyjLCZ6 #Mastersecret:私匙(相当于密码)
+ AppUpdateContent: ; #APP更新内容
+
+ #===================== 永中office在线预览配置 =====================
+ YozoDomain: //dcsapi.com/ #永中api域名
+ YozoDomainKey: 57462250284462899305150 #域名key
+ YozoCloudDomain: //dmc.yozocloud.cn #云预览
+ YozoAppId: yozoAgR41jgC0062 #appid
+ YozoAppKey: fc3134a9ba8bc6f4c69d635f9adf #app秘钥
+ YozoEditDomain: //eic.yozocloud.cn #云编辑
+
+ #===================== 系统功能配置 =====================
+ EnablePreAuth: false #是否开启接口鉴权
+ EnableLogicDelete: false #是否开启逻辑删除
+
+# 接口放行地址 与GatewayWhite中的默认URL合并
+gateway:
+ # 禁止访问接口
+ block-url:
+ ## 配置示例
+ #- /api/message/Notice
+ #- /api/permission/Users/*
+ # 不验证Token, 放行接口(默认记录日志)
+ white-url:
+ # # 配置示例
+ #- /api/message/Notice
+ #- /api/permission/Users/*
+ # 放行接口(不记录日志)
+ exclude-url:
+ # # 配置示例
+ #- /api/message/Notice
+ #- /api/permission/Users/*
+ # 入站IP(禁止配置以外的IP访问block-url配置的接口)
+ white-ip:
+ #- 192.168.0.10
+ #- 192.168.0.20
+
+# 日志配置
+logging:
+ config: classpath:logback-spring.xml
+ level:
+ #自定义第三方包名日志等级
+ # 解除注释后Druid连接池打印SQL语句
+ druid.sql.Statement: debug
+# druid.sql.DataSource: debug
+# druid.sql.Connection: debug
+# druid.sql.ResultSet: debug
+log:
+ level:
+ # 等级 TRACE,DEBUG,INFO,WARN,ERROR(不区分大小写)
+ root: info
+ path: log/${spring.application.name}
\ No newline at end of file
diff --git a/jnpf-admin/src/main/resources/logback-spring.xml b/jnpf-admin/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000..ecb97e3
--- /dev/null
+++ b/jnpf-admin/src/main/resources/logback-spring.xml
@@ -0,0 +1,339 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${LOG_PATH}/log_error.log
+
+
+
+
+
+ ${LOG_PATH}/error/%d{yyyy-MM-dd,aux}/log-error-%d{yyyy-MM-dd}.%i.log
+
+ 7
+
+
+
+ 10MB
+
+
+
+
+ true
+
+
+
+ ${FILE_LOG_PATTERN}
+ utf-8
+
+
+
+
+ error
+ ACCEPT
+ DENY
+
+
+
+
+
+
+
+
+ ${LOG_PATH}/log_info.log
+
+
+
+
+
+ ${LOG_PATH}/info/%d{yyyy-MM-dd,aux}/log-info-%d{yyyy-MM-dd}.%i.log
+
+ 7
+
+
+
+ 10MB
+
+
+
+
+ true
+
+
+
+ ${FILE_LOG_PATTERN}
+ utf-8
+
+
+
+
+ info
+ ACCEPT
+ DENY
+
+
+
+
+
+
+
+
+ ${LOG_PATH}/log_warn.log
+
+
+
+
+
+ ${LOG_PATH}/warn/%d{yyyy-MM-dd,aux}/log-warn-%d{yyyy-MM-dd}.%i.log
+
+ 7
+
+
+
+ 10MB
+
+
+
+
+ true
+
+
+
+ ${FILE_LOG_PATTERN}
+ utf-8
+
+
+
+
+ warn
+ ACCEPT
+ DENY
+
+
+
+
+
+
+
+ ${LOG_PATH}/log_debug.log
+
+
+
+
+
+ ${LOG_PATH}/debug/%d{yyyy-MM-dd,aux}/log-debug-%d{yyyy-MM-dd}.%i.log
+
+ 7
+
+
+
+ 10MB
+
+
+
+
+ true
+
+
+
+ ${FILE_LOG_PATTERN}
+ utf-8
+
+
+
+
+ debug
+ ACCEPT
+ DENY
+
+
+
+
+
+
+
+
+ ${LOG_PATH}/log_total.log
+
+
+
+
+
+ ${LOG_PATH}/total/%d{yyyy-MM-dd,aux}/log-total-%d{yyyy-MM-dd}.%i.log
+
+ 7
+
+
+
+ 10MB
+
+
+
+
+ true
+
+
+
+ ${FILE_LOG_PATTERN}
+ utf-8
+
+
+
+
+
+
+
+
+ ${LOG_PATH}/log_release.log
+
+
+
+
+
+ ${LOG_PATH}/release/%d{yyyy-MM-dd,aux}/log-warn-%d{yyyy-MM-dd}.%i.log
+
+ 7
+
+
+
+ 10MB
+
+
+
+
+ true
+
+
+
+ ${FILE_LOG_PATTERN}
+ utf-8
+
+
+
+
+ ${LOG_LEVEL}
+ ACCEPT
+ DENY
+
+
+
+
+ 0
+ 256
+
+
+
+
+ 0
+ 256
+
+
+
+
+ 0
+ 256
+
+
+
+
+ 0
+ 256
+
+
+
+
+ 0
+ 256
+
+
+
+
+
+
+ ${CONSOLE_LOG_PATTERN}
+ utf-8
+
+
+
+
+
+
+ 0
+ 256
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/extend/BigDataMapper.xml b/jnpf-admin/src/main/resources/mapper/extend/BigDataMapper.xml
new file mode 100644
index 0000000..5ea34c1
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/extend/BigDataMapper.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/extend/DocumentMapper.xml b/jnpf-admin/src/main/resources/mapper/extend/DocumentMapper.xml
new file mode 100644
index 0000000..7e7f590
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/extend/DocumentMapper.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UPDATE ext_document SET F_DELETEMARK=1,F_DELETETIME=NULL,F_DELETEUSERID=NULL WHERE F_Id=#{id}
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/form/FormMapper.xml b/jnpf-admin/src/main/resources/mapper/form/FormMapper.xml
new file mode 100644
index 0000000..ee8676f
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/form/FormMapper.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/scm/AreaMapper.xml b/jnpf-admin/src/main/resources/mapper/scm/AreaMapper.xml
new file mode 100644
index 0000000..dd40b53
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/scm/AreaMapper.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/scm/MeasureSiteConfigMapper.xml b/jnpf-admin/src/main/resources/mapper/scm/MeasureSiteConfigMapper.xml
new file mode 100644
index 0000000..396b678
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/scm/MeasureSiteConfigMapper.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/scm/ParkMapper.xml b/jnpf-admin/src/main/resources/mapper/scm/ParkMapper.xml
new file mode 100644
index 0000000..ea102fe
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/scm/ParkMapper.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/scm/SpaceMapper.xml b/jnpf-admin/src/main/resources/mapper/scm/SpaceMapper.xml
new file mode 100644
index 0000000..611dd16
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/scm/SpaceMapper.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/scm/SpatialMapper.xml b/jnpf-admin/src/main/resources/mapper/scm/SpatialMapper.xml
new file mode 100644
index 0000000..e4f6137
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/scm/SpatialMapper.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/system/AuthorizeMapper.xml b/jnpf-admin/src/main/resources/mapper/system/AuthorizeMapper.xml
new file mode 100644
index 0000000..3b3421a
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/system/AuthorizeMapper.xml
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO base_authorize (f_id, f_item_type, f_item_id, f_object_type, f_object_id, f_sort_code, f_creator_time, f_creator_user_id ) VALUES ${values}
+
+
+
+ INSERT ALL
+
+ INTO base_authorize (f_id, f_item_type, f_item_id, f_object_type, f_object_id, f_sort_code, f_creator_time,
+ f_creator_user_id ) VALUES (
+ #{item.id},
+ #{item.itemType},
+ #{item.itemId},
+ #{item.objectType},
+ #{item.objectId},
+ #{item.sortCode,jdbcType=NUMERIC},
+ #{item.creatorTime, jdbcType=TIMESTAMP},
+ #{item.creatorUserId})
+
+ SELECT 1 FROM DUAL
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/system/ImContentMapper.xml b/jnpf-admin/src/main/resources/mapper/system/ImContentMapper.xml
new file mode 100644
index 0000000..d697fbe
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/system/ImContentMapper.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+ UPDATE base_im_content SET f_enabled_mark = 1, f_receive_time = #{map.receiveTime} WHERE 1 = 1 AND f_enabled_mark = 0 AND f_send_user_id = #{map.sendUserId} AND f_receive_user_id = #{map.receiveUserId}
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/system/ImReplyMapper.xml b/jnpf-admin/src/main/resources/mapper/system/ImReplyMapper.xml
new file mode 100644
index 0000000..1cbe86d
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/system/ImReplyMapper.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/system/MessageMapper.xml b/jnpf-admin/src/main/resources/mapper/system/MessageMapper.xml
new file mode 100644
index 0000000..17a01e0
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/system/MessageMapper.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/system/PortalManageMapper.xml b/jnpf-admin/src/main/resources/mapper/system/PortalManageMapper.xml
new file mode 100644
index 0000000..a7f92a0
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/system/PortalManageMapper.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+ SELECT
+ -- 门户管理表
+ bpm.F_Id id,
+ bpm.F_Enabled_Mark enabledMark,
+ bpm.F_Platform platform,
+ bpm.F_Description description,
+ bpm.F_Tenant_Id tenantId,
+ bpm.F_Sort_Code sortCode,
+ bpm.F_System_Id systemId,
+ bpm.F_PORTAL_ID portalId,
+ bpm.F_Creator_Time creatorTime,
+ bpm.F_Last_Modify_Time lastModifyTime,
+ -- 门户表
+ bp.F_Category categoryId,
+ bp.F_Full_Name portalName,
+ bd.F_Full_Name categoryName,
+ -- 用户表
+ us.F_Real_Name createUserName,
+ us.F_Account createUserAccount,
+ us2.F_Real_Name modifyUserName,
+ us2.F_Account modifyUserAccount
+ FROM
+ base_portal_manage bpm
+ LEFT JOIN
+ base_portal bp
+ ON
+ bpm.F_Portal_Id = bp.F_Id
+ LEFT JOIN
+ base_user us
+ ON
+ bpm.F_Creator_User_Id = us.F_Id
+ LEFT JOIN
+ base_user us2
+ ON
+ bpm.F_Last_Modify_User_Id = us2.F_Id
+ LEFT JOIN
+ base_dictionary_data bd
+ ON bp.F_Category = bd.F_Id
+ WHERE 1 = 1
+
+ AND (bp.F_Full_Name LIKE #{pmPage.keyword} OR bpm.F_Description LIKE #{pmPage.keyword})
+
+
+ AND
+ bp.F_Category = #{pmPage.category}
+
+
+ AND
+ bpm.F_Enabled_Mark = #{pmPage.enabledMark}
+ AND bp.F_Enabled_Mark = #{pmPage.enabledMark}
+
+
+ AND
+ bpm.F_Platform LIKE #{pmPage.platform}
+
+
+ AND
+ bpm.F_System_Id = #{pmPage.systemId}
+
+
+ AND
+ bp.F_state != #{pmPage.state}
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/system/PositionMapper.xml b/jnpf-admin/src/main/resources/mapper/system/PositionMapper.xml
new file mode 100644
index 0000000..b4d67d1
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/system/PositionMapper.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/system/RoleMapper.xml b/jnpf-admin/src/main/resources/mapper/system/RoleMapper.xml
new file mode 100644
index 0000000..acc88e0
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/system/RoleMapper.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/system/SysconfigMapper.xml b/jnpf-admin/src/main/resources/mapper/system/SysconfigMapper.xml
new file mode 100644
index 0000000..eaa4582
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/system/SysconfigMapper.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ delete from base_sys_config where F_Category ='SysConfig'
+
+
+ delete from base_sys_config where F_Category='MPConfig'
+
+
+ delete from base_sys_config where F_Category='QYHConfig'
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/system/UserMapper.xml b/jnpf-admin/src/main/resources/mapper/system/UserMapper.xml
new file mode 100644
index 0000000..1ff6a2c
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/system/UserMapper.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/mapper/workflow/engine/FlowTaskMapper.xml b/jnpf-admin/src/main/resources/mapper/workflow/engine/FlowTaskMapper.xml
new file mode 100644
index 0000000..155de13
--- /dev/null
+++ b/jnpf-admin/src/main/resources/mapper/workflow/engine/FlowTaskMapper.xml
@@ -0,0 +1,317 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jnpf-admin/src/main/resources/sharding-sphere.yml b/jnpf-admin/src/main/resources/sharding-sphere.yml
new file mode 100644
index 0000000..41c975c
--- /dev/null
+++ b/jnpf-admin/src/main/resources/sharding-sphere.yml
@@ -0,0 +1,52 @@
+databaseName: myshardingsphere
+dataSources: # 数据源配置 =============
+ # <数据源_0>: # 自定义数据源名称
+ # dataSourceClassName: com.zaxxer.hikari.HikariDataSource # 连接池提供方完整类名(Spring默认Hikari)
+ # driverClassName: com.mysql.jdbc.Driver # JDBC驱动
+ # jdbcUrl: jdbc:mysql://{host}:{port}/{dbName}?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8 # 数据库连接URL
+ # username: {username} # 用户
+ # password: {password} # 密码
+ ds0: # 自定义数据源名称
+ dataSourceClassName: com.alibaba.druid.pool.DruidDataSource # 连接池提供方完整类名(Spring默认Hikari)
+ driverClassName: com.mysql.jdbc.Driver # JDBC驱动
+ url: jdbc:mysql://127.0.0.1:3306/sharding1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8 # 数据库连接URL
+ username: root # 用户
+ password: 123456 # 密码
+ ds1: # 自定义数据源名称
+ dataSourceClassName: com.alibaba.druid.pool.DruidDataSource # 连接池提供方完整类名(Spring默认Hikari)
+ driverClassName: com.mysql.jdbc.Driver # JDBC驱动
+ url: jdbc:mysql://127.0.0.1:3306/sharding2?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8 # 数据库连接URL
+ username: root # 用户
+ password: 123456 # 密码
+rules: # 规则 =============
+ - !SHARDING # 注意类似“- !SHARDING”标识不能省略
+ tables:
+ ext_bigdata: # 自定义逻辑表名
+ actualDataNodes: ds${0..1}.ext_bigdata_$->{0..1} # 由数据源名 + 表名组成(参考 Inline 语法规则)
+ databaseStrategy:
+ standard:
+ shardingColumn: F_Id # 分表依据字段
+ shardingAlgorithmName: myDataSourceAlgorithm
+ tableStrategy: # 表策略 -------
+ standard:
+ shardingColumn: F_Id # 分表依据字段
+ shardingAlgorithmName: myTableAlgorithm
+
+ # defaultDatabaseStrategy: # 库策略 -------
+ # standard:
+ # shardingColumn: F_Id
+ # shardingAlgorithmName: myDataSourceAlgorithm
+ shardingAlgorithms: # 分片算法 -------
+ myDataSourceAlgorithm: # 自定义算法名
+ type: INLINE
+ props:
+ algorithm-expression: ds${(long)(Long.parseLong(F_Id)/10) % 2}
+ myTableAlgorithm: # 自定义算法名
+ type: INLINE
+ props:
+ algorithm-expression: ext_bigdata_${(long)(Long.parseLong(F_Id)/10 / 2) % 2}
+# keyGenerators:
+# dsKey: # 自定义主键策略名
+# type: SNOWFLAKE
+props:
+ sql-show: true
\ No newline at end of file
diff --git a/jnpf-app/jnpf-app-biz/pom.xml b/jnpf-app/jnpf-app-biz/pom.xml
new file mode 100644
index 0000000..110c880
--- /dev/null
+++ b/jnpf-app/jnpf-app-biz/pom.xml
@@ -0,0 +1,41 @@
+
+
+
+ jnpf-app
+ com.jnpf
+ 3.5.0-RELEASE
+
+ 4.0.0
+
+ jnpf-app-biz
+
+
+
+ com.jnpf
+ jnpf-app-entity
+ ${project.version}
+ compile
+
+
+ com.jnpf
+ jnpf-permission-biz
+ ${project.version}
+ compile
+
+
+ com.jnpf
+ jnpf-system-biz
+ ${project.version}
+ compile
+
+
+ com.jnpf
+ jnpf-workflow-engine-biz
+ ${project.version}
+ compile
+
+
+
+
\ No newline at end of file
diff --git a/jnpf-app/jnpf-app-biz/src/main/java/jnpf/mapper/AppDataMapper.java b/jnpf-app/jnpf-app-biz/src/main/java/jnpf/mapper/AppDataMapper.java
new file mode 100644
index 0000000..41a9c81
--- /dev/null
+++ b/jnpf-app/jnpf-app-biz/src/main/java/jnpf/mapper/AppDataMapper.java
@@ -0,0 +1,16 @@
+package jnpf.mapper;
+
+import jnpf.base.mapper.SuperMapper;
+import jnpf.entity.AppDataEntity;
+
+/**
+ * app常用数据
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021-07-08
+ */
+public interface AppDataMapper extends SuperMapper {
+
+}
diff --git a/jnpf-app/jnpf-app-biz/src/main/java/jnpf/service/AppDataService.java b/jnpf-app/jnpf-app-biz/src/main/java/jnpf/service/AppDataService.java
new file mode 100644
index 0000000..9322385
--- /dev/null
+++ b/jnpf-app/jnpf-app-biz/src/main/java/jnpf/service/AppDataService.java
@@ -0,0 +1,88 @@
+package jnpf.service;
+
+import jnpf.base.service.SuperService;
+import jnpf.engine.model.flowengine.FlowPagination;
+import jnpf.entity.AppDataEntity;
+import jnpf.model.AppDataListAllVO;
+import jnpf.model.AppFlowListAllVO;
+
+import java.util.List;
+
+/**
+ * app常用数据
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021-08-08
+ */
+public interface AppDataService extends SuperService {
+
+ /**
+ * 列表
+ *
+ * @param type 类型
+ * @return
+ */
+ List getList(String type);
+
+ /**
+ * 列表
+ *
+ * @return
+ */
+ List getList();
+
+ /**
+ * 信息
+ *
+ * @param objectId 对象主键
+ * @return
+ */
+ AppDataEntity getInfo(String objectId);
+
+ /**
+ * 验证名称
+ *
+ * @param objectId 对象主键
+ * @return
+ */
+ boolean isExistByObjectId(String objectId, String systemId);
+
+ /**
+ * 创建
+ *
+ * @param entity 实体对象
+ */
+ void create(AppDataEntity entity);
+
+ /**
+ * 删除
+ *
+ * @param entity 实体对象
+ */
+ void delete(AppDataEntity entity);
+
+ /**
+ * 删除
+ *
+ * @param objectId 应用主键
+ */
+ void delete(String objectId);
+
+ /**
+ * 流程所有应用
+ *
+ * @param pagination
+ * @return
+ */
+ List getFlowList(FlowPagination pagination);
+
+ /**
+ * 流程所有应用
+ * @param type 类型
+ * @return
+ */
+ List getDataList(String type);
+
+}
diff --git a/jnpf-app/jnpf-app-biz/src/main/java/jnpf/service/AppService.java b/jnpf-app/jnpf-app-biz/src/main/java/jnpf/service/AppService.java
new file mode 100644
index 0000000..a95d4db
--- /dev/null
+++ b/jnpf-app/jnpf-app-biz/src/main/java/jnpf/service/AppService.java
@@ -0,0 +1,28 @@
+package jnpf.service;
+
+import jnpf.model.AppUserInfoVO;
+import jnpf.model.AppUsersVO;
+
+/**
+ * app用户信息
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021-08-08
+ */
+public interface AppService {
+
+ /**
+ * app用户信息
+ * @return
+ */
+ AppUsersVO userInfo();
+
+ /**
+ * 通讯录
+ * @return
+ */
+ AppUserInfoVO getInfo(String id);
+
+}
diff --git a/jnpf-app/jnpf-app-biz/src/main/java/jnpf/service/impl/AppDataServiceImpl.java b/jnpf-app/jnpf-app-biz/src/main/java/jnpf/service/impl/AppDataServiceImpl.java
new file mode 100644
index 0000000..ebfcc58
--- /dev/null
+++ b/jnpf-app/jnpf-app-biz/src/main/java/jnpf/service/impl/AppDataServiceImpl.java
@@ -0,0 +1,171 @@
+package jnpf.service.impl;
+
+
+import jnpf.base.service.SuperServiceImpl;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import jnpf.base.UserInfo;
+import jnpf.base.entity.ModuleEntity;
+import jnpf.base.model.module.ModuleModel;
+import jnpf.base.service.ModuleService;
+import jnpf.engine.entity.FlowTemplateEntity;
+import jnpf.engine.model.flowengine.FlowPagination;
+import jnpf.engine.service.FlowTemplateJsonService;
+import jnpf.engine.service.FlowTemplateService;
+import jnpf.entity.AppDataEntity;
+import jnpf.mapper.AppDataMapper;
+import jnpf.model.*;
+import jnpf.permission.model.authorize.AuthorizeVO;
+import jnpf.permission.service.AuthorizeService;
+import jnpf.service.AppDataService;
+import jnpf.util.JsonUtil;
+import jnpf.util.RandomUtil;
+import jnpf.util.StringUtil;
+import jnpf.util.UserProvider;
+import jnpf.util.treeutil.SumTree;
+import jnpf.util.treeutil.newtreeutil.TreeDotUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * app常用数据
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021-08-08
+ */
+@Service
+public class AppDataServiceImpl extends SuperServiceImpl implements AppDataService {
+
+ @Autowired
+ private UserProvider userProvider;
+ @Autowired
+ private ModuleService moduleService;
+ @Autowired
+ private AuthorizeService authorizeService;
+ @Autowired
+ private FlowTemplateService flowTemplateService;
+ @Autowired
+ private FlowTemplateJsonService flowTemplateJsonService;
+
+ @Override
+ public List getList(String type) {
+ UserInfo userInfo = userProvider.get();
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.lambda().eq(AppDataEntity::getObjectType, type).eq(AppDataEntity::getCreatorUserId, userInfo.getUserId());
+ List list = this.list(queryWrapper);
+ list = list.stream().filter(t -> StringUtil.isNotEmpty(t.getSystemId()) && t.getSystemId().equals(userInfo.getAppSystemId())).collect(Collectors.toList());
+ List idAll = list.stream().map(AppDataEntity::getObjectId).collect(Collectors.toList());
+ List templateList = flowTemplateService.getTemplateList(idAll);
+ for (int i = 0; i < list.size(); i++) {
+ AppDataEntity appDataEntity = list.get(i);
+ if ("2".equals(type)) {
+ ModuleEntity info = moduleService.getInfo(appDataEntity.getObjectId());
+ if (info == null || info.getEnabledMark() == 0) {
+ list.remove(i);
+ i--;
+ }
+ } else {
+ FlowTemplateEntity templateEntity = templateList.stream().filter(t -> t.getId().equals(appDataEntity.getObjectId())).findFirst().orElse(null);
+ if (templateEntity == null) {
+ list.remove(i);
+ i--;
+ }
+ }
+ }
+ return list;
+ }
+
+ @Override
+ public List getList() {
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ return this.list(queryWrapper);
+ }
+
+ @Override
+ public AppDataEntity getInfo(String objectId) {
+ UserInfo userInfo = userProvider.get();
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.lambda().eq(AppDataEntity::getObjectId, objectId).eq(AppDataEntity::getCreatorUserId, userInfo.getUserId());
+ return this.getOne(queryWrapper);
+ }
+
+ @Override
+ public boolean isExistByObjectId(String objectId, String systemId) {
+ UserInfo userInfo = userProvider.get();
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.lambda().eq(AppDataEntity::getObjectId, objectId)
+ .eq(AppDataEntity::getCreatorUserId, userInfo.getUserId())
+ .eq(AppDataEntity::getSystemId, systemId);
+ return this.count(queryWrapper) > 0 ? true : false;
+ }
+
+ @Override
+ public void create(AppDataEntity entity) {
+ UserInfo userInfo = userProvider.get();
+ entity.setId(RandomUtil.uuId());
+ entity.setCreatorUserId(userInfo.getUserId());
+ entity.setCreatorTime(new Date());
+ entity.setEnabledMark(1);
+ entity.setSystemId(userInfo.getAppSystemId());
+ this.save(entity);
+ }
+
+ @Override
+ public void delete(AppDataEntity entity) {
+ this.removeById(entity.getId());
+ }
+
+ @Override
+ public void delete(String objectId) {
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.lambda().eq(AppDataEntity::getObjectId, objectId);
+ this.remove(queryWrapper);
+ }
+
+ @Override
+ public List getFlowList(FlowPagination pagination) {
+ List objectId = getList("1").stream().map(AppDataEntity::getObjectId).collect(Collectors.toList());;
+ List pageList = flowTemplateService.getListAll(pagination,true);
+ List result = new ArrayList<>();
+ for (FlowTemplateEntity entity : pageList) {
+ AppFlowListAllVO vo = JsonUtil.getJsonToBean(entity, AppFlowListAllVO.class);
+ vo.setIsData(objectId.contains(vo.getId()));
+ result.add(vo);
+ }
+ return pagination.setData(result, pagination.getTotal());
+ }
+
+ @Override
+ public List getDataList(String type) {
+ List dataList = getList(type);
+ String appSystemId = userProvider.get().getAppSystemId();
+ AuthorizeVO authorizeModel = authorizeService.getAuthorize(true, false);
+ List buttonList = authorizeModel.getModuleList();
+ List menuList = moduleService.getList().stream().filter(t -> "App".equals(t.getCategory()) && t.getEnabledMark() == 1 && t.getSystemId().equals(appSystemId)).collect(Collectors.toList());
+ List list = new LinkedList<>();
+ for (ModuleEntity module : menuList) {
+ boolean count = buttonList.stream().filter(t -> t.getId().equals(module.getId())).count() > 0;
+ UserMenuModel userMenuModel = JsonUtil.getJsonToBean(module, UserMenuModel.class);
+ if (count) {
+ boolean isData = dataList.stream().filter(t -> t.getObjectId().equals(module.getId())).count() > 0;
+ userMenuModel.setIsData(isData);
+ list.add(userMenuModel);
+ }
+ }
+ List> menuAll = TreeDotUtils.convertListToTreeDot(list);
+ List menuListAll = JsonUtil.getJsonToList(menuAll, AppDataListAllVO.class);
+ List data = new LinkedList<>();
+ for (AppDataListAllVO appMenu : menuListAll) {
+ if ("-1".equals(appMenu.getParentId())) {
+ data.add(appMenu);
+ }
+ }
+ return data;
+ }
+
+
+}
diff --git a/jnpf-app/jnpf-app-biz/src/main/java/jnpf/service/impl/AppServiceImpl.java b/jnpf-app/jnpf-app-biz/src/main/java/jnpf/service/impl/AppServiceImpl.java
new file mode 100644
index 0000000..d617ba7
--- /dev/null
+++ b/jnpf-app/jnpf-app-biz/src/main/java/jnpf/service/impl/AppServiceImpl.java
@@ -0,0 +1,157 @@
+package jnpf.service.impl;
+
+import cn.hutool.core.collection.ListUtil;
+import jnpf.base.UserInfo;
+import jnpf.model.AppPositionVO;
+import jnpf.model.AppUserInfoVO;
+import jnpf.model.AppUsersVO;
+import jnpf.permission.entity.*;
+import jnpf.permission.service.*;
+import jnpf.service.AppService;
+import jnpf.util.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * app用户信息
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021-08-08
+ */
+@Service
+public class AppServiceImpl implements AppService {
+
+ @Autowired
+ private UserProvider userProvider;
+ @Autowired
+ private UserService userService;
+ @Autowired
+ private PositionService positionService;
+ @Autowired
+ private OrganizeService organizeService;
+ @Autowired
+ private RoleService roleService;
+ @Autowired
+ private RedisUtil redisUtil;
+ @Autowired
+ private UserRelationService userRelationService;
+
+ @Override
+ public AppUsersVO userInfo() {
+ UserInfo userInfo = userProvider.get();
+ UserEntity userEntity = userService.getInfo(userInfo.getUserId());
+ AppUsersVO usersVO = new AppUsersVO();
+ usersVO.setBirthday(userEntity.getBirthday() != null ? userEntity.getBirthday().getTime() : null);
+ usersVO.setEmail(userEntity.getEmail());
+ usersVO.setGender(userEntity.getGender());
+ usersVO.setMobilePhone(userEntity.getMobilePhone());
+ this.data(usersVO, userEntity, userInfo);
+ this.userInfo(usersVO, userInfo);
+ //岗位
+ PositionEntity position = positionService.getInfo(userEntity.getPositionId());
+ AppPositionVO positionVO = new AppPositionVO();
+ if(position != null){
+ positionVO.setId(position.getId());
+ positionVO.setName(position.getFullName());
+ usersVO.setPositionIds(ListUtil.toList(positionVO));
+ }
+ //直属主管
+ if(StringUtil.isNotEmpty(userEntity.getManagerId())){
+ UserEntity menager = userService.getInfo(userEntity.getManagerId());
+ usersVO.setManager(menager != null ? menager.getRealName() + "/" + menager.getAccount() : "");
+ }
+ //角色
+ List roles = roleService.getAllRoleIdsByUserIdAndOrgId(userInfo.getUserId(), usersVO.getOrganizeId());
+ List roleList = roleService.getListByIds(roles, null, false);
+ usersVO.setRoleName(String.join(",", roleList.stream().map(RoleEntity::getFullName).collect(Collectors.toList())));
+ usersVO.setRoleId(String.join(".", roleList.stream().map(RoleEntity::getId).collect(Collectors.toList())));
+ return usersVO;
+ }
+
+ @Override
+ public AppUserInfoVO getInfo(String id) {
+ AppUserInfoVO userInfoVO = new AppUserInfoVO();
+ UserEntity entity = userService.getInfo(id);
+ if (entity != null) {
+ userInfoVO = JsonUtil.getJsonToBean(entity, AppUserInfoVO.class);
+ List positionIds = StringUtil.isNotEmpty(entity.getPositionId()) ? Arrays.asList(entity.getPositionId().split(",")) : new ArrayList<>();
+ List positionName = positionService.getPositionName(positionIds, false).stream().map(t -> t.getFullName()).collect(Collectors.toList());
+ userInfoVO.setPositionName(String.join(",", positionName));
+ OrganizeEntity info = organizeService.getInfo(entity.getOrganizeId());
+ userInfoVO.setOrganizeName(info != null ? info.getFullName() : "");
+ userInfoVO.setHeadIcon(UploaderUtil.uploaderImg(userInfoVO.getHeadIcon()));
+ }
+ return userInfoVO;
+ }
+ /**
+ * 赋值
+ *
+ * @param userInfo
+ * @param userId
+ * @param isAdmin
+ */
+ private void userInfo(UserInfo userInfo, String userId, boolean isAdmin, UserEntity userEntity) {
+ List userIdList = new ArrayList(){{add(userId);}};
+ List data = userRelationService.getListByUserIdAll(userIdList);
+ //获取一个字段的值
+ List positionList = data.stream().filter(m -> "Position".equals(m.getObjectType())).map(t -> t.getObjectId()).collect(Collectors.toList());
+ Set id = new LinkedHashSet<>();
+ String[] position = StringUtil.isNotEmpty(userEntity.getPositionId()) ? userEntity.getPositionId().split(",") : new String[]{};
+ List positions = positionList.stream().filter(t->Arrays.asList(position).contains(t)).collect(Collectors.toList());
+ id.addAll(positions);
+ id.addAll(positionList);
+ userInfo.setPositionIds(id.toArray(new String[id.size()]));
+ if (!isAdmin) {
+ data = data.stream().filter(m -> "Role".equals(m.getObjectType())).collect(Collectors.toList());
+ }
+ List roleList = data.stream().map(t -> t.getObjectId()).collect(Collectors.toList());
+ userInfo.setRoleIds(roleList);
+ }
+
+ private void data(AppUsersVO usersVO, UserEntity userEntity, UserInfo userInfo) {
+ //组织
+ usersVO.setOrganizeId(userEntity.getOrganizeId());
+ List organizeIdList = new ArrayList<>();
+ organizeService.getOrganizeId(userEntity.getOrganizeId(),organizeIdList);
+ Collections.reverse(organizeIdList);
+ usersVO.setOrganizeName(organizeIdList.stream().map(OrganizeEntity::getFullName).collect(Collectors.joining("/")));
+ OrganizeEntity organizeEntity = organizeIdList.stream().filter(t->t.getId().equals(userEntity.getOrganizeId())).findFirst().orElse(null);
+ if (organizeEntity != null) {
+ String[] organizeId = StringUtil.isNotEmpty(organizeEntity.getOrganizeIdTree()) ? organizeEntity.getOrganizeIdTree().split(",") : new String[]{};
+ if (organizeId.length > 0) {
+ userInfo.setOrganizeId(organizeId[0]);
+ userInfo.setDepartmentId(organizeId[organizeId.length - 1]);
+ }
+ }
+ userInfo.setManagerId(userInfo.getManagerId());
+ boolean b = userInfo.getIsAdministrator();
+ List subordinateIdsList = userService.getListByManagerId(userInfo.getUserId(),null).stream().map(UserEntity::getId).collect(Collectors.toList());
+ userInfo.setSubordinateIds(subordinateIdsList);
+ this.userInfo(userInfo, userInfo.getUserId(), b,userEntity);
+ userInfo.setSubOrganizeIds(new String[]{});
+ //redisUtil.insert(userInfo.getId(), userInfo, DateUtil.getTime(userInfo.getOverdueTime()) - DateUtil.getTime(new Date()));
+ UserProvider.setLoginUser(userInfo);
+ UserProvider.setLocalLoginUser(userInfo);
+ }
+
+ /**
+ * 登录信息
+ *
+ * @param appUsersVO 返回对象
+ * @param userInfo 回话信息
+ * @return
+ */
+ private void userInfo(AppUsersVO appUsersVO, UserInfo userInfo) {
+ appUsersVO.setUserId(userInfo.getUserId());
+ appUsersVO.setHeadIcon(UploaderUtil.uploaderImg(userInfo.getUserIcon()));
+ appUsersVO.setUserName(userInfo.getUserName());
+ appUsersVO.setUserAccount(userInfo.getUserAccount());
+ }
+
+
+}
diff --git a/jnpf-app/jnpf-app-controller/pom.xml b/jnpf-app/jnpf-app-controller/pom.xml
new file mode 100644
index 0000000..423116c
--- /dev/null
+++ b/jnpf-app/jnpf-app-controller/pom.xml
@@ -0,0 +1,23 @@
+
+
+
+ jnpf-app
+ com.jnpf
+ 3.5.0-RELEASE
+
+ 4.0.0
+
+ jnpf-app-controller
+
+
+
+ com.jnpf
+ jnpf-app-biz
+ ${project.version}
+ compile
+
+
+
+
\ No newline at end of file
diff --git a/jnpf-app/jnpf-app-controller/src/main/java/jnpf/controller/AppDataController.java b/jnpf-app/jnpf-app-controller/src/main/java/jnpf/controller/AppDataController.java
new file mode 100644
index 0000000..113b1a6
--- /dev/null
+++ b/jnpf-app/jnpf-app-controller/src/main/java/jnpf/controller/AppDataController.java
@@ -0,0 +1,129 @@
+package jnpf.controller;
+
+import jnpf.base.controller.SuperController;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.Operation;
+import jnpf.base.ActionResult;
+import jnpf.base.vo.ListVO;
+import jnpf.base.vo.PageListVO;
+import jnpf.base.vo.PaginationVO;
+import jnpf.constant.MsgCode;
+import jnpf.engine.model.flowengine.FlowPagination;
+import jnpf.entity.AppDataEntity;
+import jnpf.model.AppDataCrForm;
+import jnpf.model.AppDataListAllVO;
+import jnpf.model.AppDataListVO;
+import jnpf.model.AppFlowListAllVO;
+import jnpf.service.AppDataService;
+import jnpf.util.JsonUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * app常用数据
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司(https://www.jnpfsoft.com)
+ * @date 2021-07-08
+ */
+@Tag(name = "app常用数据", description = "data")
+@RestController
+@RequestMapping("/api/app/Data")
+public class AppDataController extends SuperController {
+
+ @Autowired
+ private AppDataService appDataService;
+
+ /**
+ * 常用数据
+ *
+ * @param type 类型
+ * @return
+ */
+ @Operation(summary = "常用数据")
+ @GetMapping
+ @Parameters({
+ @Parameter(name = "type", description = "类型"),
+ })
+ public ActionResult> list(@RequestParam("type") String type) {
+ List list = appDataService.getList(type);
+ List data = JsonUtil.getJsonToList(list, AppDataListVO.class);
+ ListVO listVO = new ListVO();
+ listVO.setList(data);
+ return ActionResult.success(listVO);
+ }
+
+ /**
+ * 新建
+ *
+ * @param appDataCrForm 新建模型
+ * @return
+ */
+ @PostMapping
+ @Operation(summary = "新建")
+ @Parameters({
+ @Parameter(name = "appDataCrForm", description = "常用模型",required = true),
+ })
+ public ActionResult create(@RequestBody @Valid AppDataCrForm appDataCrForm) {
+ AppDataEntity entity = JsonUtil.getJsonToBean(appDataCrForm, AppDataEntity.class);
+ if (appDataService.isExistByObjectId(entity.getObjectId(),appDataCrForm.getSystemId())) {
+ return ActionResult.fail("常用数据已存在");
+ }
+ appDataService.create(entity);
+ return ActionResult.success(MsgCode.SU001.get());
+ }
+
+ /**
+ * 删除
+ *
+ * @param objectId 主键
+ * @return
+ */
+ @Operation(summary = "删除")
+ @DeleteMapping("/{objectId}")
+ @Parameters({
+ @Parameter(name = "objectId", description = "主键", required = true),
+ })
+ public ActionResult create(@PathVariable("objectId") String objectId) {
+ AppDataEntity entity = appDataService.getInfo(objectId);
+ if (entity != null) {
+ appDataService.delete(entity);
+ return ActionResult.success(MsgCode.SU003.get());
+ }
+ return ActionResult.fail(MsgCode.FA003.get());
+ }
+
+ /**
+ * 所有流程
+ *
+ * @param pagination 分页模型
+ * @return
+ */
+ @Operation(summary = "所有流程")
+ @GetMapping("/getFlowList")
+ public ActionResult> getFlowList(FlowPagination pagination) {
+ List list = appDataService.getFlowList(pagination);
+ PaginationVO paginationVO = JsonUtil.getJsonToBean(pagination, PaginationVO.class);
+ return ActionResult.page(list, paginationVO);
+ }
+
+ /**
+ * 所有应用
+ *
+ * @return
+ */
+ @Operation(summary = "所有应用")
+ @GetMapping("/getDataList")
+ public ActionResult> getAllList() {
+ List result = appDataService.getDataList("2");
+ ListVO listVO = new ListVO();
+ listVO.setList(result);
+ return ActionResult.success(listVO);
+ }
+}
diff --git a/jnpf-app/jnpf-app-controller/src/main/java/jnpf/controller/AppMenuController.java b/jnpf-app/jnpf-app-controller/src/main/java/jnpf/controller/AppMenuController.java
new file mode 100644
index 0000000..2c86fe0
--- /dev/null
+++ b/jnpf-app/jnpf-app-controller/src/main/java/jnpf/controller/AppMenuController.java
@@ -0,0 +1,93 @@
+package jnpf.controller;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import jnpf.base.ActionResult;
+import jnpf.base.Page;
+import jnpf.base.entity.ModuleEntity;
+import jnpf.base.entity.SystemEntity;
+import jnpf.base.model.module.ModuleModel;
+import jnpf.base.service.ModuleService;
+import jnpf.base.service.SystemService;
+import jnpf.base.vo.ListVO;
+import jnpf.constant.PermissionConst;
+import jnpf.model.AppMenuListVO;
+import jnpf.model.UserMenuModel;
+import jnpf.permission.entity.OrganizeAdministratorEntity;
+import jnpf.permission.model.authorize.AuthorizeVO;
+import jnpf.permission.service.AuthorizeService;
+import jnpf.permission.service.OrganizeAdministratorService;
+import jnpf.util.JsonUtil;
+import jnpf.util.StringUtil;
+import jnpf.util.UserProvider;
+import jnpf.util.treeutil.ListToTreeUtil;
+import jnpf.util.treeutil.SumTree;
+import jnpf.util.treeutil.newtreeutil.TreeDotUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * app应用
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司(https://www.jnpfsoft.com)
+ * @date 2021-07-08
+ */
+@Tag(name = "app应用", description = "Menu")
+@RestController
+@RequestMapping("/api/app/Menu")
+public class AppMenuController {
+
+ @Autowired
+ private ModuleService moduleApi;
+ @Autowired
+ private AuthorizeService authorizeService;
+ @Autowired
+ private UserProvider userProvider;
+ @Autowired
+ private OrganizeAdministratorService organizeAdminTratorApi;
+ @Autowired
+ private SystemService systemApi;
+
+ /**
+ * 获取菜单列表
+ *
+ * @param page 分页模型
+ * @return
+ */
+ @Operation(summary = "获取菜单列表")
+ @GetMapping
+ public ActionResult> list(Page page) {
+ // 从分级管理获取应用权限后获取菜单
+ List listByUserId = organizeAdminTratorApi.getOrganizeAdministratorEntity(UserProvider.getLoginUserId(), PermissionConst.SYSTEM, false);
+ List systemEntities = systemApi.getListByIds(listByUserId.stream().map(OrganizeAdministratorEntity::getOrganizeId).collect(Collectors.toList()));
+ List moduleBySystemIds = moduleApi.getModuleBySystemIds(systemEntities.stream().map(SystemEntity::getId).collect(Collectors.toList()));
+ List jsonToList = JsonUtil.getJsonToList(moduleBySystemIds, ModuleModel.class);
+ List listByUserId1 = organizeAdminTratorApi.getOrganizeAdministratorEntity(UserProvider.getLoginUserId(), PermissionConst.MODULE, false);
+ List moduleEntities = moduleApi.getModuleByIds(listByUserId1.stream().map(OrganizeAdministratorEntity::getOrganizeId).collect(Collectors.toList()));
+ List jsonToList1 = JsonUtil.getJsonToList(moduleEntities, ModuleModel.class);
+ AuthorizeVO authorizeModel = authorizeService.getAuthorize(true, true);
+ List buttonListAll = authorizeModel.getModuleList().stream().filter(t -> "App".equals(t.getCategory())).collect(Collectors.toList());
+ buttonListAll.addAll(jsonToList);
+ buttonListAll.addAll(jsonToList1);
+ // 通过系统id捞取相应的菜单
+ buttonListAll = buttonListAll.stream().distinct().filter(t -> userProvider.get().getAppSystemId() != null && userProvider.get().getAppSystemId().equals(t.getSystemId()) && "App".equals(t.getCategory())).collect(Collectors.toList());
+ List buttonList = buttonListAll;
+ if (StringUtil.isNotEmpty(page.getKeyword())) {
+ buttonList = buttonListAll.stream().filter(t -> t.getFullName().contains(page.getKeyword())).collect(Collectors.toList());
+ }
+ List list = JsonUtil.getJsonToList(ListToTreeUtil.treeWhere(buttonList, buttonListAll), UserMenuModel.class);
+ List> menuAll = TreeDotUtils.convertListToTreeDot(list, "-1");
+ List data = JsonUtil.getJsonToList(menuAll, AppMenuListVO.class);
+ ListVO listVO = new ListVO();
+ listVO.setList(data);
+ return ActionResult.success(listVO);
+ }
+
+}
diff --git a/jnpf-app/jnpf-app-controller/src/main/java/jnpf/controller/AppUserController.java b/jnpf-app/jnpf-app-controller/src/main/java/jnpf/controller/AppUserController.java
new file mode 100644
index 0000000..9079b7b
--- /dev/null
+++ b/jnpf-app/jnpf-app-controller/src/main/java/jnpf/controller/AppUserController.java
@@ -0,0 +1,62 @@
+package jnpf.controller;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.Operation;
+import jnpf.base.ActionResult;
+import jnpf.model.AppUserInfoVO;
+import jnpf.model.AppUsersVO;
+import jnpf.model.AppUserInfoVO;
+import jnpf.service.AppService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 用户信息
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司(https://www.jnpfsoft.com)
+ * @date 2021-07-08
+ */
+@Tag(name = "app用户信息", description = "User")
+@RestController
+@RequestMapping("/api/app/User")
+public class AppUserController {
+
+ @Autowired
+ private AppService appService;
+
+ /**
+ * 用户信息
+ *
+ * @return
+ */
+ @Operation(summary = "用户信息")
+ @GetMapping
+ public ActionResult getInfo() {
+ AppUsersVO userAllVO = appService.userInfo();
+ return ActionResult.success(userAllVO);
+ }
+
+ /**
+ * 通讯录详情
+ *
+ * @param id 主键
+ * @return
+ */
+ @Operation(summary = "通讯录详情")
+ @GetMapping("/{id}")
+ @Parameters({
+ @Parameter(name = "id", description = "主键", required = true),
+ })
+ public ActionResult userInfo(@PathVariable("id") String id) {
+ AppUserInfoVO userInfoVO = appService.getInfo(id);
+ return ActionResult.success(userInfoVO);
+ }
+
+}
diff --git a/jnpf-app/jnpf-app-controller/src/main/java/jnpf/controller/AppVersionController.java b/jnpf-app/jnpf-app-controller/src/main/java/jnpf/controller/AppVersionController.java
new file mode 100644
index 0000000..66fd9d6
--- /dev/null
+++ b/jnpf-app/jnpf-app-controller/src/main/java/jnpf/controller/AppVersionController.java
@@ -0,0 +1,45 @@
+package jnpf.controller;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import jnpf.base.ActionResult;
+import jnpf.util.NoDataSourceBind;
+import jnpf.base.service.SysconfigService;
+import org.apache.commons.collections4.map.HashedMap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+/**
+ * 获取AppVersion
+ *
+ * @author :JNPF开发平台组
+ * @version: V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date :2022/3/31 11:26
+ */
+@Tag(name = "获取APP版本号", description = "AppVersion")
+@RestController
+@RequestMapping("/api/app")
+public class AppVersionController {
+ @Autowired
+ private SysconfigService sysconfigService;
+
+ /**
+ * 判断是否需要验证码
+ *
+ * @return
+ */
+ @NoDataSourceBind()
+ @Operation(summary = "判断是否需要验证码")
+ @GetMapping("/Version")
+ public ActionResult getAppVersion() {
+ String sysVersion = sysconfigService.getSysInfo().getSysVersion();
+ Map map = new HashedMap<>();
+ map.put("sysVersion", sysVersion);
+ return ActionResult.success(map);
+ }
+}
diff --git a/jnpf-app/jnpf-app-entity/pom.xml b/jnpf-app/jnpf-app-entity/pom.xml
new file mode 100644
index 0000000..b6e234c
--- /dev/null
+++ b/jnpf-app/jnpf-app-entity/pom.xml
@@ -0,0 +1,22 @@
+
+
+
+ jnpf-app
+ com.jnpf
+ 3.5.0-RELEASE
+
+ 4.0.0
+
+ jnpf-app-entity
+
+
+
+ com.jnpf
+ jnpf-common-all
+ ${project.version}
+
+
+
+
\ No newline at end of file
diff --git a/jnpf-app/jnpf-app-entity/src/main/java/jnpf/entity/AppDataEntity.java b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/entity/AppDataEntity.java
new file mode 100644
index 0000000..289d079
--- /dev/null
+++ b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/entity/AppDataEntity.java
@@ -0,0 +1,46 @@
+package jnpf.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import jnpf.base.entity.SuperExtendEntity;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * app常用数据
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021-08-08
+ */
+@Data
+@TableName("base_app_data")
+public class AppDataEntity extends SuperExtendEntity.SuperExtendDEEntity {
+
+ /**
+ * 对象类型
+ */
+ @TableField("f_object_type")
+ private String objectType;
+
+ /**
+ * 对象主键
+ */
+ @TableField("f_object_id")
+ private String objectId;
+
+ /**
+ * 数据
+ */
+ @TableField("f_object_data")
+ private String objectData;
+
+ /**
+ * 关联系统id
+ */
+ @TableField("f_system_id")
+ private String systemId;
+
+}
diff --git a/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppDataCrForm.java b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppDataCrForm.java
new file mode 100644
index 0000000..e4d3b81
--- /dev/null
+++ b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppDataCrForm.java
@@ -0,0 +1,30 @@
+package jnpf.model;
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * app常用数据
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021-07-08
+ */
+@Data
+@Schema(description = "常用模型")
+public class AppDataCrForm {
+ @NotBlank(message = "必填")
+ @Schema(description = "应用类型")
+ private String objectType;
+ @NotBlank(message = "必填")
+ @Schema(description = "应用主键")
+ private String objectId;
+ @Schema(description = "数据")
+ private String objectData;
+ @Schema(description = "系统主键")
+ private String systemId;
+}
diff --git a/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppDataListAllVO.java b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppDataListAllVO.java
new file mode 100644
index 0000000..fbed765
--- /dev/null
+++ b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppDataListAllVO.java
@@ -0,0 +1,40 @@
+package jnpf.model;
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * app常用数据
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021-07-08
+ */
+@Data
+@Schema(description = "常用模型")
+public class AppDataListAllVO {
+ @Schema(description = "主键")
+ private String id;
+ @Schema(description = "是否有下级菜单")
+ private Boolean hasChildren;
+ @Schema(description = "菜单名称")
+ private String fullName;
+ @Schema(description = " 图标")
+ private String icon;
+ @Schema(description = "链接地址")
+ private String urlAddress;
+ @Schema(description = "父级id")
+ private String parentId;
+ @Schema(description = "菜单类型",example = "1")
+ private Integer type;
+ @Schema(description = "扩展字段")
+ private String propertyJson;
+ @Schema(description = "是否常用")
+ private Boolean isData;
+ @Schema(description = "下级菜单列表")
+ private List children;
+}
diff --git a/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppDataListVO.java b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppDataListVO.java
new file mode 100644
index 0000000..2cf89e5
--- /dev/null
+++ b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppDataListVO.java
@@ -0,0 +1,24 @@
+package jnpf.model;
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * app常用数据
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021-07-08
+ */
+@Data
+@Schema(description = "常用模型")
+public class AppDataListVO {
+ @Schema(description = "主键")
+ private String id;
+ @Schema(description = "应用主键")
+ private String objectId;
+ @Schema(description = "数据")
+ private String objectData;
+}
diff --git a/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppFlowListAllVO.java b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppFlowListAllVO.java
new file mode 100644
index 0000000..0e9c0ee
--- /dev/null
+++ b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppFlowListAllVO.java
@@ -0,0 +1,30 @@
+package jnpf.model;
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * app常用数据
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021-07-08
+ */
+@Data
+@Schema(description = "常用模型")
+public class AppFlowListAllVO {
+ @Schema(description = "主键")
+ private String id;
+ @Schema(description = "名称")
+ private String fullName;
+ @Schema(description = "图标")
+ private String icon;
+ @Schema(description = "图标背景色")
+ private String iconBackground;
+ @Schema(description = "编码")
+ private String enCode;
+ @Schema(description = "是否常用")
+ private Boolean isData;
+}
diff --git a/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppMenuListVO.java b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppMenuListVO.java
new file mode 100644
index 0000000..2b00d8b
--- /dev/null
+++ b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppMenuListVO.java
@@ -0,0 +1,40 @@
+package jnpf.model;
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * app应用
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021-07-08
+ */
+@Data
+@Schema(description = "常用模型")
+public class AppMenuListVO {
+ @Schema(description = "主键")
+ private String id;
+ @Schema(description = "是否有下级菜单")
+ private Boolean hasChildren;
+ @Schema(description = "父级id")
+ private String parentId;
+ @Schema(description = "菜单名称")
+ private String fullName;
+ @Schema(description = " 图标")
+ private String icon;
+ @Schema(description = "是否常用")
+ private Boolean isData;
+ @Schema(description = "链接地址")
+ private String urlAddress;
+ @Schema(description = "菜单类型",example = "1")
+ private Integer type;
+ @Schema(description = "扩展字段")
+ private String propertyJson;
+ @Schema(description = "下级菜单列表")
+ private List children;
+}
diff --git a/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppPositionVO.java b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppPositionVO.java
new file mode 100644
index 0000000..38469e4
--- /dev/null
+++ b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppPositionVO.java
@@ -0,0 +1,22 @@
+package jnpf.model;
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * app应用
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021-08-08
+ */
+@Data
+@Schema(description = "常用模型")
+public class AppPositionVO {
+ @Schema(description = "岗位id")
+ private String id;
+ @Schema(description = "岗位名称")
+ private String name;
+}
diff --git a/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppUserInfoVO.java b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppUserInfoVO.java
new file mode 100644
index 0000000..d2dc9ec
--- /dev/null
+++ b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppUserInfoVO.java
@@ -0,0 +1,37 @@
+package jnpf.model;
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021/3/12 15:31
+ */
+@Data
+@Schema(description = "常用模型")
+public class AppUserInfoVO {
+ @Schema(description = "主键")
+ private String id;
+ @Schema(description = "户名")
+ private String realName;
+ @Schema(description = "部门名称")
+ private String organizeName;
+ @Schema(description = "账号")
+ private String account;
+ @Schema(description = "岗位名称")
+ private String positionName;
+ @Schema(description = "办公电话")
+ private String telePhone;
+ @Schema(description = "办公座机")
+ private String landline;
+ @Schema(description = "手机号码")
+ private String mobilePhone;
+ @Schema(description = "用户头像")
+ private String headIcon;
+ @Schema(description = "邮箱")
+ private String email;
+}
diff --git a/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppUsersVO.java b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppUsersVO.java
new file mode 100644
index 0000000..b8bbc25
--- /dev/null
+++ b/jnpf-app/jnpf-app-entity/src/main/java/jnpf/model/AppUsersVO.java
@@ -0,0 +1,50 @@
+package jnpf.model;
+
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 用户
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021-07-08
+ */
+@Data
+@Schema(description = "常用模型")
+public class AppUsersVO {
+ @Schema(description = "用户id")
+ private String userId;
+ @Schema(description = "用户账号")
+ private String userAccount;
+ @Schema(description = "用户姓名")
+ private String userName;
+ @Schema(description = "用户头像")
+ private String headIcon;
+ @Schema(description = "组织主键")
+ private String organizeId;
+ @Schema(description = "组织名称")
+ private String organizeName;
+ @Schema(description = "角色主键")
+ private String roleId;
+ @Schema(description = "角色名称")
+ private String roleName;
+ @Schema(description = "性别")
+ private Integer gender;
+ @Schema(description = "岗位")
+ private List positionIds;
+ @Schema(description = "生日")
+ private Long birthday;
+ @Schema(description = "手机")
+ private String mobilePhone;
+ @Schema(description = "邮箱")
+ private String email;
+ @Schema(description = "直属主管")
+ private String manager;
+
+}
diff --git a/jnpf-app/pom.xml b/jnpf-app/pom.xml
new file mode 100644
index 0000000..5c36a03
--- /dev/null
+++ b/jnpf-app/pom.xml
@@ -0,0 +1,20 @@
+
+
+
+ jnpf-java-boot
+ com.jnpf
+ 3.5.0-RELEASE
+
+ 4.0.0
+
+ jnpf-app
+ pom
+
+ jnpf-app-entity
+ jnpf-app-biz
+ jnpf-app-controller
+
+
+
diff --git a/jnpf-example/pom.xml b/jnpf-example/pom.xml
new file mode 100644
index 0000000..61fb2c1
--- /dev/null
+++ b/jnpf-example/pom.xml
@@ -0,0 +1,20 @@
+
+
+
+ jnpf-java-boot
+ com.jnpf
+ 3.5.0-RELEASE
+
+ 4.0.0
+
+ jnpf-example
+ pom
+
+ jnpf-example-entity
+ jnpf-example-biz
+ jnpf-example-controller
+
+
+
diff --git a/jnpf-exception/pom.xml b/jnpf-exception/pom.xml
new file mode 100644
index 0000000..6bdb50a
--- /dev/null
+++ b/jnpf-exception/pom.xml
@@ -0,0 +1,31 @@
+
+
+
+ jnpf-java-boot
+ com.jnpf
+ 3.5.0-RELEASE
+
+ 4.0.0
+
+ jnpf-exception
+
+
+ com.jnpf
+ jnpf-common-auth
+
+
+ com.jnpf
+ jnpf-common-all
+ ${project.version}
+
+
+ com.jnpf
+ jnpf-oauth-entity
+ ${project.version}
+
+
+
+
+
\ No newline at end of file
diff --git a/jnpf-exception/src/main/java/jnpf/controller/LogController.java b/jnpf-exception/src/main/java/jnpf/controller/LogController.java
new file mode 100644
index 0000000..0ac5804
--- /dev/null
+++ b/jnpf-exception/src/main/java/jnpf/controller/LogController.java
@@ -0,0 +1,144 @@
+package jnpf.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import jnpf.base.controller.SuperController;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import jnpf.base.ActionResult;
+import jnpf.base.PaginationTime;
+import jnpf.base.vo.PaginationVO;
+import jnpf.constant.MsgCode;
+import jnpf.entity.LogEntity;
+import jnpf.model.*;
+import jnpf.service.LogService;
+import jnpf.util.JsonUtil;
+import jnpf.util.StringUtil;
+import org.apache.commons.collections4.map.HashedMap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * 系统日志
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2019年9月27日 上午9:18
+ */
+@Tag(name = "系统日志", description = "Log")
+@RestController
+@RequestMapping("/api/system/Log")
+public class LogController extends SuperController {
+
+ @Autowired
+ private LogService logService;
+
+
+ /**
+ * 获取系统日志信息
+ *
+ * @param category 主键值分类 1:登录日志,2.访问日志,3.操作日志,4.异常日志,5.请求日志
+ * @return
+ */
+ @Operation(summary = "获取系统日志列表")
+ @Parameters({
+ @Parameter(name = "category", description = "分类", required = true)
+ })
+ @SaCheckPermission("system.log")
+ @GetMapping("/{category}")
+ public ActionResult getInfoList(@PathVariable("category") String category, PaginationLogModel paginationTime) {
+ if (StringUtil.isEmpty(category) || !StringUtil.isNumeric(category)) {
+ return ActionResult.fail("获取失败");
+ }
+ List list = logService.getList(Integer.parseInt(category), paginationTime);
+ PaginationVO paginationVO = JsonUtil.getJsonToBean(paginationTime, PaginationVO.class);
+ int i = Integer.parseInt(category);
+ switch (i) {
+ case 1:
+ List loginLogVOList = JsonUtil.getJsonToList(list, LoginLogVO.class);
+ return ActionResult.page(loginLogVOList, paginationVO);
+ case 3:
+ List handleLogVOList = JsonUtil.getJsonToList(list, HandleLogVO.class);
+ for (int j = 0; j < handleLogVOList.size(); j++) {
+ handleLogVOList.get(j).setJson(list.get(j).getJsons());
+ }
+ return ActionResult.page(handleLogVOList, paginationVO);
+ case 4:
+ List errorLogVOList = JsonUtil.getJsonToList(list, ErrorLogVO.class);
+ for (int j = 0; j < errorLogVOList.size(); j++) {
+ errorLogVOList.get(j).setJson(list.get(j).getJsons());
+ }
+ return ActionResult.page(errorLogVOList, paginationVO);
+ case 5:
+ List requestLogVOList = JsonUtil.getJsonToList(list, RequestLogVO.class);
+ return ActionResult.page(requestLogVOList, paginationVO);
+ default:
+ return ActionResult.fail("获取失败");
+ }
+ }
+
+ /**
+ * 批量删除系统日志
+ *
+ * @param logDelForm 批量删除日志模型
+ * @return
+ */
+ @Operation(summary = "批量删除系统日志")
+ @Parameters({
+ @Parameter(name = "logDelForm", description = "批量删除日志模型", required = true)
+ })
+ @SaCheckPermission("system.log")
+ @DeleteMapping
+ public ActionResult delete(@RequestBody LogDelForm logDelForm) {
+ boolean flag = logService.delete(logDelForm.getIds());
+ if (flag == false) {
+ return ActionResult.fail(MsgCode.FA003.get());
+ }
+ return ActionResult.success(MsgCode.SU003.get());
+ }
+
+ /**
+ * 一键清空操作日志
+ *
+ * @param type 分类
+ * @return
+ */
+ @Operation(summary = "一键清空操作日志")
+ @Parameters({
+ @Parameter(name = "type", description = "分类", required = true)
+ })
+ @SaCheckPermission("system.log")
+ @DeleteMapping("/{type}")
+ public ActionResult deleteHandelLog(@PathVariable("type") String type) {
+ logService.deleteHandleLog(type);
+ return ActionResult.success(MsgCode.SU005.get());
+ }
+
+ /**
+ * 获取菜单名
+ *
+ * @return
+ */
+ @Operation(summary = "获取菜单名")
+ @SaCheckPermission("system.log")
+ @GetMapping("/ModuleName")
+ public ActionResult>> moduleName() {
+ List