15 Commits
Author SHA1 Message Date
vben 60edc1d39c 修改readme
Signed-off-by: vben <fohozq@163.com>
2026-01-14 11:58:32 +00:00
小犹太 a30f2e746a update README.md.
Signed-off-by: 小犹太 <676948472@qq.com>
2026-01-14 11:50:46 +00:00
vben 25f90f2d19 修复三级菜单导航异常 2025-12-31 08:08:08 +08:00
vben e999e9f873 数据库字段命名优化 2025-12-24 13:31:56 +08:00
vben 3d832fb22c 组织架构与权限管理扁平化 2025-12-22 14:42:56 +08:00
vben 66fe29c7dd 增加微信联系方式,欢迎加微信进微信交流群 2025-12-18 19:39:47 +08:00
vben a2d84353cc 增加代码生成与可视化表单模块 2025-12-16 12:30:54 +08:00
vben f8b6ef4cb6 增加crud~demo案例 2025-12-03 17:06:45 +08:00
vben 115787922b update README.md.
修改移动端技术栈,尝试uni-app x 体验地址见README.md

Signed-off-by: vben <fohozq@163.com>
2025-11-29 15:38:24 +00:00
vben 5242760d08 流程优化 2025-11-17 19:10:11 +08:00
vben 0265651d94 修改文档地址 2025-11-16 09:56:51 +08:00
vben a538dd5497 修改readme 2025-11-16 09:20:26 +08:00
vben c5e29b9f3b 修改默认附件上传地址 2025-11-15 18:05:53 +08:00
vben 40c8bbd641 新版本初始化2025-11-15 2025-11-15 16:25:20 +08:00
vben ab83308a4e 老版本归档与清理 2025-11-15 13:28:18 +08:00
1245 changed files with 62888 additions and 28136 deletions
+18
View File
@@ -0,0 +1,18 @@
# http://editorconfig.org
root = true
# 空格替代Tab缩进在各种编辑工具下效果一致
[*]
indent_style = space
indent_size = 4
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
[*.{json,yml,yaml}]
indent_size = 2
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
+50 -12
View File
@@ -1,12 +1,50 @@
# 项目排除路径
/vben-admin/target/
/vben-admin/src/main/resources/static/
/vben-admin-bi/target/
/vben-admin-bi/src/main/resources/static/
/vben-core/target/
/vben-extend/target/
/vben-extend-bi/target/
/.idea/
#/vben-extend/src/main/java/vben/extend/bi/
#/vben-extend/src/main/java/vben/extend/sa/
#/vben-extend/src/main/java/vben/extend/te/
######################################################################
# Build Tools
.gradle
/build/
!gradle/wrapper/gradle-wrapper.jar
target/
!.mvn/wrapper/maven-wrapper.jar
######################################################################
# IDE
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
logs
zsvg
### JRebel ###
rebel.xml
### NetBeans ###
nbproject/private/
build/*
nbbuild/
nbdist/
.nb-gradle/
######################################################################
# Others
*.log
*.xml.versionsBackup
*.swp
!*/build/*.java
!*/build/*.html
!*/build/*.xml
.flattened-pom.xml
-3
View File
@@ -1,3 +0,0 @@
- **初始化项目 V0.2**
- [更新] README.md、项目介绍
+13 -14
View File
@@ -1,21 +1,20 @@
MIT License
The MIT License (MIT)
Copyright (c) 2022 vben
Copyright (c) 2026 vben
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+427 -54
View File
@@ -1,63 +1,436 @@
<div align="center"><h1 align="center">vben-java</h1></div>
<div align="center"><h3 align="center">一个开箱即用的快速开发平台JAVA版</h3></div>
### 🍿 项目简介
# 🍿 相关地址
* PC端体验地址 :[http://8.153.168.178/](http://8.153.168.178/) (演示版本采用最新vben5版本)
* 移动端体验地址 :[http://8.153.168.178/unibest/](http://8.153.168.178/unibest/)
* 文档地址 :[http://8.153.168.178/doc](http://8.153.168.178/doc)
* QQ交流群:[795417789](https://jq.qq.com/?_wv=1027&k=yoKKIlIG)
[![码云Gitee](https://gitee.com/vben/vben-java/badge/star.svg?theme=blue)](https://gitee.com/vben/vben-java)
[![License](https://img.shields.io/badge/License-MIT-blue.svg)]()
[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.4-blue.svg)]()
[![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]()
[![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]()
### 🍟 概述
* 特别说明:vben系列项目是由https://gitee.com/zsvg 大哥原vboot项目转移的。
* 特别说明:目前前端是基于vue-next-admin的,vben5 ui目前正在适配中。
* 基于JAVA实现的快速开发平台。模块化插件式开发,前后端分离,开箱即用。
* 后台基于SpringBoot框架,数据库访问同时集成了Jpa与MyBatis-Plus,即可自动生成数据库表结构,又可灵活编写sql。
* 前端基于vue-next-admin/vben框架,引入了bpmn.js工作流、VForm可视化表单。
* 前端项目地址:[https://gitee.com/vben/vben-ui](https://gitee.com/vben/vben-ui)
* .NET8实现的同功能项目地址[https://gitee.com/vben/vben-net](https://gitee.com/vben/vben-net) 两个项目会同步开发
vben-java 是一款基于SpringBoot3+Vue3的前后端分离快速开发框架。
### 🍄 快速启动
* 准备工作:1.配置一个名为vben-java的mysql数据库,默认账号root,密码123456(可改) 2.开启redis 可不设置密码
* 启动后台:打开项目,找到vben-admin下的vbenApplication启动类启动运行
* 启动前端:下载配套的前端UI[https://gitee.com/vben/vben-ui](https://gitee.com/vben/vben-ui)使用npm构建,访问 `http://localhost:868` 预览
后端基于 [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) 改造,集成业界一流技术栈,针对企业痛点,具有组件化、模块化、轻耦合、高扩展等特色。
应用层可自由选择ORM框架(Mybatis Plus,JPA)
### 🏀 分层说明
```
├─vben-admin ->自定义管理应用层,在此写您具体业务代码
├─vben-core ->框架核心层,包含框架集成,基础模块与通用工具类等
├─vben-extend ->框架扩展层,包含扩展的常用功能与模块
注:建议将自己的业务代码写在【vben-admin】层里面,可随框架升级减少冲突。
```
前端基于 [Vben Admin](https://github.com/vbenjs/vue-vben-admin) 改造,使用最新前端技术栈,提供丰富的组件和模板以及N种偏好设置组合方案,
应用层可自由选择UI框架(Element Plus,Ant Design Vue,Native UI)
### 🍖 详细功能
1. 主控面板:控制台页面,可进行工作台,分析页,统计等功能的展示。
2. 部门管理:部门维护,支持多层级结构的树形结构。
3. 用户管理:用户维护,可设置用户部门,岗位,群组,职务,角色,数据权限等。
4. 岗位管理:岗位维护,岗位可作为用户的一个标签,岗位也可与权限等其他功能挂钩。
5. 群组管理:群组维护,群组可设置部门,用户,岗位,用于更广泛的权限设置。
6. 菜单管理:菜单目录,菜单,和按钮的维护是权限控制的基本单位。
7. 角色管理:角色绑定菜单后,可限制相关角色的人员登录系统的功能范围。
8. 字典管理:系统内各种枚举类型的维护。
9. 访问日志:用户的登录和退出日志的查看和管理。
10. 操作日志:用户的操作业务的日志的查看和管理。
11. 定时任务:定时任务的维护,通过cron表达式控制任务的执行频率。
12. 流程引擎:流程图展示,自解析bpmn.js,支持驳回、转办、废弃,跳转等功能
13. 在线表单:在线表单设计,配合流程可以实现表单数据流转
14. 消息机制:待办待阅功能,联通钉钉与企业微信接口
15. 代码生成:在线配置,一键生成前后端代码
移动端基于 [cool-unix](https://gitee.com/cool-team-official/cool-unix) 改造,参照了unibest的方式,通过pnpm集成,
除了可继续使用HBuilderX,还可以使用VS Code,Webstorm 开发运行uni-app x 应用(WEB与小程序)。注:安卓、苹果、鸿蒙端的运行还是需要借助HBuilderX。
### ⚡ 近期计划
- [ ] 完善文档
- [ ] 完善工作流
### 🍟 相关地址
* 前端WEB 体验地址 :[http://8.153.168.178/](http://8.153.168.178/)
* 移动端APP 体验地址 :[http://8.153.168.178/app/](http://8.153.168.178/app/)
* 文档地址 :[http://8.153.168.178/java-doc](http://8.153.168.178/java-doc)
* 后端API 项目地址 https://gitee.com/vben/vben-java
* 前端WEB 项目地址 https://gitee.com/vben/vben-web
* 移动端APP 项目地址 https://gitee.com/vben/vben-app
* 同功能.net后端 项目地址 https://gitee.com/vben/vben-net
* 联系方式(加微信后可找小狐狸拉进交流群):
![输入图片说明](https://gitee.com/vben/vben-app/raw/master/docs/wx.jpg "微信联系方式")
### ⚡ 快速启动
后端
* 准备工作:1. 准备java17及以上版本,修改pom.xml对应java.version 2. 根据application-dev.yml配置文件准备一个空的数据库,默认为vben-java的mysql数据库,账号root,密码123456 3. 开启redis 默认密码为空
* 数据库初始化:启动VbenSetup,程序会自动创建数据库表与初始化表数据,生成完成后VbenSet应用会自动关闭
* 启动后台API:启动VbenAdmin,也可启动VbenJpa或VbenMybatis查看相应DEMO示例
前端
* 准备工作:准备Node.js 20.15.0以上环境,全局安装pnpm:npm install -g pnpm
* 启动前台WEB:1. 使用pnpm install安装依赖 2. 使用pnpm dev:ele运行项目 3.访问 http://localhost:5666/ 预览
### 🍄 主要特色
- 后端项目中抽离并拆分了公共功能,以插件化与扩展包的方式组织,结构解耦且易于扩展。
- 后端项目业务模块以多基础模块与多应用方式组织,可实现多个应用共用相同基础模块,方便实现基础模块共享
- 后端项目基础业务模块采用JdbcTemplate实现,上层应用可采用mybatis-plus或者jpa,选择留给用户
- 工作流模块不依赖其他工作流引擎,全部自行实现,易于扩展,实现复杂工作流
- 统一的命名风格,数据库表主键统一用ID命名,表字段采用SAP风格(后端手册里有详细介绍)
### 🏀 技术选型
后端框架基于RuoYi-Vue-Plus,因此包含了RuoYi-Vue-Plus框架的几乎所有技术栈,
采用Mybatis Plus方式可保留原有框架所有功能,采用JPA方式可实现更强大的ORM功能。
RuoYi-Vue-Plus框架对分布式支持比较好,vben-java框架在支持分布式的同时可更方便的实现单机模式
<table>
<thead>
<tr>
<th width="150" align="center">功能模块</th>
<th width="*">RuoYi-Vue-Plus</th>
<th width="300" align="center">vben-java</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">Web容器</td>
<td>采用 Undertow 基于 XNIO 的高性能容器</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">权限认证</td>
<td>采用 Sa-Token、Jwt 静态使用功能齐全 低耦合 高扩展</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">权限注解</td>
<td>采用 Sa-Token 支持注解 登录校验、角色校验、权限校验、二级认证校验、HttpBasic校验、忽略校验角色与权限校验支持多种条件
如 AND OR 或 权限 OR 角色 等复杂表达式
</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">三方鉴权</td>
<td>采用 JustAuth 第三方登录组件 支持微信、钉钉等数十种三方认证</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">关系数据库支持</td>
<td>原生支持 MySQL、Oracle、PostgreSQL、SQLServer可同时使用异构切换(支持其他 mybatis-plus 支持的所有数据库
只需要增加jdbc依赖即可使用 达梦金仓等均有成功案例)
</td>
<td align="center">√ 基础与核心业务模块采用JdbcTemplate实现,上层应用可采用mybatis-plus或者jpa</td>
</tr>
<tr>
<td align="center">缓存数据库</td>
<td>支持 Redis 5-7 支持大部分新功能特性 如 分布式限流、分布式队列</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">Redis客户端</td>
<td>采用 Redisson Redis官方推荐 基于Netty的客户端工具支持Redis 90%以上的命令 底层优化规避很多不正确的用法 例如:
keys被转换为scan支持单机、哨兵、单主集群、多主集群等模式
</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">缓存注解</td>
<td>采用 Spring-Cache 注解 对其扩展了实现支持了更多功能 例如过期时间 最大空闲时间 组最大长度等
只需一个注解即可完成数据自动缓存
</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">ORM框架</td>
<td>采用 Mybatis-Plus 基于对象几乎不用写SQL全java操作 功能强大插件众多 例如多租户插件 分页插件 乐观锁插件等等
</td>
<td align="center">√ JPA方式可实现功能更全的ORM功能,比如自动生成表结构</td>
</tr>
<tr>
<td align="center">SQL监控</td>
<td>采用 p6spy 可输出完整SQL与执行时间监控</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">数据分页</td>
<td>采用 Mybatis-Plus 分页插件 框架对其进行了扩展 对象化分页对象 支持多种方式传参 支持前端多排序 复杂排序</td>
<td align="center">√ JdbcTemplate Mybatis JPA 三种方式都可轻松实现数据分页</td>
</tr>
<tr>
<td align="center">数据权限</td>
<td>采用 Mybatis-Plus 插件 自行分析拼接SQL 无感式过滤只需为Mapper设置好注解条件 支持多种自定义 不限于部门角色
</td>
<td align="center">√ 可采用此方式,另外组织架构模块增加了群组模块,可实现更灵活的数据权限控制</td>
</tr>
<tr>
<td align="center">数据脱敏</td>
<td>采用 注解 + jackson 序列化期间脱敏 支持不同模块不同的脱敏条件支持多种策略 如身份证、手机号、地址、邮箱、银行卡等
可自行扩展
</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">数据加解密</td>
<td>采用 注解 + mybatis 拦截器 对存取数据期间自动加解密支持多种策略 如BASE64、AES、RSA、SM2、SM4等</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">接口传输加密</td>
<td>采用 动态 AES + RSA 加密请求 body 每一次请求秘钥都不同大幅度降低可破解性</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">数据翻译</td>
<td>采用 注解 + jackson 序列化期间动态修改数据 数据进行翻译,支持多种模式: 映射翻译 直接翻译 其他扩展条件翻译
接口化两步即可完成自定义扩展 内置多种翻译实现
</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">多数据源框架</td>
<td>采用 dynamic-datasource 支持市面大部分数据库,通过yml配置即可动态管理异构不同种类的数据库
也可通过前端页面添加数据源,支持spel表达式从请求头参数等条件切换数据源
</td>
<td align="center">√ mybatis-plus方式支持动态数据源,<br/> × jpa方式不支持动态数据源,需要单独配置引入多数据源
</td>
</tr>
<tr>
<td align="center">多数据源事务</td>
<td>采用 dynamic-datasource 支持多数据源不同种类的数据库事务回滚</td>
<td align="center">√ mybatis-plus方式多数据源事务,<br/> × jpa方式不支多数据源事务</td>
</tr>
<tr>
<td align="center">数据库连接池</td>
<td>采用 HikariCP Spring官方内置连接池 配置简单 以性能与稳定性闻名天下</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">数据库主键</td>
<td>采用 雪花ID 基于时间戳的 有序增长 唯一ID 再也不用为分库分表 数据合并主键冲突重复而发愁</td>
<td align="center">√
支持雪花ID,为了兼容性支持,特别是需要与其他业务系统关联的基础组织架构模块,采用的是32位字符串UUID方式
</td>
</tr>
<tr>
<td align="center">WebSocket协议</td>
<td>基于 Spring 封装的 WebSocket 协议 扩展了Token鉴权与分布式会话同步 不再只是基于单机的废物</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">SSE推送</td>
<td>采用 Spring SSE 实现 扩展了Token鉴权与分布式会话同步</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">序列化</td>
<td>采用 Jackson Spring官方内置序列化 靠谱!!!</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">分布式幂等</td>
<td>参考美团GTIS防重系统简化实现</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">分布式任务调度</td>
<td>采用 SnailJob 天生支持分布式 统一的管理中心 支持多种数据库 支持分片重试DAG任务流等</td>
<td align="center">√
支持SnailJob分布式方式,另外项目也集成了Quartz,对于不需要分布式的项目可以更便捷地使用定时调度
</td>
</tr>
<tr>
<td align="center">文件存储</td>
<td>采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储,支持权限管理 安全可靠 文件可加密存储</td>
<td align="center">√ 支持Minio方式,另外项目也实现了本地文件存储方式供用户选择</td>
</tr>
<tr>
<td align="center">云存储</td>
<td>采用 AWS S3 协议客户端 支持 七牛、阿里、腾讯 等一切支持S3协议的厂家</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">短信</td>
<td>采用 sms4j 短信融合包 支持数十种短信厂家 只需在yml配置好厂家密钥即可使用 可多厂家共用</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">邮件</td>
<td>采用 mail-api 通用协议支持大部分邮件厂商</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">接口文档</td>
<td>采用 SpringDoc、javadoc 无注解零入侵基于java注释只需把注释写好 无需再写一大堆的文档注解了</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">校验框架</td>
<td>采用 Validation 支持注解与工具类校验 注解支持国际化</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">Excel框架</td>
<td>采用 Alibaba EasyExcel 基于插件化,框架对其增加了很多功能 例如 自动合并相同内容 自动排列布局 字典翻译等</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">工具类框架</td>
<td>采用 Hutool、Lombok 上百种工具覆盖90%的使用需求 基于注解自动生成 get set 等简化框架大量代码</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">监控框架</td>
<td>采用 SpringBoot-Admin 基于SpringBoot官方 actuator 探针机制,实时监控服务状态
框架还为其扩展了在线日志查看监控
</td>
<td align="center">√ 支持SpringBoot-Admin方式,另外项目也集成了oshi,可方便的实现单机服务器监控</td>
</tr>
<tr>
<td align="center">链路追踪</td>
<td>采用 Apache SkyWalking 还在为请求不知道去哪了
到哪出了问题而烦恼吗,用了它即可实时查看请求经过的每一处每一个节点
</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">代码生成器</td>
<td>只需设计好表结构 一键生成所有crud代码与页面,降低80%的开发量 把精力都投入到业务设计上,框架为其适配MP、SpringDoc规范化代码
同时支持动态多数据源代码生成
</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">部署方式</td>
<td>支持 Docker 编排 一键搭建所有环境 让开发人员从此不再为搭建环境而烦恼</td>
<td align="center">√</td>
</tr>
</tbody>
</table>
### 🍖 内置功能
后端框架基于RuoYi-Vue-Plus,表结构重新定义了,但是业务功能基本都有保留,比较遗憾的是放弃了对多租户的支持。
<table>
<thead>
<tr>
<th width="150" align="center">业务模块</th>
<th width="*">RuoYi-Vue-Plus</th>
<th width="300" align="center">vben-java</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">租户管理</td>
<td>系统内租户的管理 如:租户套餐、过期时间、用户数量、企业信息等</td>
<td align="center">×</td>
</tr>
<tr>
<td align="center">租户套餐管理</td>
<td>系统内租户所能使用的套餐管理 如:套餐内所包含的菜单等</td>
<td align="center">×</td>
</tr>
<tr>
<td align="center">客户端管理</td>
<td>系统内对接的所有客户端管理 如: pc端、小程序端等,支持动态授权登录方式 如: 短信登录、密码登录等 支持动态控制token时效</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">用户管理</td>
<td>用户的管理配置 如:新增用户、分配用户所属部门、角色、岗位等</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">部门管理</td>
<td>配置系统组织机构(公司、部门、小组) 树结构展现支持数据权限</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">岗位管理</td>
<td>配置系统用户所属担任职务</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">菜单管理</td>
<td>配置系统菜单、操作权限、按钮权限标识等</td>
<td align="center">√ 菜单管理分离为菜单管理(对应原目录与菜单)与接口管理(对应原按钮)</td>
</tr>
<tr>
<td align="center">角色管理</td>
<td>角色菜单权限分配、设置角色按机构进行数据范围权限划分</td>
<td align="center">√ 角色成员支持部门、用户、岗位、群组</td>
</tr>
<tr>
<td align="center">字典管理</td>
<td>对系统中经常使用的一些较为固定的数据进行维护</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">参数管理</td>
<td>对系统动态配置常用参数</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">通知公告</td>
<td>系统通知公告信息发布维护</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">操作日志</td>
<td>系统正常操作日志记录和查询 系统异常信息日志记录和查询</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">登录日志</td>
<td>系统登录日志记录查询包含登录异常</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">文件管理</td>
<td>系统文件展示、上传、下载、删除等管理</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">文件配置管理</td>
<td>系统文件上传、下载所需要的配置信息动态添加、修改、删除等管理</td>
<td align="center">√ 在支持分布式的同时可更方便的实现单机模式</td>
</tr>
<tr>
<td align="center">在线用户管理</td>
<td>已登录系统的在线用户信息监控与强制踢出操作</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">定时任务</td>
<td>运行报表、任务管理(添加、修改、删除)、日志管理、执行器管理等</td>
<td align="center">√ 在支持分布式的同时可更方便的实现单机模式</td>
</tr>
<tr>
<td align="center">代码生成</td>
<td>多数据源前后端代码的生成(java、html、xml、sql)支持CRUD下载</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">系统接口</td>
<td>根据业务代码自动生成相关的api接口文档</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">服务监控</td>
<td>监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等</td>
<td align="center">√ 在支持分布式的同时可更方便的实现单机模式</td>
</tr>
<tr>
<td align="center">缓存监控</td>
<td>对系统的缓存信息查询,命令统计等</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">在线构建器</td>
<td>拖动表单元素生成相应的HTML代码</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">使用案例</td>
<td>系统的一些功能案例</td>
<td align="center">√</td>
</tr>
<tr>
<td align="center">工作流</td>
<td>采用Warm-Flow工作流</td>
<td align="center">√ 前端流程图采用BPMN.js,表单采用FromCreate(FormDesigner),后端自行实现流程引擎</td>
</tr>
</tbody>
</table>
### 💐 特别鸣谢
- 👉 eladmin:[https://gitee.com/elunez/eladmin](https://gitee.com/elunez/eladmin)
- 👉 ruoyi:[https://gitee.com/y_project/RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue)
- 👉 Vben-Admin:[https://vvbin.cn/doc-next](https://vvbin.cn/doc-next)
- 👉 vue-next-admin:[https://gitee.com/lyt-top/vue-next-admin](https://gitee.com/lyt-top/vue-next-admin)
- 👉 vxe-table:[https://gitee.com/xuliangzhan_admin/vxe-table](https://gitee.com/xuliangzhan_admin/vxe-table)
- 👉 VForm:[https://www.vform666.com](https://www.vform666.com/)
- 👉 原框架作者:[zsvg](https://gitee.com/zsvg)
- 👉 Vben-Admin:[https://github.com/vbenjs/vue-vben-admin](https://github.com/vbenjs/vue-vben-admin)
- 👉 RuoYi-Vue-Plus:[https://gitee.com/dromara/RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus)
- 👉 FormCreate:[https://www.form-create.com/](https://www.form-create.com/)
```
如果对您有帮助,点击右上角⭐Star⭐关注 ,感谢支持开源!
```
+397 -31
View File
@@ -5,24 +5,95 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.zsvg</groupId>
<artifactId>vben</artifactId>
<packaging>pom</packaging>
<version>0.1</version>
<modules>
<module>vben-core</module>
<module>vben-extend</module>
<module>vben-admin</module>
</modules>
<artifactId>vben-java</artifactId>
<version>${revision}</version>
<name>vben-java</name>
<url>https://gitee.com/vben/vben-java</url>
<description>vben-admin 后台管理系统</description>
<!--定义属性值-->
<properties>
<revision>1.0.0</revision>
<spring-boot.version>3.5.7</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<vben.version>0.1</vben.version>
<spring.boot.version>2.5.15</spring.boot.version>
<java.version>21</java.version>
<mybatis.version>3.5.16</mybatis.version>
<springdoc.version>2.8.13</springdoc.version>
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
<fastexcel.version>1.3.0</fastexcel.version>
<velocity.version>2.3</velocity.version>
<satoken.version>1.44.0</satoken.version>
<mybatis-plus.version>3.5.14</mybatis-plus.version>
<p6spy.version>3.9.1</p6spy.version>
<hutool.version>5.8.40</hutool.version>
<spring-boot-admin.version>3.5.3</spring-boot-admin.version>
<redisson.version>3.51.0</redisson.version>
<lock4j.version>2.2.7</lock4j.version>
<dynamic-ds.version>4.3.1</dynamic-ds.version>
<snailjob.version>1.8.0</snailjob.version>
<mapstruct-plus.version>1.5.0</mapstruct-plus.version>
<mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
<lombok.version>1.18.40</lombok.version>
<bouncycastle.version>1.80</bouncycastle.version>
<justauth.version>1.16.7</justauth.version>
<!-- 离线IP地址定位库 -->
<ip2region.version>2.7.0</ip2region.version>
<!-- OSS 配置 -->
<aws.sdk.version>2.28.22</aws.sdk.version>
<!-- SMS 配置 -->
<sms4j.version>3.3.5</sms4j.version>
<!-- 限制框架中的fastjson版本 -->
<fastjson.version>1.2.83</fastjson.version>
<!-- 面向运行时的D-ORM依赖 -->
<anyline.version>8.7.2-20250603</anyline.version>
<!-- 插件版本 -->
<maven-jar-plugin.version>3.4.2</maven-jar-plugin.version>
<maven-war-plugin.version>3.4.0</maven-war-plugin.version>
<maven-compiler-plugin.version>3.14.0</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.5.3</maven-surefire-plugin.version>
<flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
<!-- 打包默认跳过测试 -->
<skipTests>true</skipTests>
</properties>
<profiles>
<profile>
<id>local</id>
<properties>
<!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>local</profiles.active>
<logging.level>info</logging.level>
<monitor.username>vben</monitor.username>
<monitor.password>123456</monitor.password>
</properties>
</profile>
<profile>
<id>dev</id>
<properties>
<!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>dev</profiles.active>
<logging.level>info</logging.level>
<monitor.username>vben</monitor.username>
<monitor.password>123456</monitor.password>
</properties>
<activation>
<!-- 默认环境 -->
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<profiles.active>prod</profiles.active>
<logging.level>warn</logging.level>
<monitor.username>vben</monitor.username>
<monitor.password>123456</monitor.password>
</properties>
</profile>
</profiles>
<!-- 依赖声明 -->
<dependencyManagement>
<dependencies>
@@ -31,66 +102,358 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- hutool 的依赖配置-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-bom</artifactId>
<version>${hutool.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- common 的依赖配置-->
<dependency>
<groupId>com.zsvg</groupId>
<artifactId>vben-common-bom</artifactId>
<version>${revision}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
<version>${springdoc.version}</version>
</dependency>
<dependency>
<groupId>com.github.therapi</groupId>
<artifactId>therapi-runtime-javadoc</artifactId>
<version>${therapi-javadoc.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>cn.idev.excel</groupId>
<artifactId>fastexcel</artifactId>
<version>${fastexcel.version}</version>
</dependency>
<!-- velocity代码生成使用模板 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>${velocity.version}</version>
</dependency>
<!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
<version>${satoken.version}</version>
</dependency>
<!-- Sa-Token 整合 jwt -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</artifactId>
<version>${satoken.version}</version>
<exclusions>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<version>${satoken.version}</version>
</dependency>
<!-- dynamic-datasource 多数据源-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>${dynamic-ds.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-jsqlparser</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-annotation</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- sql性能分析插件 -->
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>${p6spy.version}</version>
</dependency>
<!-- AWS SDK for Java 2.x -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<!-- 基于 AWS CRT 的 S3 客户端的性能增强的 S3 传输管理器 -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3-transfer-manager</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<!-- 将基于 Netty 的 HTTP 客户端从类路径中移除 -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<!--短信sms4j-->
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-spring-boot-starter</artifactId>
<version>${sms4j.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>${spring-boot-admin.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>${spring-boot-admin.version}</version>
</dependency>
<!--redisson-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>${redisson.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>lock4j-redisson-spring-boot-starter</artifactId>
<version>${lock4j.version}</version>
</dependency>
<!-- SnailJob Client -->
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>snail-job-client-starter</artifactId>
<version>${snailjob.version}</version>
</dependency>
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>snail-job-client-job-core</artifactId>
<version>${snailjob.version}</version>
</dependency>
<!-- 加密包引入 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
<version>${mapstruct-plus.version}</version>
</dependency>
<!-- JustAuth 的依赖配置-->
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>${justauth.version}</version>
</dependency>
<!-- 离线IP地址定位库 ip2region -->
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>${ip2region.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- 工作流模块 -->
<dependency>
<groupId>com.zsvg</groupId>
<artifactId>vben-base</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.zsvg</groupId>
<artifactId>vben-bpm</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!--编译管理 jdk版本和字符集编码-->
<modules>
<module>vben-common</module>
<module>vben-modules</module>
<module>vben-apps</module>
</modules>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<skip>true</skip>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<annotationProcessorPaths>
<path>
<groupId>com.github.therapi</groupId>
<artifactId>therapi-runtime-javadoc-scribe</artifactId>
<version>${therapi-javadoc.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
</path>
<path>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-processor</artifactId>
<version>${mapstruct-plus.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${mapstruct-plus.lombok.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<!-- 单元测试使用 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<argLine>-Dfile.encoding=UTF-8</argLine>
<!-- 根据打包环境执行对应的@Tag测试方法 -->
<groups>${profiles.active}</groups>
<!-- 排除标签 -->
<excludedGroups>exclude</excludedGroups>
</configuration>
</plugin>
<!-- 统一版本号管理 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>${flatten-maven-plugin.version}</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>lib</directory>
<targetPath>/WEB-INF/lib/</targetPath>
<includes>
<include>**/*.jar</include>
</includes>
<directory>src/main/resources</directory>
<!-- 关闭过滤 -->
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<!-- 引入所有 匹配文件进行过滤 -->
<includes>
<include>**/*</include>
<include>application*</include>
<include>bootstrap*</include>
<include>banner*</include>
</includes>
<!-- 启用过滤 即该资源中的变量将会被过滤器中的值替换 -->
<filtering>true</filtering>
</resource>
</resources>
</build>
<!--Maven远程仓库设置 非必要,可以删除-->
<repositories>
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public/</url>
<name>huawei nexus</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<!--Maven远程插件库设置 非必要,可以删除-->
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public/</url>
<name>huawei nexus</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
@@ -99,4 +462,7 @@
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
</project>
-56
View File
@@ -1,56 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>vben</artifactId>
<groupId>com.zsvg</groupId>
<version>0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>vben-admin</artifactId>
<dependencies>
<dependency>
<groupId>com.zsvg</groupId>
<artifactId>vben-extend</artifactId>
<version>${vben.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!-- <version>5.1.49</version>-->
<version>8.0.26</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 打包 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -1,42 +0,0 @@
package vben;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.EnableAsync;
import java.net.InetAddress;
import java.net.UnknownHostException;
@EnableCaching
@SpringBootApplication
@Slf4j
@EnableAsync
public class VbenAdmin {
public static void main(String[] args) {
ApplicationContext app = SpringApplication.run(VbenAdmin.class, args);
Environment env = app.getEnvironment();
String ip = null;
try {
ip = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
}
String port = env.getProperty("server.port");
String path = env.getProperty("server.servlet.context-path");
if (StrUtil.isBlank(path)) {
path = "";
}
System.out.println("-----------------------系统启动成功!-----------------------");
log.info("\n\tLocal接口访问地址: \thttp://localhost:" + port + path + "/doc.html" + "\n" +
"\tExternal访问网址: \thttp://" + ip + ":" + port + path + "/doc.html");
}
}
@@ -1,56 +0,0 @@
package vben.admin.my.demo.cate;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import vben.core.common.mvc.entity.BaseCateEntity;
import vben.core.module.sys.org.root.SysOrg;
import javax.persistence.*;
import java.util.List;
@Entity
@Getter
@Setter
@ApiModel("DEMO分类")
public class MyDemoCate extends BaseCateEntity {
@ManyToOne(fetch= FetchType.EAGER)
@JoinColumn(name = "pid")
@ApiModelProperty("父类别")
private MyDemoCate parent;
@Column(length = 32)
private String fomod;//表单形式
private Boolean prtag;//是否有流程
@Column(length = 32)
private String protd;//全局流程模板ID
@Transient
private String prxml;//流程XML
@Lob
private String fjson;//fields 表单字段
@Lob
private String tjson;//tabs 表单页签
@Lob
private String ljson;//links 表单联动
@ManyToMany
@JoinTable(name = "my_demo_cate_reman", joinColumns = {@JoinColumn(name = "mid")},
inverseJoinColumns = {@JoinColumn(name = "oid")})
@ApiModelProperty("数据可阅读者")
private List<SysOrg> remen;
@ManyToMany
@JoinTable(name = "my_demo_cate_usman", joinColumns = {@JoinColumn(name = "mid")},
inverseJoinColumns = {@JoinColumn(name = "oid")})
@ApiModelProperty("分类可使用者")
private List<SysOrg> usmen;
}
@@ -1,102 +0,0 @@
package vben.admin.my.demo.cate;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.web.bind.annotation.*;
import vben.core.common.mvc.api.R;
import vben.core.common.mvc.dao.JdbcDao;
import vben.core.common.mvc.dao.Sqler;
import vben.core.common.mvc.pojo.Ztree;
import vben.core.common.utils.lang.TreeUtils;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("my/demo/cate")
@Api(tags = {"DEMO分类管理"})
public class MyDemoCateApi {
private String table = "my_demo_cate";
@GetMapping("treez")
@ApiOperation("查询DEMO除自身外的分类树")
public R getTreez(String name, String id) {
List<Ztree> list = service.tier2Choose(table, id, name);
return R.ok(list);
}
@GetMapping("treea")
@ApiOperation("查询DEMO分类树")
public R getTreea(String name) {
Sqler sqler=new Sqler(table);
sqler.addSelect("t.pid,t.fomod type");
sqler.addOrder("t.ornum");
sqler.addWhere("t.avtag=1");
List<Ztree> list = jdbcDao.getTp().query(sqler.getSql(),sqler.getParams(),
new BeanPropertyRowMapper<>(Ztree.class));
return R.ok(TreeUtils.build(list)) ;
}
@GetMapping("tree")
@ApiOperation("查询DEMO分类列表")
public R getTree(String name) {
Sqler sqler = new Sqler(table);
sqler.addLike("t.name", name);
sqler.addOrder("t.ornum");
sqler.addWhere("t.avtag=1");
sqler.addSelect("t.pid,t.notes");
sqler.selectCUinfo();
List<MyDemoCateVo> list = jdbcDao.getTp().query(sqler.getSql(), sqler.getParams(),
new BeanPropertyRowMapper<>(MyDemoCateVo.class));
return R.ok(TreeUtils.buildEtree(list));
}
@GetMapping
@ApiOperation("查询DEMO分类分页")
public R get(String name) {
Sqler sqler = new Sqler(table);
sqler.addLike("t.name", name);
sqler.addSelect("t.notes");
return R.ok(service.findPageData(sqler));
}
@GetMapping("one/{id}")
@ApiOperation("查询DEMO分类详情")
public R getOne(@PathVariable String id) {
MyDemoCate cate = service.findOne(id);
if(cate.getPrtag()!=null&&cate.getPrtag()){
String sql = "select orxml from bpm_proc_temp where id=?";
Map<String, Object> map = jdbcDao.findMap(sql, cate.getProtd());
cate.setPrxml((String)map.get("orxml"));
}
return R.ok(cate);
}
@PostMapping
@ApiOperation("新增DEMO分类")
public R post(@RequestBody MyDemoCate main) {
return R.ok(service.insertx(main));
}
@PutMapping
@ApiOperation("更新DEMO分类")
public R put(@RequestBody MyDemoCate main) {
return R.ok(service.updatex(main, table));
}
@DeleteMapping("{ids}")
@ApiOperation("删除DEMO分类")
public R delete(@PathVariable String[] ids) {
return R.ok(service.delete(ids));
}
@Autowired
private MyDemoCateService service;
@Autowired
private JdbcDao jdbcDao;
}
@@ -1,9 +0,0 @@
package vben.admin.my.demo.cate;
import org.springframework.data.jpa.repository.JpaRepository;
//DEMO分类JPA仓储
public interface MyDemoCateRepo extends JpaRepository<MyDemoCate,String> {
}
@@ -1,68 +0,0 @@
package vben.admin.my.demo.cate;
import cn.hutool.core.util.StrUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.stereotype.Service;
import vben.core.common.mvc.dao.Sqler;
import vben.core.common.mvc.service.BaseCateService;
import vben.core.module.bpm.proc.temp.BpmProcTemp;
import vben.core.module.bpm.proc.temp.BpmProcTempService;
import javax.annotation.PostConstruct;
import java.util.List;
//DEMO分类服务
@Service
public class MyDemoCateService extends BaseCateService<MyDemoCate> {
//获取分类treeTable数据
public List<MyDemoCate> findTree(Sqler sqler) {
List<MyDemoCate> list = jdbcDao.getTp().query(sqler.getSql(), sqler.getParams(),
new BeanPropertyRowMapper<>(MyDemoCate.class));
return buildByRecursive(list);
}
public String insertx(MyDemoCate cate) {
BpmProcTemp bpmProcTemp = new BpmProcTemp();
bpmProcTemp.setName(cate.getName());
bpmProcTemp.setOrxml(cate.getPrxml());
if(StrUtil.isNotBlank((bpmProcTemp.getOrxml()))){
String chxml = "<?xml version=\"1.0\" encoding=\"gb2312\"?>"
+ "\n<process" + bpmProcTemp.getOrxml().split("bpmn2:process")[1]
.replaceAll("bpmn2:", "")
.replaceAll("activiti:", "") + "process>";
bpmProcTemp.setChxml(chxml);
}
String temid = bpmProcTempService.insert(bpmProcTemp);
cate.setProtd(temid);
return super.insert(cate);
}
public String updatex(MyDemoCate cate,String table) {
BpmProcTemp bpmProcTemp = bpmProcTempService.findOne(cate.getProtd());
bpmProcTemp.setName(cate.getName());
bpmProcTemp.setOrxml(cate.getPrxml());
if(StrUtil.isNotBlank((bpmProcTemp.getOrxml()))) {
String chxml = "<?xml version=\"1.0\" encoding=\"gb2312\"?>"
+ "\n<process" + bpmProcTemp.getOrxml().split("bpmn2:process")[1]
.replaceAll("bpmn2:", "")
.replaceAll("activiti:", "") + "process>";
bpmProcTemp.setChxml(chxml);
}
bpmProcTempService.update(bpmProcTemp);
return super.update(cate,table,false);
}
@Autowired
private BpmProcTempService bpmProcTempService;
@Autowired
private MyDemoCateRepo repo;
@PostConstruct
public void initDao() {
super.setRepo(repo);
}
}
@@ -1,23 +0,0 @@
package vben.admin.my.demo.cate;
import lombok.Getter;
import lombok.Setter;
import vben.core.common.mvc.pojo.Ztree;
import java.util.Date;
@Getter
@Setter
public class MyDemoCateVo extends Ztree {
private Date crtim;
private String crman;
private Date uptim;
private String upman;
private String notes;
}
@@ -1,41 +0,0 @@
package vben.admin.my.demo.main;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
@Data
@ApiModel("DEMO附件")
public class MyDemoAtt
{
@Id
@Column(length = 32)
@ApiModelProperty("主键ID")
private String id;
@ApiModelProperty("附件名称")
private String name;
@ApiModelProperty("附件大小")
private String zsize;
@ApiModelProperty("存储地址")
private String path;
@ApiModelProperty("文件ID")
@Column(length = 32)
private String filid;
@ApiModelProperty("业务ID")
@Column(length = 32)
private String busid;
@ApiModelProperty("排序号")
private Integer ornum;
}
@@ -1,46 +0,0 @@
package vben.admin.my.demo.main;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
//主记录OneToMany
@Data
@Entity
@ApiModel("DEMO明细行")
public class MyDemoItem {
@Id
@Column(length = 36)
@ApiModelProperty("主键ID")
private String id;
@Column(length = 32)
@ApiModelProperty("姓名")
private String name;
@Column(length = 32)
@ApiModelProperty("手机号")
private String monum;
@Column(length = 32)
@ApiModelProperty("性别")
private String gender;
@Column(length = 64)
@ApiModelProperty("职务")
private String post;
@Column(length = 32)
@ApiModelProperty("邮箱")
private String email;
@ApiModelProperty("备注")
private String notes;
@ApiModelProperty("排序号")
private Integer ornum;
}
@@ -1,108 +0,0 @@
package vben.admin.my.demo.main;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import vben.core.common.mvc.entity.BaseMainEntity;
import vben.core.module.bpm.proc.main.Zbpm;
import vben.core.module.sys.org.root.SysOrg;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Getter
@Setter
@ApiModel("DEMO主数据")
public class MyDemoMain extends BaseMainEntity {
//分类关联示例
@Column(length = 32)
@ApiModelProperty("分类ID")
private String catid;
//流水号示例
@Column(length = 32)
@ApiModelProperty("流水号")
private String senum;
//数据字典示例
@Column(length = 32)
@ApiModelProperty("等级")
private String grade;
//ManyToOne示例
@ManyToOne
@JoinColumn(name = "opman")
@ApiModelProperty("经办人")
private SysOrg opman;
//ManyToMany示例
@ManyToMany
@JoinTable(name = "my_demo_viman", joinColumns = {@JoinColumn(name = "mid")},
inverseJoinColumns = {@JoinColumn(name = "oid")})
@ApiModelProperty("可查看者")
private List<SysOrg> vimen;
//ManyToMany示例
@ManyToMany
@JoinTable(name = "my_demo_edman", joinColumns = {@JoinColumn(name = "mid")},
inverseJoinColumns = {@JoinColumn(name = "oid")})
@ApiModelProperty("可编辑者")
private List<SysOrg> edmen;
//OneToMany示例
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "maiid")
@OrderBy("ornum ASC")
@ApiModelProperty("明细行")
private List<MyDemoItem> items = new ArrayList<>();
//附件示例
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "busid")
@OrderBy("ornum ASC")
@ApiModelProperty("附件清单")
private List<MyDemoAtt> atts = new ArrayList<>();
//地址选择示例,可根据实际情况存想要的字段
//region-----地址相关信息-----
@ApiModelProperty("完整地址")
private String addre;
@Column(length = 64)
@ApiModelProperty("省市区")
private String adreg;
@Column(length = 128)
@ApiModelProperty("省市区以外的详细信息")
private String addet;
@Column(length = 32)
@ApiModelProperty("经纬度")
private String adcoo;
@Column(length = 32)
@ApiModelProperty("省")
private String adpro;
@Column(length = 32)
@ApiModelProperty("市")
private String adcit;
@Column(length = 32)
@ApiModelProperty("区")
private String addis;
//endregion
@Column(length = 32)
private String protd;//全局流程模板ID
@Transient
private Zbpm zbpm;
@Column(length = 8)
private String state;
}
@@ -1,83 +0,0 @@
package vben.admin.my.demo.main;
import cn.hutool.core.util.StrUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import vben.core.common.mvc.api.PageData;
import vben.core.common.mvc.api.R;
import vben.core.common.mvc.dao.Sqler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import vben.core.module.ass.num.main.AssNumMainService;
import vben.core.module.bpm.task.main.BpmTaskMainService;
import vben.core.module.mon.log.oper.Oplog;
@RestController
@RequestMapping("my/demo/main")
@Api(tags = {"DEMO管理"})
public class MyDemoMainApi {
@Oplog("查询DEMO分页")
@GetMapping
@ApiOperation("查询DEMO分页")
public R get(String name) {
Sqler sqler = new Sqler("my_demo_main");
sqler.addLike("t.name", name);
sqler.addLeftJoin("c.name catna,c.fomod type","my_demo_cate c","c.id=t.catid");
sqler.addSelect("t.state,t.senum,t.notes");
PageData pageData = service.findPageData(sqler);
taskMainService.findCurrentExmen(pageData.getItems());
return R.ok(pageData);
}
@Oplog("查询DEMO详情")
@GetMapping("one/{id}")
@ApiOperation("查询DEMO详情")
public R getOne(@PathVariable String id) {
MyDemoMain main = service.findOne(id);
return R.ok(main);
}
@Oplog("新增DEMO")
@PostMapping
@ApiOperation("新增DEMO")
public R post(@RequestBody MyDemoMain main) throws Exception {
main.setSenum(numService.getNum("DEMO"));//设置供应商流水号
if(StrUtil.isBlank(main.getProtd())){
main.setState("30");
service.insert(main);
}else{
service.insertx(main);
}
return R.ok();
}
@Oplog("更新DEMO")
@PutMapping
@ApiOperation("更新DEMO")
public R put(@RequestBody MyDemoMain main) throws Exception {
if(StrUtil.isBlank(main.getProtd())){
service.update(main);
}else{
service.updatex(main);
}
return R.ok();
}
@Oplog("删除DEMO")
@DeleteMapping("{ids}")
@ApiOperation("删除DEMO")
public R delete(@PathVariable String[] ids) {
return R.ok(service.delete(ids));
}
@Autowired
private BpmTaskMainService taskMainService;
@Autowired
private MyDemoMainService service;
@Autowired
private AssNumMainService numService;
}
@@ -1,10 +0,0 @@
package vben.admin.my.demo.main;
import org.springframework.data.jpa.repository.JpaRepository;
//DEMO主数据JPA仓储
public interface MyDemoMainRepo extends JpaRepository<MyDemoMain,String> {
}
@@ -1,91 +0,0 @@
package vben.admin.my.demo.main;
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import vben.core.common.mvc.service.BaseMainService;
import vben.core.common.utils.web.XuserUtil;
import vben.core.module.bpm.proc.cond.BpmProcCond;
import vben.core.module.bpm.proc.cond.BpmProcCondRepo;
import vben.core.module.bpm.proc.main.BpmProcMainService;
import vben.core.module.bpm.proc.main.Zbpm;
import vben.core.module.bpm.proc.main.Znode;
import vben.core.common.utils.lang.IdUtils;
import javax.annotation.PostConstruct;
import java.util.Date;
//DEMO主数据服务
@Service
public class MyDemoMainService extends BaseMainService<MyDemoMain> {
public void insertx(MyDemoMain main) throws Exception {
main.setState("20");
main.setId(IdUtils.getUID());
main.setUptim(new Date());
if (main.getCrman() == null) {
main.setCrman(XuserUtil.getUser());
}
MyDemoMain dbMain = repo.save(main);
BpmProcCond cond = new BpmProcCond();
cond.setId(dbMain.getId());
Gson gson = new Gson();
cond.setCond(gson.toJson(dbMain));
condRepo.saveAndFlush(cond);
Zbpm zbpm = main.getZbpm();
zbpm.setModty("app_demo");
zbpm.setProid(dbMain.getId());
zbpm.setProna(dbMain.getName());
zbpm.setHaman(dbMain.getCrman().getId());
zbpm.setTemid(dbMain.getProtd());
Znode znode = procService.start(zbpm);
if ("NE".equals(znode.getFacno())) {
dbMain.setState("30");
super.update(dbMain);
}
}
public void updatex(MyDemoMain main) throws Exception {
main.setState("20");
super.update(main);
BpmProcCond cond = new BpmProcCond();
cond.setId(main.getId());
Gson gson = new Gson();
cond.setCond(gson.toJson(main));
condRepo.saveAndFlush(cond);
main.getZbpm().setModty("app_demo");
if ("pass".equals(main.getZbpm().getOpkey())) {
Znode znode = procService.handlerPass(main.getZbpm());
if ("NE".equals(znode.getFacno())) {
main.setState("30");
super.update(main);
}
} else if ("refuse".equals(main.getZbpm().getOpkey())) {
if ("N1".equals(main.getZbpm().getTarno())) {
main.setState("11");
super.update(main);
}
Znode znode = procService.handlerRefuse(main.getZbpm());
}
}
@Autowired
private BpmProcMainService procService;
@Autowired
private BpmProcCondRepo condRepo;
@Autowired
private MyDemoMainRepo repo;
@PostConstruct
public void initDao() {
super.setRepo(repo);
}
}
@@ -1,136 +0,0 @@
package vben.init;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import vben.core.module.ass.dict.data.AssDictData;
import vben.core.module.ass.dict.data.AssDictDataRepo;
import vben.core.module.ass.dict.main.AssDictMain;
import vben.core.module.ass.dict.main.AssDictMainRepo;
import vben.core.module.ass.num.main.AssNumMain;
import vben.core.module.ass.num.main.AssNumMainRepo;
import vben.core.common.utils.lang.IdUtils;
import java.util.ArrayList;
import java.util.List;
//辅助数据初始化
@Component
public class AssInit {
protected void initData() throws Exception {
initNum();
initDict();
}
//流水号初始化
private void initNum() {
List<AssNumMain> numList = new ArrayList<>();
AssNumMain suppNum = new AssNumMain();
suppNum.setId("DEMO");
suppNum.setName("DEMO流水号");
suppNum.setNumod("yy");
suppNum.setNulen(4);
suppNum.setNflag(true);
suppNum.setNupre("D");
numList.add(suppNum);
numRepo.saveAll(numList);
}
//数据字典初始化
private void initDict() {
List<AssDictMain> dictList = new ArrayList<>();
AssDictMain demoDict = new AssDictMain();
demoDict.setId("DEMO_GRADE");
demoDict.setName("DEMO等级");
demoDict.setAvtag(true);
dictList.add(demoDict);
dictRepo.saveAll(dictList);
List<AssDictData> dictDataList = new ArrayList<>();
AssDictData demo1 = new AssDictData();
demo1.setId(IdUtils.getUID());
demo1.setCode("A");
demo1.setName("等级A");
demo1.setAvtag(true);
demo1.setOrnum(1);
demo1.setMaiid("DEMO_GRADE");
dictDataList.add(demo1);
AssDictData demo2 = new AssDictData();
demo2.setId(IdUtils.getUID());
demo2.setCode("B");
demo2.setName("等级B");
demo2.setAvtag(true);
demo2.setOrnum(2);
demo2.setMaiid("DEMO_GRADE");
dictDataList.add(demo2);
AssDictData demo3 = new AssDictData();
demo3.setId(IdUtils.getUID());
demo3.setCode("C");
demo3.setName("等级C");
demo3.setAvtag(true);
demo3.setOrnum(3);
demo3.setMaiid("DEMO_GRADE");
dictDataList.add(demo3);
AssDictData demo4 = new AssDictData();
demo4.setId(IdUtils.getUID());
demo4.setCode("Z");
demo4.setName("不合格");
demo4.setAvtag(true);
demo4.setOrnum(4);
demo4.setMaiid("DEMO_GRADE");
dictDataList.add(demo4);
AssDictData dist1 = new AssDictData();
dist1.setId(IdUtils.getUID());
dist1.setCode("A");
dist1.setName("A级资质");
dist1.setAvtag(true);
dist1.setOrnum(1);
dist1.setMaiid("DIST_GRADE");
dictDataList.add(dist1);
AssDictData dist2 = new AssDictData();
dist2.setId(IdUtils.getUID());
dist2.setCode("B");
dist2.setName("B级资质");
dist2.setAvtag(true);
dist2.setOrnum(2);
dist2.setMaiid("DIST_GRADE");
dictDataList.add(dist2);
AssDictData dist3 = new AssDictData();
dist3.setId(IdUtils.getUID());
dist3.setCode("C");
dist3.setName("C级资质");
dist3.setAvtag(true);
dist3.setOrnum(3);
dist3.setMaiid("DIST_GRADE");
dictDataList.add(dist3);
AssDictData dist4 = new AssDictData();
dist4.setId(IdUtils.getUID());
dist4.setCode("Z");
dist4.setName("不合格");
dist4.setAvtag(true);
dist4.setOrnum(4);
dist4.setMaiid("DIST_GRADE");
dictDataList.add(dist4);
dictDataRepo.saveAll(dictDataList);
}
@Autowired
private AssDictMainRepo dictRepo;
@Autowired
private AssDictDataRepo dictDataRepo;
@Autowired
private AssNumMainRepo numRepo;
}
@@ -1,87 +0,0 @@
package vben.init;
import org.springframework.context.annotation.PropertySource;
import vben.core.module.ass.oss.config.AssOssConfigService;
import vben.core.module.sys.org.user.SysOrgUserRepo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
//数据库初始化监听器
@Configuration
@Slf4j
@PropertySource(value = { "classpath:config/app-init.properties" },encoding = "UTF-8")
public class DbInitListener implements ApplicationListener<ContextRefreshedEvent> {
@Value("${app.init.orgType}")
private String ORG_TYPE;
@Value("${app.init.orgName}")
private String ORG_NAME;
@Value("${app.init.orgRootId}")
private String ORG_ROOT_ID;
@Value("${app.init.uiType}")
private String UI_TYPE;
//首次启动,数据库生成后,初始化组织架构,菜单,权限角色,接口等信息
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
try {
if (!userDao.existsById("sa")) {
System.out.println("首次启动系统,正在进行数据库初始化,请耐心等待。");
sysOrgInit.initRoot(ORG_NAME,ORG_ROOT_ID);
sysOrgInit.initSa();
if ("test".equals(ORG_TYPE)) {
sysOrgInit.initTestOrg();
}
System.out.println("1 初始化组织架构完毕");
if ("vben".equals(UI_TYPE)) {
sysPortalVbenInit.initPortal();
sysPortalVbenInit.initSysMenu();
sysPortalVbenInit.initSaMenu();
}else{
sysPortalVueInit.initPortal();
sysPortalVueInit.initSysMenu();
sysPortalVueInit.initSaMenu();
}
System.out.println("2 初始化门户菜单完毕");
assInit.initData();
System.out.println("3 初始化辅助数据完毕");
}
sysApiInit.initApi();
assOssConfigService.init();
} catch (Exception e) {
System.err.println("初始化出错");
e.printStackTrace();
}
}
@Autowired
private SysOrgUserRepo userDao;
@Autowired
private AssOssConfigService assOssConfigService;
@Autowired
private SysOrgInit sysOrgInit;
@Autowired
private AssInit assInit;
@Autowired
private SysApiInit sysApiInit;
@Autowired
private SysPortalVbenInit sysPortalVbenInit;
@Autowired
private SysPortalVueInit sysPortalVueInit;
}
@@ -1,298 +0,0 @@
package vben.init;
import cn.hutool.core.lang.ClassScanner;
import cn.hutool.core.util.StrUtil;
import org.springframework.web.bind.annotation.*;
import vben.core.common.mvc.dao.JdbcDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import vben.core.framework.security.authz.AuthzApiData;
import vben.core.framework.security.pojo.Yapi;
import vben.core.framework.security.pojo.Yurl;
import java.lang.reflect.Method;
import java.util.*;
/**
* API接口初始化,每次修改代码重启后,都会从代码搜集比对需要认证的请求URL,生成唯一的权限码存入数据库
* 并将最新的需要认证的Url根据Method分类放到公共内存,用于用户每次请求时获取权限码做权限认证
*/
@Component
public class SysApiInit {
protected void initApi() {
//扫描Controller中的所有Mapping方法,得到需要认证的URL集合
List<Yurl> codeUrlList = getScanList();
//从数据库获取所有已存的URL集合
List<String> dbUrlList = jdbcDao.findStringList("select id from sys_api_main");
//收集最大权限位及最大权限位的最大权限码
String sql = "select max(u.pos) as pos,max(u.code) as code from sys_api_main u where u.pos = (select max(uu.pos) from sys_api_main uu)";
Map<String, Object> maxMap = jdbcDao.findMap(sql);
int pos = 0;
long code = 0;
if (maxMap != null && maxMap.get("pos") != null) {
pos = Integer.parseInt(String.valueOf(maxMap.get("pos")));
code = Long.parseLong(String.valueOf(maxMap.get("code")));
}
//比较两个集合,计算得到需要插入数据库的insertList与需要更新数据库的updateList
List<Object[]> insertList = new ArrayList<Object[]>();
List<Object[]> updateList = new ArrayList<Object[]>();
for (Yurl yurl : codeUrlList) {
boolean flag = false;
for (String dbUrlstr : dbUrlList) {
if (yurl.getId().equals(dbUrlstr)) {
flag = true;
break;
}
}
if (!flag) {//插入
if (yurl.getType() == null) {
Object[] objects = new Object[7];
objects[0] = yurl.getId();
objects[1] = yurl.getPid();
objects[2] = 0;
objects[3] = 0;
objects[4] = yurl.getUrl();
objects[5] = yurl.getType();
objects[6] = new Date();
insertList.add(objects);
} else {
if (code >= (1L << 62)) {
pos = pos + 1;
code = 1;
} else {
if (code == 0) {
code = 1;
} else {
code = code << 1;
}
}
Object[] objects = new Object[7];
objects[0] = yurl.getId();
objects[1] = yurl.getPid();
objects[2] = pos;
objects[3] = code;
objects[4] = yurl.getUrl();
objects[5] = yurl.getType();
objects[6] = new Date();
insertList.add(objects);
}
} else {//更新
Object[] objects = new Object[3];
objects[0] = yurl.getPid();
objects[1] = yurl.getType();
objects[2] = yurl.getId();
updateList.add(objects);
}
}
//设置是否为公共资源
// for (Object[] objects : insertList) {
// if (objects[0].toString().contains("_c")) {
// objects[5] = 1;
// }
// }
//批量插入与更新数据库
String initSql = "UPDATE sys_api_main SET avtag=0";
String updateSql = "UPDATE sys_api_main SET pid=?,type=?,avtag=1 WHERE id=?";
String insertSql = "INSERT INTO sys_api_main(id,pid,pos,code,url,type,crtim,avtag) VALUES(?,?,?,?,?,?,?,1)";
jdbcDao.update(initSql);
jdbcDao.batch(updateSql, updateList);
jdbcDao.batch(insertSql, insertList);
AuthzApiData.AUTHPOS = pos;
//初始化所有用户权限
String updateUserSql = "update sys_org_user set catag=0";
jdbcDao.update(updateUserSql);
String updateCoopUserSql = "update sys_coop_user set catag=0";
jdbcDao.update(updateCoopUserSql);
//将所有要求认证的Url分Method放入内存,用于每次请求时的权限校验
String g1ApiSql = "SELECT url,pos,code from sys_api_main where avtag=1 and type='get' and id not like '%}:get'";
AuthzApiData.GET1_APIS = findDbApis(g1ApiSql);
String g2ApiSql = "SELECT url,pos,code from sys_api_main where avtag=1 and type='get' and id like '%}:get'";
AuthzApiData.GET2_APIS = findDbApis(g2ApiSql);
String postApiSql = "SELECT url,pos,code from sys_api_main where avtag=1 and type='post'";
AuthzApiData.POST_APIS = findDbApis(postApiSql);
String putApiSql = "SELECT url,pos,code from sys_api_main where avtag=1 and type='put'";
AuthzApiData.PUT_APIS = findDbApis(putApiSql);
String deleteApiSql = "SELECT url,pos,code from sys_api_main where avtag= 1 and type='delete'";
AuthzApiData.DELETE_APIS = findDbApis(deleteApiSql);
String patchApiSql = "SELECT url,pos,code from sys_api_main where avtag=1 and type='patch'";
AuthzApiData.PATCH_APIS = findDbApis(patchApiSql);
}
//扫描Controller中的所有Mapping方法,得到需要认证的URL集合
private List<Yurl> getScanList() {
List<Yurl> list = new ArrayList<>();
Set<Class<?>> classes = ClassScanner.scanPackage("vben");
for (Class<?> clazz : classes) {
RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
if (requestMapping != null) {
String classUrl = requestMapping.value()[0];
//---> /authc 开头的不需要登录, /gen 只要登录就有权限 /sys 需要管理员才有权限 其余通过rbac权限机制判断
// if (!url.startsWith("authc")&&!url.startsWith("gen")&&!url.startsWith("sys")) {
if (!classUrl.startsWith("authc") && !classUrl.startsWith("gen")) {
Yurl topUrl = new Yurl();
topUrl.setId(classUrl.replaceAll("/", "-"));
if (!classUrl.startsWith("/")) {
classUrl = "/" + classUrl;
}
if (topUrl.getId().contains("-")) {
topUrl.setPid(topUrl.getId().split("-")[0]);
}
topUrl.setUrl(classUrl);
if(StrUtil.isNotBlank(topUrl.getId())){
list.add(topUrl);
}
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
GetMapping getMapping = method.getAnnotation(GetMapping.class);
if (getMapping != null) {
Yurl yurl = new Yurl();
String methodUrl = "";
if (getMapping.value().length > 0) {
methodUrl = getMapping.value()[0];
yurl.setUrl(topUrl.getUrl() + "/" + methodUrl);
methodUrl = methodUrl.replaceAll("/", "-");
yurl.setId(topUrl.getId() + "-" + methodUrl + ":get");
} else {
yurl.setId(topUrl.getId() + ":get");
yurl.setUrl(topUrl.getUrl());
}
yurl.setPid(topUrl.getId());
yurl.setType("get");
list.add(yurl);
continue;
}
PostMapping postMapping = method.getAnnotation(PostMapping.class);
if (postMapping != null) {
Yurl yurl = new Yurl();
String methodUrl = "";
if (postMapping.value().length > 0) {
methodUrl = postMapping.value()[0];
yurl.setUrl(topUrl.getUrl() + "/" + methodUrl);
methodUrl = methodUrl.replaceAll("/", "-");
yurl.setId(topUrl.getId() + "-" + methodUrl + ":post");
} else {
yurl.setId(topUrl.getId() + ":post");
yurl.setUrl(topUrl.getUrl());
}
yurl.setPid(topUrl.getId());
yurl.setType("post");
list.add(yurl);
continue;
}
PutMapping putMapping = method.getAnnotation(PutMapping.class);
if (putMapping != null) {
Yurl yurl = new Yurl();
String methodUrl = "";
if (putMapping.value().length > 0) {
methodUrl = putMapping.value()[0];
yurl.setUrl(topUrl.getUrl() + "/" + methodUrl);
methodUrl = methodUrl.replaceAll("/", "-");
yurl.setId(topUrl.getId() + "-" + methodUrl + ":put");
} else {
yurl.setId(topUrl.getId() + ":put");
yurl.setUrl(topUrl.getUrl());
}
yurl.setPid(topUrl.getId());
yurl.setType("put");
list.add(yurl);
continue;
}
DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
if (deleteMapping != null) {
Yurl yurl = new Yurl();
String methodUrl = "";
if (deleteMapping.value().length > 0) {
methodUrl = deleteMapping.value()[0];
yurl.setUrl(topUrl.getUrl() + "/" + methodUrl);
methodUrl = methodUrl.replaceAll("/", "-");
yurl.setId(topUrl.getId() + "-" + methodUrl + ":delete");
} else {
yurl.setId(topUrl.getId() + ":delete");
yurl.setUrl(topUrl.getUrl());
}
yurl.setPid(topUrl.getId());
yurl.setType("delete");
list.add(yurl);
continue;
}
PatchMapping patchMapping = method.getAnnotation(PatchMapping.class);
if (patchMapping != null) {
Yurl yurl = new Yurl();
String methodUrl = "";
if (patchMapping.value().length > 0) {
methodUrl = patchMapping.value()[0];
yurl.setUrl(topUrl.getUrl() + "/" + methodUrl);
methodUrl = methodUrl.replaceAll("/", "-");
yurl.setId(topUrl.getId() + "-" + methodUrl + ":patch");
} else {
yurl.setId(topUrl.getId() + ":patch");
yurl.setUrl(topUrl.getUrl());
}
yurl.setPid(topUrl.getId());
yurl.setType("patch");
list.add(yurl);
continue;
}
}
}
}
}
//设置请求URL的root根目录,方便后面API权限分配
Set<String> rootSet = new HashSet<>();
for (Yurl yurl : list) {
if (yurl.getType() == null && yurl.getPid() != null) {
rootSet.add(yurl.getPid());
}
}
for (String str : rootSet) {
Yurl yurl = new Yurl();
yurl.setId(str);
if(StrUtil.isNotBlank(yurl.getId())){
list.add(yurl);
}
}
return list;
}
//获取数据库请求的通用方法
private List<Yapi> findDbApis(String sql) {
return jdbcDao.getTp().query(sql, (rs, rowNum) -> {
Yapi yperm = new Yapi();
String url = rs.getString("url");
if (url.endsWith("}")) {
yperm.setUrl(url.substring(0, url.lastIndexOf("/")));
} else {
yperm.setUrl(url);
}
yperm.setPos(rs.getInt("pos"));
yperm.setCode(rs.getLong("code"));
return yperm;
});
}
@Autowired
private JdbcDao jdbcDao;
}
@@ -1,333 +0,0 @@
package vben.init;
import cn.hutool.core.util.StrUtil;
import vben.core.module.sys.org.dept.SysOrgDept;
import vben.core.module.sys.org.dept.SysOrgDeptService;
import vben.core.module.sys.org.group.SysOrgGroup;
import vben.core.module.sys.org.group.SysOrgGroupCate;
import vben.core.module.sys.org.group.SysOrgGroupCateService;
import vben.core.module.sys.org.group.SysOrgGroupService;
import vben.core.module.sys.org.post.SysOrgPost;
import vben.core.module.sys.org.post.SysOrgPostService;
import vben.core.module.sys.org.role.*;
import vben.core.module.sys.org.root.SysOrg;
import vben.core.module.sys.org.user.SysOrgUser;
import vben.core.module.sys.org.user.SysOrgUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
//组织架构初始化,可根据application.properties的app.init.orgType配置生成不同的基础数据
@Component
public class SysOrgInit {
private String rootId = "1";
protected void initRoot(String name,String id) {
if(StrUtil.isNotBlank(id)){
rootId=id;
}
SysOrgDept root = new SysOrgDept();
root.setId(rootId);
root.setName(name);
root.setLabel("1");
root.setOrnum(0);
root.setAvtag(true);
root.setTier("x"+rootId+"x");
root.setType(1);
deptService.insert(root);
}
//初始化管理员
protected void initSa() {
SysOrgUser user = new SysOrgUser();
user.setId("sa");
user.setUsnam("sa");
user.setName("管理员");
user.setPacod("1");
user.setAvtag(true);
user.setDept(new SysOrg(rootId));
user.setTier("x"+rootId+"xsax");
userService.insert(user);
SysOrgUser user2 = new SysOrgUser();
user2.setId("vben");
user2.setUsnam("vben");
user2.setName("小维");
user2.setPacod("123456");
user2.setAvtag(true);
user2.setDept(new SysOrg(rootId));
user2.setTier("x"+rootId+"xvbenx");
userService.insert(user2);
}
//初始化测试部门与人员
protected void initTestOrg() {
SysOrgDept d1=new SysOrgDept();
d1.setId("dept1");
d1.setName("测试一部");
d1.setLabel("1");
d1.setOrnum(9991);
d1.setAvtag(true);
d1.setType(2);
d1.setParent(new SysOrg(rootId));
d1.setTier("x"+rootId+"xdept1x");
deptService.insert(d1);
SysOrgDept d2=new SysOrgDept();
d2.setId("dept2");
d2.setName("测试二部");
d2.setLabel("1");
d2.setOrnum(9992);
d2.setAvtag(true);
d2.setType(2);
d2.setParent(new SysOrg(rootId));
d2.setTier("x"+rootId+"xdept2x");
deptService.insert(d2);
List<SysOrgUser> userList=new ArrayList<>();
SysOrgUser u1 = new SysOrgUser();
u1.setId("l1");
u1.setUsnam("l1");
u1.setName("刘一");
u1.setPacod("1");
u1.setOrnum(1);
u1.setAvtag(true);
u1.setDept(new SysOrg("dept1"));
u1.setTier("x"+rootId+"xdept1xl1x");
userList.add(u1);
SysOrgUser u2 = new SysOrgUser();
u2.setId("c2");
u2.setUsnam("c2");
u2.setName("陈二");
u2.setPacod("1");
u2.setOrnum(2);
u2.setAvtag(true);
u2.setDept(new SysOrg("dept1"));
u2.setTier("x"+rootId+"xdept1xc2x");
userList.add(u2);
SysOrgUser u3 = new SysOrgUser();
u3.setId("z3");
u3.setUsnam("z3");
u3.setName("张三");
u3.setPacod("1");
u3.setOrnum(3);
u3.setAvtag(true);
u3.setDept(new SysOrg("dept1"));
u3.setTier("x"+rootId+"xdept1xz3x");
userList.add(u3);
SysOrgUser u4 = new SysOrgUser();
u4.setId("l4");
u4.setUsnam("l4");
u4.setName("李四");
u4.setPacod("1");
u4.setOrnum(4);
u4.setAvtag(true);
u4.setDept(new SysOrg("dept1"));
u4.setTier("x"+rootId+"xdept1xl4x");
userList.add(u4);
SysOrgUser u5 = new SysOrgUser();
u5.setId("w5");
u5.setUsnam("w5");
u5.setName("王五");
u5.setPacod("1");
u5.setOrnum(5);
u5.setAvtag(true);
u5.setDept(new SysOrg("dept2"));
u5.setTier("x"+rootId+"xdept2xw5x");
userList.add(u5);
SysOrgUser u6 = new SysOrgUser();
u6.setId("z6");
u6.setUsnam("z6");
u6.setName("赵六");
u6.setPacod("1");
u6.setOrnum(6);
u6.setAvtag(true);
u6.setDept(new SysOrg("dept2"));
u6.setTier("x"+rootId+"xdept2xz6x");
userList.add(u6);
SysOrgUser u7 = new SysOrgUser();
u7.setId("s7");
u7.setUsnam("s7");
u7.setName("孙七");
u7.setPacod("1");
u7.setOrnum(7);
u7.setAvtag(true);
u7.setDept(new SysOrg("dept2"));
u7.setTier("x"+rootId+"xdept2xs7x");
userList.add(u7);
SysOrgUser u8 = new SysOrgUser();
u8.setId("z8");
u8.setUsnam("z8");
u8.setName("周八");
u8.setPacod("1");
u8.setOrnum(8);
u8.setAvtag(true);
u8.setDept(new SysOrg("dept2"));
u8.setTier("x"+rootId+"xdept2xz8x");
userList.add(u8);
userService.insertAll(userList);
SysOrgPost p1 = new SysOrgPost();
p1.setId("post1");
p1.setName("一部负责人");
p1.setOrnum(0);
p1.setAvtag(true);
p1.setDept(new SysOrg("dept1"));
p1.setTier("x"+rootId+"xdept1xpost1x");
p1.setUsers(new ArrayList<>());
p1.getUsers().add(new SysOrg("l1","刘一",8));
postService.insert(p1);
SysOrgPost p2 = new SysOrgPost();
p2.setId("post2");
p2.setName("二部负责人");
p2.setOrnum(0);
p2.setAvtag(true);
p2.setDept(new SysOrg("dept2"));
p2.setTier("x"+rootId+"xdept2xpost2x");
p2.setUsers(new ArrayList<>());
p2.getUsers().add(new SysOrg("w5","王五",8));
p2.getUsers().add(new SysOrg("z6","赵六",8));
postService.insert(p2);
SysOrgGroupCate gcate = new SysOrgGroupCate();
gcate.setId("gcate");
gcate.setName("测试群组分类");
gcate.setAvtag(true);
gcate.setOrnum(1);
gcate.setCrman(new SysOrg("sa"));
groupCateService.insert(gcate);
SysOrgGroup g1 = new SysOrgGroup();
g1.setId("group1");
g1.setName("张三李四组");
g1.setOrnum(1);
g1.setAvtag(true);
g1.setCatid("gcate");
g1.setMembers(new ArrayList<>());
g1.getMembers().add(new SysOrg("z3","张三",8));
g1.getMembers().add(new SysOrg("l4","李四",8));
groupService.insert(g1);
SysOrgGroup g2 = new SysOrgGroup();
g2.setId("group2");
g2.setName("用户岗位部门混合组");
g2.setOrnum(2);
g2.setAvtag(true);
g2.setCatid("gcate");
g2.setMembers(new ArrayList<>());
g2.getMembers().add(new SysOrg("c2","陈二",8));
g2.getMembers().add(new SysOrg("post1","一部负责人",4));
g2.getMembers().add(new SysOrg("dept2","测试二部",2));
groupService.insert(g2);
SysOrgRoleTree rtree1 = new SysOrgRoleTree();
rtree1.setId("rtree1");
rtree1.setName("业务角色树");
rtree1.setOrnum(1);
rtree1.setAvtag(true);
rtree1.setRoles(new ArrayList<>());
rtree1.getRoles().add(new SysOrgRole("role1","分管领导",1));
rtree1.getRoles().add(new SysOrgRole("role2","部门领导",2));
rtree1.setCrman(new SysOrg("sa"));
roleTreeService.insertx(rtree1);
SysOrgRoleNode rnode1 = new SysOrgRoleNode();
rnode1.setId("rnode1");
rnode1.setName("一部分管领导");
rnode1.setTreid("rtree1");
rnode1.setOrnum(1);
rnode1.setAvtag(true);
rnode1.setMember(new SysOrg("post1"));
rnode1.setTier("xrnode1x");
roleNodeService.insert(rnode1);
SysOrgRoleNode rnode11 = new SysOrgRoleNode();
rnode11.setId("rnode11");
rnode11.setName("一部部门领导");
rnode11.setTreid("rtree1");
rnode11.setOrnum(1);
rnode11.setAvtag(true);
rnode11.setMember(new SysOrg("c2"));
rnode11.setParent(new SysOrgRoleNode("rnode1"));
rnode11.setTier("xrnode1xrnode11x");
roleNodeService.insert(rnode11);
SysOrgRoleNode rnode111 = new SysOrgRoleNode();
rnode111.setId("rnode111");
rnode111.setName("一部人员");
rnode111.setTreid("rtree1");
rnode111.setOrnum(1);
rnode111.setAvtag(true);
rnode111.setMember(new SysOrg("dept1"));
rnode111.setParent(new SysOrgRoleNode("rnode11"));
rnode111.setTier("xrnode1xrnode11xrnode111x");
roleNodeService.insert(rnode111);
SysOrgRoleNode rnode2 = new SysOrgRoleNode();
rnode2.setId("rnode2");
rnode2.setName("二部分管领导");
rnode2.setTreid("rtree1");
rnode2.setOrnum(2);
rnode2.setAvtag(true);
rnode2.setMember(new SysOrg("post2"));
rnode2.setTier("xrnode2x");
roleNodeService.insert(rnode2);
SysOrgRoleNode rnode21 = new SysOrgRoleNode();
rnode21.setId("rnode21");
rnode21.setName("二部部门领导");
rnode21.setTreid("rtree1");
rnode21.setOrnum(1);
rnode21.setAvtag(true);
rnode21.setMember(new SysOrg("z6"));
rnode21.setParent(new SysOrgRoleNode("rnode2"));
rnode21.setTier("xrnode2xrnode21x");
roleNodeService.insert(rnode21);
SysOrgRoleNode rnode211 = new SysOrgRoleNode();
rnode211.setId("rnode211");
rnode211.setName("二部人员");
rnode211.setTreid("rtree1");
rnode211.setOrnum(1);
rnode211.setAvtag(true);
rnode211.setMember(new SysOrg("dept2"));
rnode211.setParent(new SysOrgRoleNode("rnode21"));
rnode211.setTier("xrnode2xrnode21xrnode211x");
roleNodeService.insert(rnode211);
}
@Autowired
private SysOrgRoleNodeService roleNodeService;
@Autowired
private SysOrgRoleTreeService roleTreeService;
@Autowired
private SysOrgGroupCateService groupCateService;
@Autowired
private SysOrgGroupService groupService;
@Autowired
private SysOrgDeptService deptService;
@Autowired
private SysOrgUserService userService;
@Autowired
private SysOrgPostService postService;
}
@@ -1,981 +0,0 @@
package vben.init;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import vben.core.module.sys.portal.main.SysPortalMain;
import vben.core.module.sys.portal.main.SysPortalMainService;
import vben.core.module.sys.portal.menu.SysPortalMenu;
import vben.core.module.sys.portal.menu.SysPortalMenuService;
//系统门户与菜单初始化
@Component
public class SysPortalVbenInit {
//门户初始化
protected void initPortal() {
SysPortalMain sysPortalMain=new SysPortalMain();
sysPortalMain.setId("sys");
sysPortalMain.setOrnum(0);
sysPortalMain.setName("管理员门户");
mainService.save(sysPortalMain);
SysPortalMain sysPortalMain2=new SysPortalMain();
sysPortalMain2.setId("sa");
sysPortalMain2.setOrnum(1);
sysPortalMain2.setName("营销门户");
mainService.save(sysPortalMain2);
}
//管理员门户的菜单初始化
protected void initSysMenu() {
// SysPortalMenu home = new SysPortalMenu();
// home.setId("Home");
// home.setName("首页");
// home.setCode("Home");
// home.setComp("/home/index");
// home.setPath("/home");
// home.setOrnum(0);
// home.setIcon("ele-House");
// home.setAvtag(true);
// home.setShtag(true);
// home.setType("M");
// home.setPorid("sys");
// menuService.insert(home);
//-----------------系统管理--------------------
SysPortalMenu menu1 = new SysPortalMenu();
menu1.setId("Sys");
menu1.setName("系统管理");
menu1.setCode("Sys");
menu1.setComp("LAYOUT");
menu1.setPath("/sys");
menu1.setRedirect("/sys/org/user");
menu1.setOrnum(1);
menu1.setIcon("ant-design:setting-outlined");
menu1.setAvtag(true);
menu1.setShtag(true);
menu1.setType("D");
menu1.setPorid("sys");
menuService.insert(menu1);
SysPortalMenu menu11 = new SysPortalMenu();
menu11.setId("SysOrg");
menu11.setName("组织架构");
menu11.setCode("SysOrg");
menu11.setComp("LAYOUT");
menu11.setPath("/sys/org");
menu11.setRedirect("/sys/org/user");
menu11.setOrnum(1);
menu11.setIcon("ant-design:partition-outlined");
menu11.setPid("Sys");
menu11.setAvtag(true);
menu11.setShtag(true);
menu11.setType("D");
menu11.setPorid("sys");
menuService.insert(menu11);
SysPortalMenu menu111 = new SysPortalMenu();
menu111.setId("SysOrgDept");
menu111.setName("部门管理");
menu111.setCode("SysOrgDept");
menu111.setPath("/sys/org/dept");
menu111.setComp("/sys/org/dept/index");
menu111.setOrnum(10);
menu111.setPid("SysOrg");
menu111.setCatag(true);
menu111.setAvtag(true);
menu111.setShtag(true);
menu111.setType("M");
menu111.setPorid("sys");
menuService.insert(menu111);
SysPortalMenu menu111a = new SysPortalMenu();
menu111a.setId("SysOrgDeptEdit");
menu111a.setName("部门编辑");
menu111a.setCode("SysOrgDeptEdit");
menu111a.setPath("/sys/org/dept/edit");
menu111a.setComp("/sys/org/dept/edit");
menu111a.setOrnum(11);
menu111a.setPid("SysOrg");
menu111a.setCatag(true);
menu111a.setAvtag(true);
menu111a.setShtag(false);
menu111a.setType("M");
menu111a.setPorid("sys");
menuService.insert(menu111a);
SysPortalMenu menu112 = new SysPortalMenu();
menu112.setId("SysOrgUser");
menu112.setName("用户管理");
menu112.setCode("SysOrgUser");
menu112.setPath("/sys/org/user");
menu112.setComp("/sys/org/user/index");
menu112.setOrnum(20);
menu112.setPid("SysOrg");
menu112.setCatag(true);
menu112.setAvtag(true);
menu112.setShtag(true);
menu112.setType("M");
menu112.setPorid("sys");
menuService.insert(menu112);
SysPortalMenu menu112a = new SysPortalMenu();
menu112a.setId("SysOrgUserEdit");
menu112a.setName("用户编辑");
menu112a.setCode("SysOrgUserEdit");
menu112a.setPath("/sys/org/user/edit");
menu112a.setComp("/sys/org/user/edit");
menu112a.setOrnum(21);
menu112a.setPid("SysOrg");
menu112a.setCatag(true);
menu112a.setAvtag(true);
menu112a.setShtag(false);
menu112a.setType("M");
menu112a.setPorid("sys");
menuService.insert(menu112a);
SysPortalMenu menu113 = new SysPortalMenu();
menu113.setId("SysOrgPost");
menu113.setName("岗位管理");
menu113.setCode("SysOrgPost");
menu113.setPath("/sys/org/post");
menu113.setComp("/sys/org/post/index");
menu113.setOrnum(31);
menu113.setPid("SysOrg");
menu113.setCatag(true);
menu113.setAvtag(true);
menu113.setShtag(true);
menu113.setType("M");
menu113.setPorid("sys");
menuService.insert(menu113);
SysPortalMenu menu113a = new SysPortalMenu();
menu113a.setId("SysOrgPostEdit");
menu113a.setName("岗位编辑");
menu113a.setCode("SysOrgPostEdit");
menu113a.setPath("/sys/org/post/edit");
menu113a.setComp("/sys/org/post/edit");
menu113a.setOrnum(32);
menu113a.setPid("SysOrg");
menu113a.setCatag(true);
menu113a.setAvtag(true);
menu113a.setShtag(false);
menu113a.setType("M");
menu113a.setPorid("sys");
menuService.insert(menu113a);
SysPortalMenu menu114 = new SysPortalMenu();
menu114.setId("SysOrgGroup");
menu114.setName("群组管理");
menu114.setCode("SysOrgGroup");
menu114.setPath("/sys/org/group");
menu114.setComp("/sys/org/group/index");
menu114.setOrnum(40);
menu114.setPid("SysOrg");
menu114.setCatag(true);
menu114.setAvtag(true);
menu114.setShtag(true);
menu114.setType("M");
menu114.setPorid("sys");
menuService.insert(menu114);
SysPortalMenu menu114a = new SysPortalMenu();
menu114a.setId("SysOrgGroupEdit");
menu114a.setName("群组编辑");
menu114a.setCode("SysOrgGroupEdit");
menu114a.setPath("/sys/org/group/edit");
menu114a.setComp("/sys/org/group/edit");
menu114a.setOrnum(41);
menu114a.setPid("SysOrg");
menu114a.setCatag(true);
menu114a.setAvtag(true);
menu114a.setShtag(false);
menu114a.setType("M");
menu114a.setPorid("sys");
menuService.insert(menu114a);
SysPortalMenu menu12 = new SysPortalMenu();
menu12.setId("SysApi");
menu12.setName("接口管理");
menu12.setCode("SysApi");
menu12.setComp("LAYOUT");
menu12.setPath("/sys/api");
menu12.setRedirect("/sys/api/main");
menu12.setOrnum(2);
menu12.setIcon("ant-design:safety-certificate-outlined");
menu12.setPid("Sys");
menu12.setAvtag(true);
menu12.setShtag(true);
menu12.setType("D");
menu12.setPorid("sys");
menuService.insert(menu12);
SysPortalMenu menu121 = new SysPortalMenu();
menu121.setId("SysApiMain");
menu121.setName("接口清单");
menu121.setCode("SysApiMain");
menu121.setPath("/sys/api/main");
menu121.setComp("/sys/api/main/index");
menu121.setOrnum(10);
menu121.setPid("SysApi");
menu121.setCatag(true);
menu121.setAvtag(true);
menu121.setShtag(true);
menu121.setType("M");
menu121.setPorid("sys");
menuService.insert(menu121);
SysPortalMenu menu121a = new SysPortalMenu();
menu121a.setId("SysApiMainEdit");
menu121a.setName("接口编辑");
menu121a.setCode("SysApiMainEdit");
menu121a.setPath("/sys/api/main/edit");
menu121a.setComp("/sys/api/main/edit");
menu121a.setOrnum(11);
menu121a.setPid("SysApi");
menu121a.setCatag(true);
menu121a.setAvtag(true);
menu121a.setShtag(false);
menu121a.setType("M");
menu121a.setPorid("sys");
menuService.insert(menu121a);
// SysPortalMenu menu122 = new SysPortalMenu();
// menu122.setId("SysApiMainDoc");
// menu122.setName("接口文档");
// menu122.setCode("SysApiMainDoc");
// menu122.setPath("/sys/api/role/doc");
// //menu122.setExtag(true);//外链
// menu122.setIftag(true);
// menu122.setComp("http://localhost:5000/doc.html");
// menu122.setOrnum(12);
// menu122.setPid("SysApi");
// menu122.setCatag(false);
// menu122.setAvtag(true);
// menu122.setShtag(true);
// menu122.setType("M");
// menu122.setPorid("sys");
// menuService.insert(menu122);
SysPortalMenu menu123 = new SysPortalMenu();
menu123.setId("SysApiRole");
menu123.setName("接口角色");
menu123.setCode("SysApiRole");
menu123.setPath("/sys/api/role");
menu123.setComp("/sys/api/role/index");
menu123.setOrnum(20);
menu123.setPid("SysApi");
menu123.setCatag(true);
menu123.setAvtag(true);
menu123.setShtag(true);
menu123.setType("M");
menu123.setPorid("sys");
menuService.insert(menu123);
SysPortalMenu menu123a = new SysPortalMenu();
menu123a.setId("SysApiRoleEdit");
menu123a.setName("角色编辑");
menu123a.setCode("SysApiRoleEdit");
menu123a.setPath("/sys/api/role/edit");
menu123a.setComp("/sys/api/role/edit");
menu123a.setOrnum(21);
menu123a.setPid("SysApi");
menu123a.setCatag(true);
menu123a.setAvtag(true);
menu123a.setShtag(false);
menu123a.setType("M");
menu123a.setPorid("sys");
menuService.insert(menu123a);
SysPortalMenu menu13 = new SysPortalMenu();
menu13.setId("SysPortal");
menu13.setName("菜单管理");
menu13.setCode("SysPortal");
menu13.setComp("LAYOUT");
menu13.setPath("/sys/portal");
menu13.setRedirect("/sys/portal/main");
menu13.setOrnum(3);
menu13.setIcon("ant-design:profile-outlined");
menu13.setPid("Sys");
menu13.setAvtag(true);
menu13.setShtag(true);
menu13.setType("D");
menu13.setPorid("sys");
menuService.insert(menu13);
// SysPortalMenu menu131 = new SysPortalMenu();
// menu131.setId("SysPortalMain");
// menu131.setName("门户清单");
// menu131.setCode("SysPortalMain");
// menu131.setPath("/sys/portal/main");
// menu131.setComp("/sys/portal/main/index");
// menu131.setOrnum(10);
// menu131.setIcon("ele-Tickets");
// menu131.setPid("SysPortal");
// menu131.setCatag(true);
// menu131.setAvtag(true);
// menu131.setShtag(true);
// menu131.setType("M");
// menu131.setPorid("sys");
// menuService.insert(menu131);
// SysPortalMenu menu131a = new SysPortalMenu();
// menu131a.setId("SysPortalMainEdit");
// menu131a.setName("门户编辑");
// menu131a.setCode("SysPortalMainEdit");
// menu131a.setPath("/sys/portal/main/edit");
// menu131a.setComp("/sys/portal/main/edit");
// menu131a.setOrnum(11);
// menu131a.setIcon("ele-Tickets");
// menu131a.setPid("SysPortal");
// menu131a.setCatag(true);
// menu131a.setAvtag(true);
// menu131a.setShtag(false);
// menu131a.setType("M");
// menu131a.setPorid("sys");
// menuService.insert(menu131a);
SysPortalMenu menu132 = new SysPortalMenu();
menu132.setId("SysPortalMenu");
menu132.setName("菜单列表");
menu132.setCode("SysPortalMenu");
menu132.setPath("/sys/portal/menu");
menu132.setComp("/sys/portal/menu/index");
menu132.setOrnum(12);
menu132.setPid("SysPortal");
menu132.setCatag(true);
menu132.setAvtag(true);
menu132.setShtag(true);
menu132.setType("M");
menu132.setPorid("sys");
menuService.insert(menu132);
SysPortalMenu menu132a = new SysPortalMenu();
menu132a.setId("SysPortalMenuEdit");
menu132a.setName("菜单编辑");
menu132a.setCode("SysPortalMenuEdit");
menu132a.setPath("/sys/portal/menu/edit");
menu132a.setComp("/sys/portal/menu/edit");
menu132a.setOrnum(13);
menu132a.setPid("SysPortal");
menu132a.setCatag(true);
menu132a.setAvtag(true);
menu132a.setShtag(false);
menu132a.setType("M");
menu132a.setPorid("sys");
menuService.insert(menu132a);
SysPortalMenu menu133 = new SysPortalMenu();
menu133.setId("SysPortalRole");
menu133.setName("菜单角色");
menu133.setCode("SysPortalRole");
menu133.setPath("/sys/portal/role");
menu133.setComp("/sys/portal/role/index");
menu133.setOrnum(14);
menu133.setPid("SysPortal");
menu133.setCatag(true);
menu133.setAvtag(true);
menu133.setShtag(true);
menu133.setType("M");
menu133.setPorid("sys");
menuService.insert(menu133);
SysPortalMenu menu133a = new SysPortalMenu();
menu133a.setId("SysPortalRoleEdit");
menu133a.setName("角色编辑");
menu133a.setCode("SysPortalRoleEdit");
menu133a.setPath("/sys/portal/role/edit");
menu133a.setComp("/sys/portal/role/edit");
menu133a.setOrnum(15);
menu133a.setPid("SysPortal");
menu133a.setCatag(true);
menu133a.setAvtag(true);
menu133a.setShtag(false);
menu133a.setType("M");
menu133a.setPorid("sys");
menuService.insert(menu133a);
//-----------------监控中心--------------------
SysPortalMenu menu2 = new SysPortalMenu();
menu2.setId("Mon");
menu2.setName("监控中心");
menu2.setCode("Mon");
menu2.setComp("LAYOUT");
menu2.setPath("/mon");
menu2.setRedirect("/mon/server/main");
menu2.setOrnum(2);
menu2.setIcon("ant-design:fund-outlined");
menu2.setAvtag(true);
menu2.setShtag(true);
menu2.setType("D");
menu2.setPorid("sys");
menuService.insert(menu2);
SysPortalMenu menu211 = new SysPortalMenu();
menu211.setId("MonOnlineUser");
menu211.setName("在线用户");
menu211.setCode("MonOnlineUser");
menu211.setPath("/mon/online/user");
menu211.setComp("/mon/online/user/index");
menu211.setOrnum(211);
menu211.setPid("Mon");
menu211.setCatag(true);
menu211.setAvtag(true);
menu211.setShtag(true);
menu211.setType("M");
menu211.setPorid("sys");
menuService.insert(menu211);
SysPortalMenu menu221 = new SysPortalMenu();
menu221.setId("MonLogLogin");
menu221.setName("登录日志");
menu221.setCode("MonLogLogin");
menu221.setPath("/mon/log/login");
menu221.setComp("/mon/log/login/index");
menu221.setOrnum(221);
menu221.setPid("Mon");
menu221.setCatag(true);
menu221.setAvtag(true);
menu221.setShtag(true);
menu221.setType("M");
menu221.setPorid("sys");
menuService.insert(menu221);
SysPortalMenu menu222 = new SysPortalMenu();
menu222.setId("MonLogOper");
menu222.setName("操作日志");
menu222.setCode("MonLogOper");
menu222.setPath("/mon/log/oper");
menu222.setComp("/mon/log/oper/index");
menu222.setOrnum(222);
menu222.setPid("Mon");
menu222.setCatag(true);
menu222.setAvtag(true);
menu222.setShtag(true);
menu222.setType("M");
menu222.setPorid("sys");
menuService.insert(menu222);
SysPortalMenu menu223 = new SysPortalMenu();
menu223.setId("MonLogError");
menu223.setName("错误日志");
menu223.setCode("MonLogError");
menu223.setPath("/mon/log/error");
menu223.setComp("/mon/log/error/index");
menu223.setOrnum(223);
menu223.setPid("Mon");
menu223.setCatag(true);
menu223.setAvtag(true);
menu223.setShtag(true);
menu223.setType("M");
menu223.setPorid("sys");
menuService.insert(menu223);
SysPortalMenu menu261 = new SysPortalMenu();
menu261.setId("MonJobMain");
menu261.setName("定时任务");
menu261.setCode("MonJobMain");
menu261.setPath("/mon/job/main");
menu261.setComp("/mon/job/main/index");
menu261.setOrnum(261);
menu261.setPid("Mon");
menu261.setCatag(true);
menu261.setAvtag(true);
menu261.setShtag(true);
menu261.setType("M");
menu261.setPorid("sys");
menuService.insert(menu261);
SysPortalMenu menu262 = new SysPortalMenu();
menu262.setId("MonJobMainEdit");
menu262.setName("任务编辑");
menu262.setCode("MonJobMainEdit");
menu262.setPath("/mon/job/main/edit");
menu262.setComp("/mon/job/main/edit");
menu262.setOrnum(262);
menu262.setPid("Mon");
menu262.setCatag(true);
menu262.setAvtag(true);
menu262.setShtag(false);
menu262.setType("M");
menu262.setPorid("sys");
menuService.insert(menu262);
SysPortalMenu menu263 = new SysPortalMenu();
menu263.setId("MonJobLog");
menu263.setName("任务日志");
menu263.setCode("MonJobLog");
menu263.setPath("/mon/job/log");
menu263.setComp("/mon/job/log/index");
menu263.setOrnum(263);
menu263.setPid("Mon");
menu263.setCatag(true);
menu263.setAvtag(true);
menu263.setShtag(false);
menu263.setType("M");
menu263.setPorid("sys");
menuService.insert(menu263);
// SysPortalMenu menu271 = new SysPortalMenu();
// menu271.setId("MonServerMain");
// menu271.setName("服务监控");
// menu271.setCode("MonServerMain");
// menu271.setPath("/mon/server/main");
// menu271.setComp("/mon/server/main/show");
// menu271.setOrnum(271);
// menu271.setPid("Mon");
// menu271.setCatag(false);
// menu271.setAvtag(true);
// menu271.setShtag(true);
// menu271.setType("M");
// menu271.setPorid("sys");
// menuService.insert(menu271);
//
// SysPortalMenu menu281 = new SysPortalMenu();
// menu281.setId("MonCacheMain");
// menu281.setName("缓存监控");
// menu281.setCode("MonCacheMain");
// menu281.setPath("/mon/cache/main");
// menu281.setComp("/mon/cache/main/show");
// menu281.setOrnum(281);
// menu281.setPid("Mon");
// menu281.setCatag(false);
// menu281.setAvtag(true);
// menu281.setShtag(true);
// menu281.setType("M");
// menu281.setPorid("sys");
// menuService.insert(menu281);
//
// SysPortalMenu menu291 = new SysPortalMenu();
// menu291.setId("MonDbMain");
// menu291.setName("数据监控");
// menu291.setCode("MonDbMain");
// menu291.setPath("/mon/db/main");
// menu291.setComp("http://localhost:5000/druid/sql.html");
// menu291.setOrnum(291);
// menu291.setPid("Mon");
// menu291.setIftag(true);
// //menu122.setExtag(true);//外链
// menu291.setCatag(false);
// menu291.setAvtag(true);
// menu291.setShtag(true);
// menu291.setType("M");
// menu291.setPorid("sys");
// menuService.insert(menu291);
//-----------------辅助工具--------------------
SysPortalMenu menu3 = new SysPortalMenu();
menu3.setId("Ass");
menu3.setName("辅助工具");
menu3.setCode("Ass");
menu3.setComp("LAYOUT");
menu3.setPath("/ass");
menu3.setRedirect("/ass/dict/main");
menu3.setOrnum(3);
menu3.setIcon("ant-design:tool-outlined");
menu3.setAvtag(true);
menu3.setShtag(true);
menu3.setType("D");
menu3.setPorid("sys");
menuService.insert(menu3);
// SysPortalMenu menu311 = new SysPortalMenu();
// menu311.setId("AssCogeForm");
// menu311.setName("表单设计");
// menu311.setCode("AssCogeForm");
// menu311.setPath("/ass/coge/form");
// menu311.setComp("/ass/coge/form/index");
// menu311.setOrnum(311);
// menu311.setPid("Ass");
// menu311.setCatag(false);
// menu311.setAvtag(true);
// menu311.setShtag(true);
// menu311.setType("M");
// menu311.setPorid("sys");
// menuService.insert(menu311);
//
// SysPortalMenu menu312 = new SysPortalMenu();
// menu312.setId("AssCogeFormEdit");
// menu312.setName("表单设计编辑");
// menu312.setCode("AssCogeFormEdit");
// menu312.setPath("/ass/coge/form/edit");
// menu312.setComp("/ass/coge/form/edit");
// menu312.setOrnum(312);
// menu312.setPid("Ass");
// menu312.setCatag(false);
// menu312.setAvtag(true);
// menu312.setShtag(false);
// menu312.setType("M");
// menu312.setPorid("sys");
// menuService.insert(menu312);
// SysPortalMenu menu341 = new SysPortalMenu();
// menu341.setId("AssCogeTable");
// menu341.setName("代码生成");
// menu341.setCode("AssCogeTable");
// menu341.setPath("/ass/coge/table");
// menu341.setComp("/ass/coge/table/index");
// menu341.setOrnum(341);
// menu341.setPid("Ass");
// menu341.setCatag(false);
// menu341.setAvtag(true);
// menu341.setShtag(true);
// menu341.setType("M");
// menu341.setPorid("sys");
// menuService.insert(menu341);
//
// SysPortalMenu menu342 = new SysPortalMenu();
// menu342.setId("AssCogeTableEdit");
// menu342.setName("代码生成");
// menu342.setCode("AssCogeTableEdit");
// menu342.setPath("/ass/coge/table/edit");
// menu342.setComp("/ass/coge/table/edit");
// menu342.setOrnum(342);
// menu342.setPid("Ass");
// menu342.setCatag(false);
// menu342.setAvtag(true);
// menu342.setShtag(false);
// menu342.setType("M");
// menu342.setPorid("sys");
// menuService.insert(menu342);
SysPortalMenu menu351 = new SysPortalMenu();
menu351.setId("AssDictMain");
menu351.setName("数据字典");
menu351.setCode("AssDictMain");
menu351.setPath("/ass/dict/main");
menu351.setComp("/ass/dict/main/index");
menu351.setOrnum(351);
menu351.setPid("Ass");
menu351.setCatag(false);
menu351.setAvtag(true);
menu351.setShtag(true);
menu351.setType("M");
menu351.setPorid("sys");
menuService.insert(menu351);
SysPortalMenu menu352 = new SysPortalMenu();
menu352.setId("AssDictData");
menu352.setName("字典数据");
menu352.setCode("AssDictData");
menu352.setPath("/ass/dict/data");
menu352.setComp("/ass/dict/data/index");
menu352.setOrnum(352);
menu352.setPid("Ass");
menu352.setCatag(false);
menu352.setAvtag(true);
menu352.setShtag(false);
menu352.setType("M");
menu352.setPorid("sys");
menuService.insert(menu352);
SysPortalMenu menu361 = new SysPortalMenu();
menu361.setId("AssNumMain");
menu361.setName("编号策略");
menu361.setCode("AssNumMain");
menu361.setPath("/ass/num/main");
menu361.setComp("/ass/num/main/index");
menu361.setOrnum(361);
menu361.setPid("Ass");
menu361.setCatag(false);
menu361.setAvtag(true);
menu361.setShtag(true);
menu361.setType("M");
menu361.setPorid("sys");
menuService.insert(menu361);
// SysPortalMenu menu371 = new SysPortalMenu();
// menu371.setId("AssAddrMain");
// menu371.setName("省市区县");
// menu371.setCode("AssAddrMain");
// menu371.setPath("/ass/addr/main");
// menu371.setComp("/ass/addr/main/index");
// menu371.setOrnum(371);
// menu371.setPid("Ass");
// menu371.setCatag(false);
// menu371.setAvtag(true);
// menu371.setShtag(true);
// menu371.setType("M");
// menu371.setPorid("sys");
// menuService.insert(menu371);
//-----------------数字办公--------------------
// SysPortalMenu menu4 = new SysPortalMenu();
// menu4.setId("Oa");
// menu4.setName("数字办公");
// menu4.setCode("Oa");
// menu4.setComp("LAYOUT");
// menu4.setPath("/oa");
// menu4.setRedirect("/oa/flow/temp");
// menu4.setOrnum(4);
// menu4.setIcon("ele-Menu");
// menu4.setAvtag(true);
// menu4.setShtag(true);
// menu4.setType("D");
// menu4.setPorid("sys");
// menuService.insert(menu4);
SysPortalMenu menu41 = new SysPortalMenu();
menu41.setId("OaFlow");
menu41.setName("流程管理");
menu41.setCode("OaFlow");
menu41.setComp("LAYOUT");
menu41.setPath("/oa/flow");
menu41.setRedirect("/oa/flow/temp");
menu41.setOrnum(4);
menu41.setIcon("ant-design:retweet-outlined");
menu41.setAvtag(true);
menu41.setShtag(true);
menu41.setType("D");
menu41.setPorid("sys");
menuService.insert(menu41);
SysPortalMenu menu411 = new SysPortalMenu();
menu411.setId("OaFlowCate");
menu411.setName("流程分类");
menu411.setCode("OaFlowCate");
menu411.setPath("/oa/flow/cate");
menu411.setComp("/oa/flow/cate/index");
menu411.setOrnum(411);
menu411.setIcon("ele-Tickets");
menu411.setPid("OaFlow");
menu411.setCatag(true);
menu411.setAvtag(true);
menu411.setShtag(true);
menu411.setType("M");
menu411.setPorid("sys");
menuService.insert(menu411);
SysPortalMenu menu411a = new SysPortalMenu();
menu411a.setId("OaFlowCateEdit");
menu411a.setName("流程分类编辑");
menu411a.setCode("OaFlowCateEdit");
menu411a.setPath("/oa/flow/cate/edit");
menu411a.setComp("/oa/flow/cate/edit");
menu411a.setOrnum(4111);
menu411a.setIcon("ele-Tickets");
menu411a.setPid("OaFlow");
menu411a.setCatag(true);
menu411a.setAvtag(true);
menu411a.setShtag(false);
menu411a.setType("M");
menu411a.setPorid("sys");
menuService.insert(menu411a);
SysPortalMenu menu412 = new SysPortalMenu();
menu412.setId("OaFlowTemp");
menu412.setName("流程模板");
menu412.setCode("OaFlowTemp");
menu412.setPath("/oa/flow/temp");
menu412.setComp("/oa/flow/temp/index");
menu412.setOrnum(412);
menu412.setIcon("ele-Tickets");
menu412.setPid("OaFlow");
menu412.setCatag(true);
menu412.setAvtag(true);
menu412.setShtag(true);
menu412.setType("M");
menu412.setPorid("sys");
menuService.insert(menu412);
SysPortalMenu menu412a = new SysPortalMenu();
menu412a.setId("OaFlowTempEdit");
menu412a.setName("流程模板编辑");
menu412a.setCode("OaFlowTempEdit");
menu412a.setPath("/oa/flow/temp/edit");
menu412a.setComp("/oa/flow/temp/edit");
menu412a.setOrnum(4121);
menu412a.setIcon("ele-Tickets");
menu412a.setPid("OaFlow");
menu412a.setCatag(true);
menu412a.setAvtag(true);
menu412a.setShtag(false);
menu412a.setType("M");
menu412a.setPorid("sys");
menuService.insert(menu412a);
SysPortalMenu menu413 = new SysPortalMenu();
menu413.setId("OaFlowMain");
menu413.setName("流程实例");
menu413.setCode("OaFlowMain");
menu413.setPath("/oa/flow/main");
menu413.setComp("/oa/flow/main/index");
menu413.setOrnum(413);
menu413.setIcon("ele-Tickets");
menu413.setPid("OaFlow");
menu413.setCatag(true);
menu413.setAvtag(true);
menu413.setShtag(true);
menu413.setType("M");
menu413.setPorid("sys");
menuService.insert(menu413);
SysPortalMenu menu413a = new SysPortalMenu();
menu413a.setId("OaFlowMainEdit");
menu413a.setName("流程实例编辑");
menu413a.setCode("OaFlowMainEdit");
menu413a.setPath("/oa/flow/main/edit");
menu413a.setComp("/oa/flow/main/edit");
menu413a.setOrnum(4131);
menu413a.setIcon("ele-Tickets");
menu413a.setPid("OaFlow");
menu413a.setCatag(true);
menu413a.setAvtag(true);
menu413a.setShtag(false);
menu413a.setType("M");
menu413a.setPorid("sys");
menuService.insert(menu413a);
SysPortalMenu menu413b = new SysPortalMenu();
menu413b.setId("OaFlowMainView");
menu413b.setName("流程实例查看");
menu413b.setCode("OaFlowMainView");
menu413b.setPath("/oa/flow/main/view");
menu413b.setComp("/oa/flow/main/view");
menu413b.setOrnum(4132);
menu413b.setIcon("ele-Tickets");
menu413b.setPid("OaFlow");
menu413b.setCatag(true);
menu413b.setAvtag(true);
menu413b.setShtag(false);
menu413b.setType("M");
menu413b.setPorid("sys");
menuService.insert(menu413b);
//-----------------DEMO--------------------
SysPortalMenu menu8 = new SysPortalMenu();
menu8.setId("My");
menu8.setName("测试样例");
menu8.setCode("My");
menu8.setComp("LAYOUT");
menu8.setPath("/my");
menu8.setRedirect("/my/demo/main");
menu8.setOrnum(8);
menu8.setIcon("ant-design:trophy-outlined");
menu8.setAvtag(true);
menu8.setShtag(true);
menu8.setType("D");
menu8.setPorid("sys");
menuService.insert(menu8);
SysPortalMenu menu811 = new SysPortalMenu();
menu811.setId("MyDemoCate");
menu811.setName("DEMO分类");
menu811.setCode("MyDemoCate");
menu811.setPath("/my/demo/cate");
menu811.setComp("/my/demo/cate/index");
menu811.setOrnum(811);
menu811.setIcon("ele-Tickets");
menu811.setPid("My");
menu811.setCatag(true);
menu811.setAvtag(true);
menu811.setShtag(true);
menu811.setType("M");
menu811.setPorid("sys");
menuService.insert(menu811);
SysPortalMenu menu812 = new SysPortalMenu();
menu812.setId("MyDemoMain");
menu812.setName("DEMO清单");
menu812.setCode("MyDemoMain");
menu812.setPath("/my/demo/main");
menu812.setComp("/my/demo/main/index");
menu812.setOrnum(812);
menu812.setIcon("ele-Tickets");
menu812.setPid("My");
menu812.setCatag(true);
menu812.setAvtag(true);
menu812.setShtag(true);
menu812.setType("M");
menu812.setPorid("sys");
menuService.insert(menu812);
SysPortalMenu menu813 = new SysPortalMenu();
menu813.setId("MyDemoMainEdit");
menu813.setName("DEMO编辑");
menu813.setCode("MyDemoMainEdit");
menu813.setPath("/my/demo/main/edit");
menu813.setComp("/my/demo/main/edit");
menu813.setOrnum(813);
menu813.setIcon("ele-Tickets");
menu813.setPid("My");
menu813.setCatag(true);
menu813.setAvtag(true);
menu813.setShtag(false);
menu813.setType("M");
menu813.setPorid("sys");
menuService.insert(menu813);
SysPortalMenu menu999 = new SysPortalMenu();
menu999.setId("AboutPage");
menu999.setName("关于");
menu999.setCode("AboutPage");
menu999.setPath("/sys/about");
menu999.setComp("/sys/about/index");
menu999.setOrnum(999);
menu999.setIcon("simple-icons:about-dot-me");
menu999.setCatag(true);
menu999.setAvtag(true);
menu999.setShtag(true);
menu999.setType("M");
menu999.setPorid("sys");
menuService.insert(menu999);
}
//营销门户的菜单初始化
protected void initSaMenu() {
SysPortalMenu home = new SysPortalMenu();
home.setId("Sa-Home");
home.setName("营销首页");
home.setCode("Home");
home.setComp("/home/sa");
home.setPath("/home");
home.setOrnum(0);
home.setIcon("ele-House");
home.setAvtag(true);
home.setShtag(true);
home.setType("M");
home.setPorid("sa");
menuService.insert(home);
SysPortalMenu menu1 = new SysPortalMenu();
menu1.setId("Sa-Oa");
menu1.setName("日常办公");
menu1.setCode("Oa");
menu1.setComp("LAYOUT");
menu1.setPath("/oa");
menu1.setRedirect("/oa/flow/main");
menu1.setOrnum(1);
menu1.setIcon("ele-Menu");
menu1.setAvtag(true);
menu1.setShtag(true);
menu1.setType("D");
menu1.setPorid("sa");
menuService.insert(menu1);
SysPortalMenu menu11 = new SysPortalMenu();
menu11.setId("Sa-OaFlowMain");
menu11.setName("流程审批");
menu11.setCode("OaFlowMain");
menu11.setPath("/oa/flow/main");
menu11.setComp("/oa/flow/main/index");
menu11.setOrnum(11);
menu11.setIcon("ele-Tickets");
menu11.setPid("Sa-Oa");
menu11.setCatag(true);
menu11.setAvtag(true);
menu11.setShtag(true);
menu11.setType("M");
menu11.setPorid("sa");
menuService.insert(menu11);
}
@Autowired
private SysPortalMainService mainService;
@Autowired
private SysPortalMenuService menuService;
}
File diff suppressed because it is too large Load Diff
@@ -1,76 +0,0 @@
server.port=5000
#主数据源druid连接池配置
spring.datasource.primary.initialSize=5
spring.datasource.primary.minIdle=10
spring.datasource.primary.maxActive=20
spring.datasource.primary.maxWait=60000
spring.datasource.primary.timeBetweenEvictionRunsMillis=60000
spring.datasource.primary.minEvictableIdleTimeMillis=300000
spring.datasource.primary.maxEvictableIdleTimeMillis=900000
spring.datasource.primary.testWhileIdle=true
spring.datasource.primary.testOnBorrow=false
spring.datasource.primary.testOnReturn=false
#主数据源JPA配置
spring.datasource.primary.jpa.entityScan=com.abc.module
spring.datasource.primary.jpa.hbm2ddl.auto=update
#spring.datasource.primary.jpa.hbm2ddl.auto=none
#主数据源-mysql5.7
#spring.datasource.primary.dbType=mysql
#spring.datasource.primary.validationQuery=SELECT 1 FROM DUAL
#spring.datasource.primary.driver-class-name=com.mysql.jdbc.Driver
#spring.datasource.primary.url=jdbc:mysql://localhost:3306/vben-java?characterEncoding=utf-8&useSSL=false
#spring.datasource.primary.username=root
#spring.datasource.primary.password=123456
#主数据源-mysql8
spring.datasource.primary.dbType=mysql
spring.datasource.primary.validationQuery=SELECT 1 FROM DUAL
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.primary.url=jdbc:mysql://localhost:3306/vben-java?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC&nullCatalogMeansCurrent=true
spring.datasource.primary.username=root
spring.datasource.primary.password=123456
#主数据源-oracle
#spring.datasource.primary.dbType=oracle
#spring.datasource.primary.validationQuery=SELECT 1 FROM DUAL
#spring.datasource.primary.driver-class-name=oracle.jdbc.OracleDriver
##spring.datasource.primary.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
##spring.datasource.primary.username=scott
##spring.datasource.primary.password=123456
#主数据源-sqlserver
#spring.datasource.primary.dbType=sqlserver
#spring.datasource.primary.validationQuery=SELECT 1
#spring.datasource.primary.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
##spring.datasource.primary.url=jdbc:sqlserver://127.0.0.1:1433;SelectMethod=cursor;DatabaseName=vben
##spring.datasource.primary.username=sa
##spring.datasource.primary.password=123456
#本地附件上传位置
app.att.path=C:/vben/att
#app.att.path=/home/linux64/java/att
#认证方式 1代表session,2待办jwt token
app.authc.type=2
ldap.url=ldap://10.0.0.0:389
ldap.base=OU=xxx,DC=xxx,DC=com
ldap.userDn=CN=xxx,CN=Users,DC=xxx,DC=com
ldap.userPwd=xxx
ldap.referral=follow
ldap.domainName=%s@xxx.com
management.health.ldap.enabled=false
oss.configkey=
oss.accesskey=
oss.secretkey=
oss.bucket=
oss.endpoint=
oss.ishttps=N
oss.region=
vben.amap.key=key维护地址:https://lbs.amap.com/api/webservice/summary/
logging.config=classpath:config/logback-dev.xml
@@ -1,76 +0,0 @@
server.port=5000
#主数据源druid连接池配置
spring.datasource.primary.initialSize=5
spring.datasource.primary.minIdle=10
spring.datasource.primary.maxActive=20
spring.datasource.primary.maxWait=60000
spring.datasource.primary.timeBetweenEvictionRunsMillis=60000
spring.datasource.primary.minEvictableIdleTimeMillis=300000
spring.datasource.primary.maxEvictableIdleTimeMillis=900000
spring.datasource.primary.testWhileIdle=true
spring.datasource.primary.testOnBorrow=false
spring.datasource.primary.testOnReturn=false
#主数据源JPA配置
spring.datasource.primary.jpa.entityScan=com.abc.module
spring.datasource.primary.jpa.hbm2ddl.auto=update
#spring.datasource.primary.jpa.hbm2ddl.auto=none
#主数据源-mysql5.7
#spring.datasource.primary.dbType=mysql
#spring.datasource.primary.validationQuery=SELECT 1 FROM DUAL
#spring.datasource.primary.driver-class-name=com.mysql.jdbc.Driver
#spring.datasource.primary.url=jdbc:mysql://localhost:3306/vben-java?characterEncoding=utf-8&useSSL=false
#spring.datasource.primary.username=root
#spring.datasource.primary.password=123456
#主数据源-mysql8
spring.datasource.primary.dbType=mysql
spring.datasource.primary.validationQuery=SELECT 1 FROM DUAL
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.primary.url=jdbc:mysql://localhost:3306/vben-java?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC&nullCatalogMeansCurrent=true
spring.datasource.primary.username=root
spring.datasource.primary.password=123456
#主数据源-oracle
#spring.datasource.primary.dbType=oracle
#spring.datasource.primary.validationQuery=SELECT 1 FROM DUAL
#spring.datasource.primary.driver-class-name=oracle.jdbc.OracleDriver
##spring.datasource.primary.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
##spring.datasource.primary.username=scott
##spring.datasource.primary.password=123456
#主数据源-sqlserver
#spring.datasource.primary.dbType=sqlserver
#spring.datasource.primary.validationQuery=SELECT 1
#spring.datasource.primary.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
##spring.datasource.primary.url=jdbc:sqlserver://127.0.0.1:1433;SelectMethod=cursor;DatabaseName=vben
##spring.datasource.primary.username=sa
##spring.datasource.primary.password=123456
#本地附件上传位置
app.att.path=C:/vben/att
#app.att.path=/home/linux64/java/att
#认证方式 1代表session,2待办jwt token
app.authc.type=2
ldap.url=ldap://10.0.0.0:389
ldap.base=OU=xxx,DC=xxx,DC=com
ldap.userDn=CN=xxx,CN=Users,DC=xxx,DC=com
ldap.userPwd=xxx
ldap.referral=follow
ldap.domainName=%s@xxx.com
management.health.ldap.enabled=false
oss.configkey=
oss.accesskey=
oss.secretkey=
oss.bucket=
oss.endpoint=
oss.ishttps=N
oss.region=
vben.amap.key=key维护地址:https://lbs.amap.com/api/webservice/summary/
logging.config=classpath:config/logback-dev.xml
@@ -1,19 +0,0 @@
#web配置
spring.servlet.multipart.max-file-size=10240000
spring.servlet.multipart.max-request-size=10240000
server.compression.enabled=true
server.compression.mime-types=application/javascript,application/json,application/xml,text/html,text/xml,text/plain,text/css
server.compression.min-response-size=40960000
#最大连接数
http.maxTotal=100
http.defaultMaxPerRoute=20
http.connectTimeout=1000
http.connectionRequestTimeout=500
http.socketTimeout=10000
http.staleConnectionCheckEnabled=true
http.validateAfterInactivity=3000000
spring.profiles.active=dev
#spring.profiles.active=prd
@@ -1,115 +0,0 @@
# druid配置
spring:
datasource:
druid:
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
# login-username: 1
# login-password: 1
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 20000
merge-sql: true
wall:
config:
multi-statement-allow: true
jpa:
open-in-view: true
banner:
location: classpath:config/banner.txt
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
--- # redis
spring:
redis:
# 地址
host: localhost
# 端口,默认为6379
port: 6379
# 数据库索引
database: 1
# 密码
# password:
# # 连接超时时间
timeout: 10s
# 是否开启ssl
ssl: false
redisson:
# 线程池数量
threads: 4
# Netty线程池数量
nettyThreads: 8
# 单节点配置
singleServerConfig:
# 客户端名称
clientName: zsvg
# 最小空闲连接数
connectionMinimumIdleSize: 8
# 连接池大小
connectionPoolSize: 32
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
#logging.config: classpath:config/logback.xml
knife4j:
# 是否开启Knife4j增强模式
enable: true
# 是否开启生产环境保护策略
production: false
# basic:
# enable: true
# username: vben
# password: 123456
# 前端Ui的个性化配置属性
setting:
# 默认语言
language: zh-CN
# 是否显示Footer
enableFooter: false
# 是否开启动态参数调试功能
enableDynamicParameter: true
# 是否在每个Debug调试栏后显示刷新变量按钮
enableReloadCacheParameter: true
zsvg:
jwt:
header: Authorization
prefix: "Bearer "
#生成accessToken用的key
akey: 6EtRVaDRFyIe5pBlBh1p6dRD+fLA5phPMyEeVkaNcEMUcpvQwZtGNby24TzuTZ4OBuXTYUaWgZqsRwROg1XWFA==
#生成refreshToken用的key
rkey: W3UZyVu0VQCGMRPvU11CqDovDUku3XASJlXLu0zFZdvUyAvXoEVrumKnz1DSBJ4O5l49Mi2Hesx7Kct4UPTL9g==
#accessToken过期时间 此处单位秒 ,默认8小时 28800
atime: 28800
#accessToken过期时间 此处单位秒 ,默认30天 3456000
rtime: 3456000
# # 在线用户key
# online-key: online-token-
# # 验证码
# code-key: code-key-
# # token 续期检查时间范围(默认30分钟,单位毫秒),在token即将过期的一段时间内用户操作了,则给用户的token续期
# detect: 1800000
# # 续期时间范围,默认1小时,单位毫秒
# renew: 3600000
@@ -1,9 +0,0 @@
#应用初始化类型
app.init.orgName=XX集团
app.init.orgRootId=1
#-- sa:组织架构只包含一个sa管理员与一个vben的演示账户
#-- test:除了以上数据还包含张三李四等测试人员
#-- wc:除了以上数据还包含了一些世界杯球队与球员,用于测试大数据量
app.init.orgType=test
#第一次启动为哪个ui生成菜单
app.init.uiType=vue
@@ -1,6 +0,0 @@
${AnsiColor.GREEN}
vben V0.1 一个开箱即用的快速开发平台JAVA版
${AnsiColor.GREEN}
${spring-boot.version}
@@ -1,199 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。
当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
<property name="log.path" value="C:/vben/logs" />
<!--0. 日志格式和颜色渲染 -->
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<!-- 彩色日志格式 -->
<!--<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(-&#45;&#45;){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>-->
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!--1. 输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<!--<charset>UTF-8</charset>-->
</encoder>
</appender>
<!--2. 输出到文档-->
<!-- 2.1 level为 DEBUG 日志,时间滚动输出 -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/web_debug.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${log.path}/web-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录debug级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.2 level为 INFO 日志,时间滚动输出 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/web_info.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/web-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.3 level为 WARN 日志,时间滚动输出 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/web_warn.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/web-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.4 level为 ERROR 日志,时间滚动输出 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/web_error.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/web-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--
<logger>用来设置某一个包或者具体的某一个类的日志打印级别、
以及指定<appender>。<logger>仅有一个name属性,
一个可选的level和一个可选的addtivity属性。
name:用来指定受此logger约束的某一个包或者具体的某一个类。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
如果未设置此属性,那么当前logger将会继承上级的级别。
addtivity:是否向上级logger传递打印信息。默认是true。
<logger name="org.springframework.web" level="info"/>
<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
-->
<!--
使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
【logging.level.org.mybatis=debug logging.level.dao=debug】
-->
<!--
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
不能设置为INHERITED或者同义词NULL。默认是DEBUG
可以包含零个或多个元素,标识这个appender将会添加到这个logger。
-->
<!--<springProfile name="dev">-->
<!--<logger name="logging.level.org.hibernate" level="error"/>-->
<!--</springProfile>-->
<!-- 4. 最终的策略 -->
<!-- 4.1 开发环境:打印控制台-->
<logger name="vben" level="debug" additivity="false">
<appender-ref ref="CONSOLE" />
<appender-ref ref="INFO_FILE"/>
</logger>
<root level="warn">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
<!--4.2 生产环境:输出到文档-->
<!--<logger name="vben" level="info" additivity="true">-->
<!--<appender-ref ref="CONSOLE"/>-->
<!--<appender-ref ref="INFO_FILE"/>-->
<!--</logger>-->
<!--<root level="warn">-->
<!--<appender-ref ref="WARN_FILE" />-->
<!--<appender-ref ref="ERROR_FILE" />-->
<!--</root>-->
</configuration>
@@ -1,198 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。
当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
<property name="log.path" value="/home/vben/logs" />
<!--0. 日志格式和颜色渲染 -->
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<!-- 彩色日志格式 -->
<!--<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(-&#45;&#45;){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>-->
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!--1. 输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<!--<charset>UTF-8</charset>-->
</encoder>
</appender>
<!--2. 输出到文档-->
<!-- 2.1 level为 DEBUG 日志,时间滚动输出 -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/web_debug.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${log.path}/web-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录debug级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.2 level为 INFO 日志,时间滚动输出 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/web_info.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/web-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.3 level为 WARN 日志,时间滚动输出 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/web_warn.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/web-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.4 level为 ERROR 日志,时间滚动输出 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/web_error.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/web-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--
<logger>用来设置某一个包或者具体的某一个类的日志打印级别、
以及指定<appender>。<logger>仅有一个name属性,
一个可选的level和一个可选的addtivity属性。
name:用来指定受此logger约束的某一个包或者具体的某一个类。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
如果未设置此属性,那么当前logger将会继承上级的级别。
addtivity:是否向上级logger传递打印信息。默认是true。
<logger name="org.springframework.web" level="info"/>
<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
-->
<!--
使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
【logging.level.org.mybatis=debug logging.level.dao=debug】
-->
<!--
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
不能设置为INHERITED或者同义词NULL。默认是DEBUG
可以包含零个或多个元素,标识这个appender将会添加到这个logger。
-->
<!--<springProfile name="dev">-->
<!--<logger name="logging.level.org.hibernate" level="error"/>-->
<!--</springProfile>-->
<!-- 4. 最终的策略 -->
<!-- 4.1 开发环境:打印控制台-->
<!-- <logger name="vben" level="debug" additivity="false">-->
<!-- <appender-ref ref="CONSOLE" />-->
<!-- <appender-ref ref="INFO_FILE"/>-->
<!-- </logger>-->
<!-- <root level="warn">-->
<!-- <appender-ref ref="CONSOLE" />-->
<!-- <appender-ref ref="DEBUG_FILE" />-->
<!-- <appender-ref ref="INFO_FILE" />-->
<!-- <appender-ref ref="WARN_FILE" />-->
<!-- <appender-ref ref="ERROR_FILE" />-->
<!-- </root>-->
<!--4.2 生产环境:输出到文档-->
<logger name="vben" level="info" additivity="true">
<appender-ref ref="INFO_FILE"/>
</logger>
<root level="warn">
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
</configuration>
@@ -1,44 +0,0 @@
package ${packageName};
import vben.core.common.mvc.api.R;
import vben.core.common.mvc.dao.Sqler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("${table.name.replace("_","/")}")
public class ${table.bunam}Api {
@GetMapping
public R get(String name) {
Sqler sqler = new Sqler("${table.name}");
sqler.addLike("t.name", name);
return R.ok(service.findPageData(sqler));
}
@GetMapping("one/{id}")
public R getOne(@PathVariable String id) {
${table.bunam} main = service.findOne(id);
return R.ok(main);
}
@PostMapping
public R post(@RequestBody ${table.bunam} main) {
return R.ok(service.insert(main));
}
@PutMapping
public R put(@RequestBody ${table.bunam} main) {
return R.ok(service.update(main));
}
@DeleteMapping("{ids}")
public R delete(@PathVariable String[] ids) {
return R.ok(service.delete(ids));
}
@Autowired
private ${table.bunam}Service service;
}
@@ -1,20 +0,0 @@
package ${packageName};
import org.springframework.beans.factory.annotation.Autowired;
import vben.core.common.mvc.service.BaseMainService;
import javax.annotation.PostConstruct;
@Service
public class ${table.bunam}Service extends BaseMainService<${table.bunam}> {
@Autowired
private ${table.bunam}Repo repo;
@PostConstruct
public void initDao() {
super.setRepo(repo);
}
}
@@ -1,86 +0,0 @@
<template>
<el-drawer v-model='state.show' size='70%'>
<template #title>
<h4>${table.remark}编辑</h4>
</template>
<template #default>
<div style='padding: 20px;border-top: 1px solid #ccc'>
<el-form ref='formRef' #if($table.pecol==2)class='xform' :inline="true"#end :model='form' label-width='160px'>
<el-form-item label='${table.remark}名称:' prop='name' :rules="[{ required: true, message: '名称不能为空'}]">
<el-input v-model='form.name'/>
</el-form-item>
#foreach ($field in $fields)
<el-form-item label='${field.remark}:' prop='${field.name}'>
#if($field.type=="bool")
<el-switch v-model='form.${field.name}'/>
#elseif($field.type=="int")
<el-input-number v-model='form.${field.name}' controls-position='right' style='width: 100%'/>
#elseif($field.type=="long")
<el-input-number v-model='form.${field.name}' controls-position='right' style='width: 100%'/>
#elseif($field.type=="date")
<el-date-picker v-model='form.${field.name}' type="date" #if($table.pecol==2)style='width: 100%'#end/>
#else
<el-input v-model='form.${field.name}'/>
#end
</el-form-item>
#end
<el-form-item label='备注:' style='width: 100%'>
<el-input v-model='form.notes' type='textarea' />
</el-form-item>
<el-form-item label='排序号:'>
<el-input-number v-model='form.ornum' controls-position='right'/>
</el-form-item>
<el-form-item label='是否启用:'>
<el-switch v-model='form.avtag'/>
</el-form-item>
<el-form-item label='创建人:'>
<div class="zinput">{{ form.crman ? form.crman.name : '' }}</div>
</el-form-item>
<el-form-item label='创建时间:'>
<div class="zinput">{{ form.crtim }}</div>
</el-form-item>
<el-form-item label='更新人:'>
<div class="zinput">{{ form.upman ? form.upman.name : '' }}</div>
</el-form-item>
<el-form-item label='更新时间:'>
<div class="zinput">{{ form.uptim }}</div>
</el-form-item>
</el-form>
</div>
</template>
<template #footer>
<div style='flex: auto;margin: 20px'>
<el-button type='primary' @click='confirm'>确认</el-button>
<el-button @click='state.show = false'>取消</el-button>
</div>
</template>
</el-drawer>
</template>
<script lang='ts' setup>
import { reactive, ref, toRefs } from 'vue';
import { drawerOpen, drawerSave } from '/@/comps/page/edit';
import { FormInstance } from 'element-plus';
const formRef = ref<FormInstance>();
const state = reactive({
url: '/${table.name.replace("_","/")}', show: false, apis: [] as any,
form: { avtag: true } as any,
});
const { form } = toRefs(state);
//暴露open方法给父组件调用
const open = async (data: any) => {
await drawerOpen({ state, id: data.id });
};
defineExpose({ open });
//取得父组件listQuery方法的调用权
const emits = defineEmits(['listQuery']);
const confirm = async () => {
await drawerSave({ formRef: formRef.value, state });
emits('listQuery');
};
</script>
@@ -1,72 +0,0 @@
<template>
<div>
<el-card class='box-card'>
<template #header>
<div class='zjustify'>
<div>
<el-input v-model='state.form.name' placeholder='输入名称回车查询' class='list-search' clearable @keyup.enter='listQuery(state)'/>
<el-button type='primary' @click='listQuery(state)' plain>查 询</el-button>
<el-button class='more-button' :icon='state.moreParams?ArrowUp:ArrowDown' plain @click='state.moreParams=!state.moreParams'/>
</div>
<div>
<el-button type='success' :icon='Plus' @click='editRef.open({})' plain>新增</el-button>
<el-button type='danger' :icon='Delete' :disabled='state.multiple' @click='listDelete(state)' plain>删除</el-button>
</div>
</div>
<div v-show='state.moreParams' class='more-params'>
<el-form :inline='true' label-width='100px'>
<el-form-item label='更多参数1'>
<el-input v-model='state.form.xxx' placeholder='更多参数1'/>
</el-form-item>
<el-form-item label='更多参数2'>
<el-input v-model='state.form.yyy' placeholder='更多参数2'/>
</el-form-item>
<el-form-item/>
</el-form>
</div>
</template>
<el-table height='400' :cell-style="{padding:'2px'}" :row-style="{height: '36px'}"
v-loading='state.loading' :data='state.list'
border stripe @selection-change='listSelect($event,state)'>
<el-table-column type='selection' width='55' align='center'/>
<el-table-column label='序号' type='index' width='55' align='center'/>
<el-table-column label='${table.remark}名称' prop='id' width='160'>
<template #default='scope'>
<span style='cursor:pointer;color: #3e9ece' @click='editRef.open({id:scope.row.id})'>
{{ scope.row.name }}
</span>
</template>
</el-table-column>
<el-table-column label='备注' prop='notes' />
<el-table-column label='创建时间' prop='crtim' width='160' />
<el-table-column label='更新时间' prop='uptim' width='160' />
</el-table>
<el-pagination
@size-change='listQuery(state)' @current-change='listQuery(state)'
class='mt8' :pager-count='5' :page-sizes='[10, 20, 30]' background
:total='state.total' v-model:current-page='state.form.page'
v-model:page-size='state.form.pageSize'
layout='total, sizes, prev, pager, next, jumper'
/>
</el-card>
<Dedit ref="editRef" @close="listQuery(state)"/>
</div>
</template>
<script lang='ts' setup>
import {Plus, Delete, ArrowDown, ArrowUp} from '@element-plus/icons-vue';
import {onMounted, reactive, ref} from 'vue';
import {listQuery, listDelete, listSelect} from '/@/comps/page/index';
import Dedit from './edit.vue';
const editRef = ref() as any;
const state = reactive({
url: '/${table.name.replace("_","/")}', loading: true, ids: [],
form: {}, single: true, multiple: true, list: [], total: 0,
});
onMounted(() => {
listQuery(state);
});
</script>
@@ -1,76 +0,0 @@
<template>
<el-dialog v-model='state.show' title='${table.remark}编辑' draggable width='800px'>
<el-form ref='formRef' :model='form' #if($table.pecol==2)class='xform' :inline="true"#end label-width='120px'>
<el-form-item label='${table.remark}名称:' prop='name' :rules="[{ required: true, message: '名称不能为空'}]">
<el-input v-model='form.name'/>
</el-form-item>
#foreach ($field in $fields)
<el-form-item label='${field.remark}:' prop='${field.name}'>
#if($field.type=="bool")
<el-switch v-model='form.${field.name}'/>
#elseif($field.type=="int")
<el-input-number v-model='form.${field.name}' controls-position='right' style='width: 100%'/>
#elseif($field.type=="long")
<el-input-number v-model='form.${field.name}' controls-position='right' style='width: 100%'/>
#elseif($field.type=="date")
<el-date-picker v-model='form.${field.name}' type="date" #if($table.pecol==2)style='width: 100%'#end/>
#else
<el-input v-model='form.${field.name}'/>
#end
</el-form-item>
#end
<el-form-item label='是否可用:' prop='avtag' style='width: 50%'>
<el-switch v-model='form.avtag'>
</el-switch>
</el-form-item>
<el-form-item label='排序号:' prop='ornum' style='width: 50%'>
<el-input-number v-model='form.ornum' controls-position='right' style='width: 100%'/>
</el-form-item>
<el-form-item label='备注:' prop='notes' style='width: 100%'>
<el-input v-model='form.notes'></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class='dialog-footer'>
<el-button type='primary' @click='handleConfirm'>确 认</el-button>
<el-button @click='state.show = false'>取 消</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang='ts' setup>
import {defineExpose, reactive, ref, toRefs} from 'vue';
import {modalSave} from '/@/comps/page/edit';
import request from "/@/utils/request";
const state = reactive({
url: '/${table.name.replace("_","/")}', show: false,
form: {avtag: true} as any,
});
const {form} = toRefs(state);
const formRef = ref();
const open = async (data: any) => {
if (data && data.id) {
state.form = await request({
url: state.url + '/one/' + data.id,
method: 'get',
});
} else {
state.form = {avtag: true};
if (formRef.value) {
formRef.value.resetFields();
}
}
state.show = true;
};
defineExpose({open});
const emits = defineEmits(['close']);
const handleConfirm = async () => {
await modalSave({formRef: formRef.value, state, iouField: "crtim"});
emits('close');
};
</script>
@@ -1,71 +0,0 @@
<template>
<div>
<el-card class='box-card'>
<template #header>
<div class='zjustify'>
<div>
<el-input v-model='state.form.name' placeholder='输入名称回车查询' class='list-search' clearable @keyup.enter='listQuery(state)'/>
<el-button type='primary' @click='listQuery(state)' plain>查 询</el-button>
<el-button class='more-button' :icon='state.moreParams?ArrowUp:ArrowDown' plain @click='state.moreParams=!state.moreParams'/>
</div>
<div>
<el-button type='success' :icon='Plus' @click='editRef.open()' plain>新增</el-button>
<el-button type='danger' :icon='Delete' :disabled='state.multiple' @click='listDelete(state)' plain>删除</el-button>
</div>
</div>
<div v-show='state.moreParams' class='more-params'>
<el-form :inline='true' label-width='100px'>
<el-form-item label='更多参数1'>
<el-input v-model='state.form.xxx' placeholder='更多参数1'/>
</el-form-item>
<el-form-item label='更多参数2'>
<el-input v-model='state.form.yyy' placeholder='更多参数2'/>
</el-form-item>
<el-form-item/>
</el-form>
</div>
</template>
<el-table height='400' :cell-style="{padding:'2px'}" :row-style="{height: '36px'}"
v-loading='state.loading' :data='state.list'
border stripe @selection-change='listSelect($event,state)'>
<el-table-column type='selection' width='55' align='center'/>
<el-table-column label='序号' type='index' width='55' align='center'/>
<el-table-column label='${table.remark}名称' prop='id' width='160'>
<template #default='scope'>
<span style='cursor:pointer;color: #3e9ece' @click='editRef.open({id:scope.row.id})'>
{{ scope.row.name }}
</span>
</template>
</el-table-column>
<el-table-column label='备注' prop='notes' />
<el-table-column label='创建时间' prop='crtim' width='160' />
<el-table-column label='更新时间' prop='uptim' width='160' />
</el-table>
<el-pagination
@size-change='listQuery(state)' @current-change='listQuery(state)'
class='mt8' :pager-count='5' :page-sizes='[10, 20, 30]' background
:total='state.total' v-model:current-page='state.form.page'
v-model:page-size='state.form.pageSize'
layout='total, sizes, prev, pager, next, jumper'
/>
</el-card>
<Pedit ref="editRef" @close="listQuery(state)"/>
</div>
</template>
<script lang='ts' setup>
import {Plus, Delete, ArrowDown, ArrowUp} from '@element-plus/icons-vue';
import {onMounted, reactive, ref} from 'vue';
import {listQuery, listDelete, listSelect} from '/@/comps/page/index';
import Pedit from './edit.vue';
const editRef = ref() as any;
const state = reactive({
url: '/${table.name.replace("_","/")}', loading: true, ids: [],
form: {}, single: true, multiple: true, list: [], total: 0,
});
onMounted(() => {
listQuery(state);
});
</script>
@@ -1,88 +0,0 @@
<template>
<el-card class='box-card' :body-style="{padding:'2px 8px'}" shadow='never'>
<template #header>
<div class='zjustify'>
<div>
<div style='line-height: 32px'>${table.remark}编辑</div>
</div>
<div>
<el-button type='success' @click='tabSave({formRef,state,proxy,route})' plain>保 存</el-button>
<el-button type='info' @click='tabClose({proxy,route})' plain>关 闭</el-button>
</div>
</div>
</template>
<div style='margin-top: 8px;margin-bottom: 8px'>
<el-form ref="formRef" :inline="true" class='yform #if($table.pecol==1)yform100#elseif($table.pecol==4)yform25#end' :model='form' label-width='140px'>
<el-tabs type='card' v-model='activeName'>
<el-tab-pane label='基本信息' name='tab1'>
<div class="yform-div">
<el-form-item label='${table.remark}名称:' prop='name' :rules="[{ required: true, message: '名称不能为空'}]">
<el-input v-model='form.name'/>
</el-form-item>
#foreach ($field in $fields)
<el-form-item label='${field.remark}:' prop='${field.name}'>
#if($field.type=="bool")
<el-switch v-model='form.${field.name}'/>
#elseif($field.type=="int")
<el-input-number v-model='form.${field.name}' controls-position='right' #if($table.pecol!=1)style='width: 100%'#end/>
#elseif($field.type=="long")
<el-input-number v-model='form.${field.name}' controls-position='right' #if($table.pecol!=1)style='width: 100%'#end/>
#elseif($field.type=="date")
<el-date-picker v-model='form.${field.name}' type="date" #if($table.pecol!=1)style='width: 100%'#end/>
#else
<el-input v-model='form.${field.name}'/>
#end
</el-form-item>
#end
</div>
</el-tab-pane>
<el-tab-pane label='其他信息' name='tab9'>
<div class="yform-div">
<el-form-item label='备注:' style="width: 100%">
<el-input type='textarea' :rows='4' v-model='form.notes'/>
</el-form-item>
<el-form-item label='创建人:' style="width: 25%">
<div class="zinput">{{ form.crman ? form.crman.name : '' }}</div>
</el-form-item>
<el-form-item label='创建时间:' style="width: 25%">
<div class='zinput'> {{ form.crtim }}</div>
</el-form-item>
<el-form-item label='更新人:' style="width: 25%">
<div class="zinput">{{ form.upman ? form.upman.name : '' }}</div>
</el-form-item>
<el-form-item label='更新时间:' style="width: 25%">
<div class='zinput'> {{ form.uptim }}</div>
</el-form-item>
</div>
</el-tab-pane>
</el-tabs>
</el-form>
</div>
</el-card>
</template>
<script lang='ts'>
export default {name: '${table.bunam}Edit}'};
</script>
<script lang='ts' setup>
import {getCurrentInstance, onMounted, reactive, ref, toRefs} from 'vue';
import {editInit, tabSave, tabClose} from '/@/comps/page/edit';
import {useRoute} from 'vue-router';
import {FormInstance} from "element-plus";
const route = useRoute();
const formRef = ref<FormInstance>();
const {proxy} = getCurrentInstance() as any;
const activeName = ref('tab1');
const state = reactive({
url: '/${table.name.replace("_","/")}',
params: {path: '', query: ''},
form: {avtag: true} as any,
});
const {form} = toRefs(state);
onMounted(async () => {
await editInit({state, route});
});
</script>
@@ -1,70 +0,0 @@
<template>
<div>
<el-card class='box-card'>
<template #header>
<div class='zjustify'>
<div>
<el-input v-model='state.form.name' placeholder='输入名称回车查询' class='list-search' clearable @keyup.enter='listQuery(state)' />
<el-button type='primary' @click='listQuery(state)' plain>查 询</el-button>
<el-button class='more-button' :icon='state.moreParams?ArrowUp:ArrowDown' plain @click='state.moreParams=!state.moreParams' />
</div>
<div>
<el-button type='success' :icon='Plus' @click='tabAdd(state.url)' plain>新增</el-button>
<el-button type='danger' :icon='Delete' :disabled='state.multiple' @click='listDelete(state)' plain>删除</el-button>
</div>
</div>
<div v-show='state.moreParams' class='more-params'>
<el-form :inline='true' label-width='100px'>
<el-form-item label='更多参数1'>
<el-input v-model='state.form.xxx' placeholder='更多参数1'/>
</el-form-item>
<el-form-item label='更多参数2'>
<el-input v-model='state.form.yyy' placeholder='更多参数2'/>
</el-form-item>
<el-form-item/>
</el-form>
</div>
</template>
<el-table height='400' :cell-style="{padding:'2px'}" :row-style="{height: '36px'}"
v-loading='state.loading' :data='state.list'
border stripe @selection-change='listSelect($event,state)'>
<el-table-column type='selection' width='55' align='center' />
<el-table-column label='序号' type='index' width='55' align='center' />
<el-table-column label='${table.remark}名称' width='180'>
<template #default='scope'>
<span style='cursor:pointer;color: #3e9ece' @click='tabEdit(state.url,scope.row.id)'>
{{ scope.row.name }}
</span>
</template>
</el-table-column>
<el-table-column label='备注' prop='notes' />
<el-table-column label='创建时间' prop='crtim' width='160' />
<el-table-column label='更新时间' prop='uptim' width='160' />
</el-table>
<el-pagination
@size-change='listQuery(state)' @current-change='listQuery(state)'
class='mt8' :pager-count='5' :page-sizes='[10, 20, 30]' background
:total='state.total' v-model:current-page='state.form.page'
v-model:page-size='state.form.pageSize'
layout='total, sizes, prev, pager, next, jumper'
/>
</el-card>
</div>
</template>
<script lang='ts' setup>
import { Plus, Delete, ArrowDown, ArrowUp } from '@element-plus/icons-vue';
import { onMounted, reactive } from 'vue';
import { listQuery, listDelete, tabAdd, tabEdit, listSelect } from '/@/comps/page/index';
const state = reactive({
url: '/${table.name.replace("_","/")}', loading: true, ids: [],
form: {}, single: true, multiple: true, list: [], total: 0,
});
onMounted(() => {
listQuery(state);
});
</script>
+25
View File
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>vben-java</artifactId>
<groupId>com.zsvg</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>vben-apps</artifactId>
<packaging>pom</packaging>
<modules>
<module>vben-admin</module>
<module>vben-mybatis</module>
<module>vben-setup</module>
<module>vben-jpa</module>
</modules>
<description>
自定义应用层
</description>
</project>
+31
View File
@@ -0,0 +1,31 @@
# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/
FROM bellsoft/liberica-openjdk-rocky:17.0.16-cds
#FROM bellsoft/liberica-openjdk-rocky:21.0.8-cds
#FROM findepi/graalvm:java17-native
LABEL maintainer="baby_fox"
RUN mkdir -p /vben/server/logs \
/vben/server/temp \
/vben/skywalking/agent
WORKDIR /vben/server
ENV SERVER_PORT=8080 SNAIL_PORT=28080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
EXPOSE ${SERVER_PORT}
# 暴露 snail job 客户端端口 用于定时任务调度中心通信
EXPOSE ${SNAIL_PORT}
ADD ./target/vben-admin.jar ./app.jar
SHELL ["/bin/bash", "-c"]
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \
-Dsnail-job.port=${SNAIL_PORT} \
# 应用名称 如果想区分集群节点监控 改成不同的名称即可
#-Dskywalking.agent.service_name=vben-server \
#-javaagent:/vben/skywalking/agent/skywalking-agent.jar \
-XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \
-jar app.jar
+111
View File
@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>vben-apps</artifactId>
<groupId>com.zsvg</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>vben-admin</artifactId>
<description>
XXX管理系统
</description>
<dependencies>
<!-- Mysql驱动包 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- &lt;!&ndash; mp支持的数据库均支持 只需要增加对应的jdbc依赖即可 &ndash;&gt;-->
<!-- &lt;!&ndash; Oracle &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.oracle.database.jdbc</groupId>-->
<!-- <artifactId>ojdbc8</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; 兼容oracle低版本 &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.oracle.database.nls</groupId>-->
<!-- <artifactId>orai18n</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; PostgreSql &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>org.postgresql</groupId>-->
<!-- <artifactId>postgresql</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; SqlServer &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.microsoft.sqlserver</groupId>-->
<!-- <artifactId>mssql-jdbc</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>com.zsvg</groupId>
<artifactId>vben-bpm</artifactId>
</dependency>
<dependency>
<groupId>com.zsvg</groupId>
<artifactId>vben-common-mybatis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- skywalking 整合 logback -->
<!-- <dependency>-->
<!-- <groupId>org.apache.skywalking</groupId>-->
<!-- <artifactId>apm-toolkit-logback-1.x</artifactId>-->
<!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.apache.skywalking</groupId>-->
<!-- <artifactId>apm-toolkit-trace</artifactId>-->
<!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>-->
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${project.artifactId}</warName>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,18 @@
package vben;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
/**
* web容器中进行部署
*
* @author Lion Li
*/
public class DromaraServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(VbenAdmin.class);
}
}
@@ -0,0 +1,22 @@
package vben;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
/**
* 启动程序
*
*/
@SpringBootApplication
public class VbenAdmin {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(VbenAdmin.class);
application.setApplicationStartup(new BufferingApplicationStartup(2048));
application.run(args);
System.out.println("(♥◠‿◠)ノ゙ Vben Admin启动成功 ლ(´ڡ`ლ)゙");
}
}
@@ -0,0 +1,276 @@
--- # 监控中心配置
spring.boot.admin.client:
# 增加客户端开关
enabled: false
url: http://localhost:9090/admin
instance:
service-host-type: IP
metadata:
username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@
password: @monitor.password@
--- # snail-job 配置
snail-job:
enabled: false
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group: "vben_group"
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server:
host: 127.0.0.1
port: 17888
# 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段
namespace: ${spring.profiles.active}
# 随主应用端口漂移
port: 2${server.port}
# 客户端ip指定
host:
--- # 数据源配置
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic:
# 性能分析插件(有性能损耗 不建议生产环境使用)
p6spy: true
# 设置默认的数据源或者数据源组,默认值即为 master
primary: master
# 严格模式 匹配不到数据源则报错
strict: true
datasource:
# 主库数据源
master:
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://localhost:3306/vben-java?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: root
password: 123456
# # 从库数据源
# slave:
# lazy: true
# type: ${spring.datasource.type}
# driverClassName: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username:
# password:
# oracle:
# type: ${spring.datasource.type}
# driverClassName: oracle.jdbc.OracleDriver
# url: jdbc:oracle:thin:@//localhost:1521/XE
# username: ROOT
# password: root
# postgres:
# type: ${spring.datasource.type}
# driverClassName: org.postgresql.Driver
# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
# username: root
# password: root
# sqlserver:
# type: ${spring.datasource.type}
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
# username: SA
# password: root
hikari:
# 最大连接池数量
maxPoolSize: 20
# 最小空闲线程数量
minIdle: 10
# 配置获取连接等待超时的时间
connectionTimeout: 30000
# 校验超时时间
validationTimeout: 5000
# 空闲连接存活最大时间,默认10分钟
idleTimeout: 600000
# 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟
maxLifetime: 1800000
# 多久检查一次连接的活性
keepaliveTime: 30000
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring.data:
redis:
# 地址
host: localhost
# 端口,默认为6379
port: 6379
# 数据库索引
database: 0
# redis 密码必须配置
# password: vben
# 连接超时时间
timeout: 10s
# 是否开启ssl
ssl.enabled: false
# redisson 配置
redisson:
# redis key前缀
keyPrefix:
# 线程池数量
threads: 4
# Netty线程池数量
nettyThreads: 8
# 单节点配置
singleServerConfig:
# 客户端名称 不能用中文
clientName: vben-admin
# 最小空闲连接数
connectionMinimumIdleSize: 8
# 连接池大小
connectionPoolSize: 32
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
--- # mail 邮件发送
mail:
enabled: false
host: smtp.163.com
port: 465
# 是否需要用户名密码验证
auth: true
# 发送方,遵循RFC-822标准
from: xxx@163.com
# 用户名(注意:如果使用foxmail邮箱,此处user为qq号)
user: xxx@163.com
# 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助)
pass: xxxxxxxxxx
# 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。
starttlsEnable: true
# 使用SSL安全连接
sslEnable: true
# SMTP超时时长,单位毫秒,缺省值不超时
timeout: 0
# Socket连接超时值,单位毫秒,缺省值不超时
connectionTimeout: 0
--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用
sms:
# 配置源类型用于标定配置来源(interface,yaml)
config-type: yaml
# 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制
restricted: true
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
minute-max: 1
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
account-max: 30
# 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中
blends:
# 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可
# 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户
config1:
# 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: alibaba
# 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。
access-key-id: 您的accessKey
# 称为accessSecret有些称之为apiSecret
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
config2:
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: tencent
access-key-id: 您的accessKey
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
--- # 三方授权
justauth:
# 前端外网访问地址
address: http://localhost:5666
type:
maxkey:
# maxkey 服务器地址
# 注意 如下均配置均不需要修改 maxkey 已经内置好了数据
server-url: http://sso.maxkey.top
client-id: 876892492581044224
client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
redirect-uri: ${justauth.address}/social-callback?source=maxkey
topiam:
# topiam 服务器地址
server-url: http://127.0.0.1:1898/api/v1/authorize/y0q************spq***********8ol
client-id: 449c4*********937************759
client-secret: ac7***********1e0************28d
redirect-uri: ${justauth.address}/social-callback?source=topiam
scopes: [openid, email, phone, profile]
qq:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=qq
union-id: false
weibo:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=weibo
gitee:
client-id: d46cb33b700cc826680192caa8eda499235a766a96f8a06c16f5ae3da74ce55a
client-secret: 680c9d423de5e264f465b9d9741e79a0363020889abcdfa933993a5d140d95b3
redirect-uri: ${justauth.address}/#/social-callback?source=gitee
dingtalk:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=dingtalk
baidu:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=baidu
csdn:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=csdn
coding:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=coding
coding-group-name: xx
oschina:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=oschina
alipay_wallet:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet
alipay-public-key: MIIB**************DAQAB
wechat_open:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_open
wechat_mp:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
wechat_enterprise:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
agent-id: 1000002
gitlab:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab
gitea:
# 前端改动 https://gitee.com/JavaLionLi/plus-ui/pulls/204
# gitea 服务器地址
server-url: https://demo.gitea.com
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitea
--- # 其他设置
#app:
#附件地址,不设置而时默认为项目根目录下的/zsvg/atts
# attpath: C:/vben/att
@@ -0,0 +1,277 @@
--- # 监控中心配置
spring.boot.admin.client:
# 增加客户端开关
enabled: false
url: http://localhost:9090/admin
instance:
service-host-type: IP
metadata:
username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@
password: @monitor.password@
--- # snail-job 配置
snail-job:
enabled: false
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group: "vben_group"
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server:
host: 127.0.0.1
port: 17888
# 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段
namespace: ${spring.profiles.active}
# 随主应用端口漂移
port: 2${server.port}
# 客户端ip指定
host:
--- # 数据源配置
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic:
# 性能分析插件(有性能损耗 不建议生产环境使用)
p6spy: true
# 设置默认的数据源或者数据源组,默认值即为 master
primary: master
# 严格模式 匹配不到数据源则报错
strict: true
datasource:
# 主库数据源
master:
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://localhost:3306/vben-java?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: root
password: 123456
# # 从库数据源
# slave:
# lazy: true
# type: ${spring.datasource.type}
# driverClassName: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username:
# password:
# oracle:
# type: ${spring.datasource.type}
# driverClassName: oracle.jdbc.OracleDriver
# url: jdbc:oracle:thin:@//localhost:1521/XE
# username: ROOT
# password: root
# postgres:
# type: ${spring.datasource.type}
# driverClassName: org.postgresql.Driver
# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
# username: root
# password: root
# sqlserver:
# type: ${spring.datasource.type}
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
# username: SA
# password: root
hikari:
# 最大连接池数量
maxPoolSize: 20
# 最小空闲线程数量
minIdle: 10
# 配置获取连接等待超时的时间
connectionTimeout: 30000
# 校验超时时间
validationTimeout: 5000
# 空闲连接存活最大时间,默认10分钟
idleTimeout: 600000
# 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟
maxLifetime: 1800000
# 多久检查一次连接的活性
keepaliveTime: 30000
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring.data:
redis:
# 地址
host: localhost
# 端口,默认为6379
port: 6379
# 数据库索引
database: 0
# redis 密码必须配置
# password: vben
# 连接超时时间
timeout: 10s
# 是否开启ssl
ssl.enabled: false
# redisson 配置
redisson:
# redis key前缀
keyPrefix:
# 线程池数量
threads: 4
# Netty线程池数量
nettyThreads: 8
# 单节点配置
singleServerConfig:
# 客户端名称 不能用中文
clientName: vben-admin
# 最小空闲连接数
connectionMinimumIdleSize: 8
# 连接池大小
connectionPoolSize: 32
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
--- # mail 邮件发送
mail:
enabled: false
host: smtp.163.com
port: 465
# 是否需要用户名密码验证
auth: true
# 发送方,遵循RFC-822标准
from: xxx@163.com
# 用户名(注意:如果使用foxmail邮箱,此处user为qq号)
user: xxx@163.com
# 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助)
pass: xxxxxxxxxx
# 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。
starttlsEnable: true
# 使用SSL安全连接
sslEnable: true
# SMTP超时时长,单位毫秒,缺省值不超时
timeout: 0
# Socket连接超时值,单位毫秒,缺省值不超时
connectionTimeout: 0
--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用
sms:
# 配置源类型用于标定配置来源(interface,yaml)
config-type: yaml
# 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制
restricted: true
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
minute-max: 1
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
account-max: 30
# 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中
blends:
# 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可
# 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户
config1:
# 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: alibaba
# 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。
access-key-id: 您的accessKey
# 称为accessSecret有些称之为apiSecret
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
config2:
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: tencent
access-key-id: 您的accessKey
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
--- # 三方授权
justauth:
# 前端外网访问地址
address: http://localhost:5666
type:
maxkey:
# maxkey 服务器地址
# 注意 如下均配置均不需要修改 maxkey 已经内置好了数据
server-url: http://sso.maxkey.top
client-id: 876892492581044224
client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
redirect-uri: ${justauth.address}/social-callback?source=maxkey
topiam:
# topiam 服务器地址
server-url: http://127.0.0.1:1898/api/v1/authorize/y0q************spq***********8ol
client-id: 449c4*********937************759
client-secret: ac7***********1e0************28d
redirect-uri: ${justauth.address}/social-callback?source=topiam
scopes: [openid, email, phone, profile]
qq:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=qq
union-id: false
weibo:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=weibo
gitee:
client-id: d46cb33b700cc826680192caa8eda499235a766a96f8a06c16f5ae3da74ce55a
client-secret: 680c9d423de5e264f465b9d9741e79a0363020889abcdfa933993a5d140d95b3
redirect-uri: ${justauth.address}/#/social-callback?source=gitee
dingtalk:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=dingtalk
baidu:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=baidu
csdn:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=csdn
coding:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=coding
coding-group-name: xx
oschina:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=oschina
alipay_wallet:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet
alipay-public-key: MIIB**************DAQAB
wechat_open:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_open
wechat_mp:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
wechat_enterprise:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
agent-id: 1000002
gitlab:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab
gitea:
# 前端改动 https://gitee.com/JavaLionLi/plus-ui/pulls/204
# gitea 服务器地址
server-url: https://demo.gitea.com
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitea
--- # 其他设置
app:
# 前端外网访问地址
attpath: C:/vben/att
# attpath: /home/app/att
@@ -0,0 +1,267 @@
# 开发环境配置
server:
# 服务器的HTTP端口,默认为8080
port: 8080
servlet:
# 应用的访问路径
context-path: /
# undertow 配置
undertow:
# HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的
max-http-post-size: -1
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
# 每块buffer的空间大小,越小的空间被利用越充分
buffer-size: 512
# 是否分配的直接内存
direct-buffers: true
threads:
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
io: 8
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
worker: 256
captcha:
# 是否启用验证码校验
enable: true
# 验证码类型 math 数组计算 char 字符验证
type: MATH
# line 线段干扰 circle 圆圈干扰 shear 扭曲干扰
category: CIRCLE
# 数字验证码位数
numberLength: 1
# 字符验证码长度
charLength: 4
# 日志配置
logging:
level:
vben: @logging.level@
org.springframework: warn
org.mybatis.spring.mapper: error
org.apache.fury: warn
config: classpath:logback.xml
# 用户配置
user:
password:
# 密码最大错误次数
maxRetryCount: 5
# 密码锁定时间(默认10分钟)
lockTime: 10
# Spring配置
spring:
application:
name: vben-admin
threads:
# 开启虚拟线程 仅jdk21可用
virtual:
enabled: true
task:
execution:
# 从 springboot 3.5 开始 spring自带线程池
# 不再需要 AsyncConfig与ThreadPoolConfig 可直接注入线程池使用
thread-name-prefix: async-
# 由spring自己初始化线程池
mode: force
# 资源信息
messages:
# 国际化资源文件路径
basename: i18n/messages
profiles:
active: @profiles.active@
# 文件上传
servlet:
multipart:
# 单个文件大小
max-file-size: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
mvc:
# 设置静态资源路径 防止所有请求都去查静态资源
static-path-pattern: /static/**
format:
date-time: yyyy-MM-dd HH:mm:ss
jackson:
# 日期格式化
date-format: yyyy-MM-dd HH:mm:ss
serialization:
# 格式化输出
indent_output: false
# 忽略无法转换的对象
fail_on_empty_beans: false
deserialization:
# 允许对象忽略json中不存在的属性
fail_on_unknown_properties: false
# Sa-Token配置
sa-token:
# token名称 (同时也是cookie名称)
token-name: Authorization
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
is-share: false
# jwt秘钥
jwt-secret-key: abcdefghijklmnopqrstuvwxyz
# security配置
security:
# 排除路径
excludes:
- /*.html
- /**/*.html
- /**/*.css
- /**/*.js
- /favicon.ico
- /error
- /*/api-docs
- /*/api-docs/**
- /warm-flow-ui/config
# 多租户配置
tenant:
# 是否开启
enable: true
# 排除表
excludes:
- sys_menu
- sys_tenant
- sys_tenant_package
- sys_role_dept
- sys_role_menu
- sys_user_post
- sys_user_role
- sys_client
- sys_oss_config
- flow_spel
# MyBatisPlus配置
# https://baomidou.com/config/
mybatis-plus:
# 自定义配置 是否全局开启逻辑删除 关闭后 所有逻辑删除功能将失效
enableLogicDelete: true
# 多包名使用 例如 vben.**.mapper,org.xxx.**.mapper
mapperPackage: vben.**.mapper
# 对应的 XML 文件位置
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: vben.**.domain
global-config:
dbConfig:
# 主键类型
# AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
# 如需改为自增 需要将数据库表全部设置为自增
idType: ASSIGN_ID
# 数据加密
mybatis-encryptor:
# 是否开启加密
enable: false
# 默认加密算法
algorithm: BASE64
# 编码方式 BASE64/HEX。默认BASE64
encode: BASE64
# 安全秘钥 对称算法的秘钥 如:AES,SM4
password:
# 公私钥 非对称算法的公私钥 如:SM2,RSA
publicKey:
privateKey:
# api接口加密
api-decrypt:
# 是否开启全局接口加密
enabled: true
# AES 加密头标识
headerFlag: encrypt-key
# 响应加密公钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换
# 对应前端解密私钥 MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJnNwrj4hi/y3CCJu868ghCG5dUj8wZK++RNlTLcXoMmdZWEQ/u02RgD5LyLAXGjLOjbMtC+/J9qofpSGTKSx/MCAwEAAQ==
# 请求解密私钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换
# 对应前端加密公钥 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y=
springdoc:
api-docs:
# 是否开启接口文档
enabled: true
info:
# 标题
title: '标题:vben-admin后台管理系统_接口文档'
# 描述
description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...'
# 版本
version: '版本号: ${project.version}'
# 作者信息
contact:
name: baby_fox
email: 676948472@qq.com
url: https://gitee.com/vben/vben-java
#这里定义了两个分组,可定义多个,也可以不定义
group-configs:
- group: 1.自定义应用
packages-to-scan: vben.admin
- group: 2.系统管理
packages-to-scan: vben.base.sys
- group: 3.监控中心
packages-to-scan: vben.base.mon
- group: 4.辅助工具
packages-to-scan: vben.base.tool
- group: 5.工作流
packages-to-scan: vben.bpm
# 防止XSS攻击
xss:
# 过滤开关
enabled: true
# 排除链接
excludeUrls:
- /system/notice
- /oa/flow/tmpl
- /bpm/bus/tmpl
--- # 分布式锁 lock4j 全局配置
lock4j:
# 获取分布式锁超时时间,默认为 3000 毫秒
acquire-timeout: 3000
# 分布式锁的超时时间,默认为 30 秒
expire: 30000
--- # Actuator 监控端点的配置项
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: ALWAYS
logfile:
external-file: ./logs/sys-console.log
--- # 默认/推荐使用sse推送
sse:
enabled: true
path: /resource/sse
--- # websocket
websocket:
# 如果关闭 需要和前端开关一起关闭
enabled: false
# 路径
path: /resource/websocket
# 设置访问源地址
allowedOrigins: '*'
--- # warm-flow工作流配置
warm-flow:
# 是否开启工作流,默认true
enabled: true
# 是否开启设计器ui
ui: true
# 是否显示流程图顶部文字
top-text-show: true
# 是否渲染节点悬浮提示,默认true
node-tooltip: true
# 默认Authorization,如果有多个token,用逗号分隔
token-name: ${sa-token.token-name},clientid
@@ -0,0 +1,11 @@
Application Version: ${revision}
Spring Boot Version: ${spring-boot.version}
8b d8 88 db 88 88
`8b d8' 88 d88b 88 ""
`8b d8' 88 d8'`8b 88
`8b d8' 88,dPPYba, ,adPPYba, 8b,dPPYba, d8' `8b ,adPPYb,88 88,dPYba,,adPYba, 88 8b,dPPYba,
`8b d8' 88P' "8a a8P_____88 88P' `"8a d8YaaaaY8b a8" `Y88 88P' "88" "8a 88 88P' `"8a
`8b d8' 88 d8 8PP""""""" 88 88 d8""""""""8b 8b 88 88 88 88 88 88 88
`888' 88b, ,a8" "8b, ,aa 88 88 d8' `8b "8a, ,d88 88 88 88 88 88 88
`8' 8Y"Ybbd8"' `"Ybbd8"' 88 88 d8' `8b `"8bbdP"Y8 88 88 88 88 88 88
@@ -0,0 +1,62 @@
#错误消息
not.null=* 必须填写
user.jcaptcha.error=验证码错误
user.jcaptcha.expire=验证码已失效
user.not.exists=对不起, 您的账号:{0} 不存在.
user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
user.password.delete=对不起,您的账号:{0} 已被删除
user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员
role.blocked=角色已封禁,请联系管理员
user.logout.success=退出成功
length.not.valid=长度必须在{min}到{max}个字符之间
user.username.not.blank=用户名不能为空
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
user.username.length.valid=账户长度必须在{min}到{max}个字符之间
user.password.not.blank=用户密码不能为空
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
user.password.not.valid=* 5-50个字符
user.password.format.valid=密码必须包含大写字母、小写字母、数字和特殊字符
user.email.not.valid=邮箱格式错误
user.email.not.blank=邮箱不能为空
user.phonenumber.not.blank=用户手机号不能为空
user.mobile.phone.number.not.valid=手机号格式错误
user.login.success=登录成功
user.register.success=注册成功
user.register.save.error=保存用户 {0} 失败,注册账号已存在
user.register.error=注册失败,请联系系统管理人员
user.notfound=请重新登录
user.forcelogout=管理员强制退出,请重新登录
user.unknown.error=未知错误,请重新登录
auth.grant.type.error=认证权限类型错误
auth.grant.type.blocked=认证权限类型已禁用
auth.grant.type.not.blank=认证权限类型不能为空
auth.clientid.not.blank=认证客户端id不能为空
##文件上传消息
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
upload.filename.exceed.length=上传的文件名最长{0}个字符
##权限
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
repeat.submit.message=不允许重复提交,请稍候再试
rate.limiter.message=访问过于频繁,请稍候再试
sms.code.not.blank=短信验证码不能为空
sms.code.retry.limit.count=短信验证码输入错误{0}次
sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟
email.code.not.blank=邮箱验证码不能为空
email.code.retry.limit.count=邮箱验证码输入错误{0}次
email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟
xcx.code.not.blank=小程序[code]不能为空
social.source.not.blank=第三方登录平台[source]不能为空
social.code.not.blank=第三方登录平台[code]不能为空
social.state.not.blank=第三方登录平台[state]不能为空
##租户
tenant.number.not.blank=租户编号不能为空
tenant.not.exists=对不起, 您的租户不存在,请联系管理员
tenant.blocked=对不起,您的租户已禁用,请联系管理员
tenant.expired=对不起,您的租户已过期,请联系管理员
@@ -0,0 +1,62 @@
#错误消息
not.null=* Required fill in
user.jcaptcha.error=Captcha error
user.jcaptcha.expire=Captcha invalid
user.not.exists=Sorry, your account: {0} does not exist
user.password.not.match=User does not exist/Password error
user.password.retry.limit.count=Password input error {0} times
user.password.retry.limit.exceed=Password input error {0} times, account locked for {1} minutes
user.password.delete=Sorry, your account:{0} has been deleted
user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator
role.blocked=Role disabled,please contact administrators
user.logout.success=Exit successful
length.not.valid=The length must be between {min} and {max} characters
user.username.not.blank=Username cannot be blank
user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number
user.username.length.valid=Account length must be between {min} and {max} characters
user.password.not.blank=Password cannot be empty
user.password.length.valid=Password length must be between {min} and {max} characters
user.password.not.valid=* 5-50 characters
user.password.format.valid=Password must contain uppercase, lowercase, digit, and special character
user.email.not.valid=Mailbox format error
user.email.not.blank=Mailbox cannot be blank
user.phonenumber.not.blank=Phone number cannot be blank
user.mobile.phone.number.not.valid=Phone number format error
user.login.success=Login successful
user.register.success=Register successful
user.register.save.error=Failed to save user {0}, The registered account already exists
user.register.error=Register failed, please contact system administrator
user.notfound=Please login again
user.forcelogout=The administrator is forced to exit,please login again
user.unknown.error=Unknown error, please login again
auth.grant.type.error=Auth grant type error
auth.grant.type.blocked=Auth grant type disabled
auth.grant.type.not.blank=Auth grant type cannot be blank
auth.clientid.not.blank=Auth clientid cannot be blank
##文件上传消息
upload.exceed.maxSize=The uploaded file size exceeds the limit file size!<br/>the maximum allowed file size is:{0}MB!
upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters
##权限
no.permission=You do not have permission to the data,please contact your administrator to add permissions [{0}]
no.create.permission=You do not have permission to create data,please contact your administrator to add permissions [{0}]
no.update.permission=You do not have permission to modify data,please contact your administrator to add permissions [{0}]
no.delete.permission=You do not have permission to delete data,please contact your administrator to add permissions [{0}]
no.export.permission=You do not have permission to export data,please contact your administrator to add permissions [{0}]
no.view.permission=You do not have permission to view data,please contact your administrator to add permissions [{0}]
repeat.submit.message=Repeat submit is not allowed, please try again later
rate.limiter.message=Visit too frequently, please try again later
sms.code.not.blank=Sms code cannot be blank
sms.code.retry.limit.count=Sms code input error {0} times
sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes
email.code.not.blank=Email code cannot be blank
email.code.retry.limit.count=Email code input error {0} times
email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes
xcx.code.not.blank=Mini program [code] cannot be blank
social.source.not.blank=Social login platform [source] cannot be blank
social.code.not.blank=Social login platform [code] cannot be blank
social.state.not.blank=Social login platform [state] cannot be blank
##租户
tenant.number.not.blank=Tenant number cannot be blank
tenant.not.exists=Sorry, your tenant does not exist. Please contact the administrator
tenant.blocked=Sorry, your tenant is disabled. Please contact the administrator
tenant.expired=Sorry, your tenant has expired. Please contact the administrator.
@@ -0,0 +1,62 @@
#错误消息
not.null=* 必须填写
user.jcaptcha.error=验证码错误
user.jcaptcha.expire=验证码已失效
user.not.exists=对不起, 您的账号:{0} 不存在.
user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
user.password.delete=对不起,您的账号:{0} 已被删除
user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员
role.blocked=角色已封禁,请联系管理员
user.logout.success=退出成功
length.not.valid=长度必须在{min}到{max}个字符之间
user.username.not.blank=用户名不能为空
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
user.username.length.valid=账户长度必须在{min}到{max}个字符之间
user.password.not.blank=用户密码不能为空
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
user.password.not.valid=* 5-50个字符
user.password.format.valid=密码必须包含大写字母、小写字母、数字和特殊字符
user.email.not.valid=邮箱格式错误
user.email.not.blank=邮箱不能为空
user.phonenumber.not.blank=用户手机号不能为空
user.mobile.phone.number.not.valid=手机号格式错误
user.login.success=登录成功
user.register.success=注册成功
user.register.save.error=保存用户 {0} 失败,注册账号已存在
user.register.error=注册失败,请联系系统管理人员
user.notfound=请重新登录
user.forcelogout=管理员强制退出,请重新登录
user.unknown.error=未知错误,请重新登录
auth.grant.type.error=认证权限类型错误
auth.grant.type.blocked=认证权限类型已禁用
auth.grant.type.not.blank=认证权限类型不能为空
auth.clientid.not.blank=认证客户端id不能为空
##文件上传消息
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
upload.filename.exceed.length=上传的文件名最长{0}个字符
##权限
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
repeat.submit.message=不允许重复提交,请稍候再试
rate.limiter.message=访问过于频繁,请稍候再试
sms.code.not.blank=短信验证码不能为空
sms.code.retry.limit.count=短信验证码输入错误{0}次
sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟
email.code.not.blank=邮箱验证码不能为空
email.code.retry.limit.count=邮箱验证码输入错误{0}次
email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟
xcx.code.not.blank=小程序[code]不能为空
social.source.not.blank=第三方登录平台[source]不能为空
social.code.not.blank=第三方登录平台[code]不能为空
social.state.not.blank=第三方登录平台[state]不能为空
##租户
tenant.number.not.blank=租户编号不能为空
tenant.not.exists=对不起, 您的租户不存在,请联系管理员
tenant.blocked=对不起,您的租户已禁用,请联系管理员
tenant.expired=对不起,您的租户已过期,请联系管理员
@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="log.path" value="./zsvg/logs"/>
<property name="console.log.pattern"
value="%cyan(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${console.log.pattern}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!-- 控制台输出 -->
<appender name="file_console" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-console.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-console.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大 1天 -->
<maxHistory>1</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
</filter>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- info异步输出 -->
<appender name="async_info" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>512</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_info"/>
</appender>
<!-- error异步输出 -->
<appender name="async_error" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>512</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_error"/>
</appender>
<!-- 整合 skywalking 控制台输出 tid -->
<!-- <appender name="console" class="ch.qos.logback.core.ConsoleAppender">-->
<!-- <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">-->
<!-- <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">-->
<!-- <pattern>[%tid] ${console.log.pattern}</pattern>-->
<!-- </layout>-->
<!-- <charset>utf-8</charset>-->
<!-- </encoder>-->
<!-- </appender>-->
<!-- 整合 skywalking 推送采集日志 -->
<!-- <appender name="sky_log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">-->
<!-- <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">-->
<!-- <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">-->
<!-- <pattern>[%tid] ${console.log.pattern}</pattern>-->
<!-- </layout>-->
<!-- <charset>utf-8</charset>-->
<!-- </encoder>-->
<!-- </appender>-->
<!--系统操作日志-->
<root level="info">
<appender-ref ref="console" />
<appender-ref ref="async_info" />
<appender-ref ref="async_error" />
<appender-ref ref="file_console" />
<!-- <appender-ref ref="sky_log"/>-->
</root>
</configuration>
@@ -0,0 +1,83 @@
package ${packageName};
import cn.dev33.satoken.annotation.SaCheckPermission;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import vben.common.core.domain.R;
import vben.common.idempotent.annotation.RepeatSubmit;
import vben.common.jdbc.dto.PageData;
import vben.common.jdbc.sqler.Sqler;
import vben.common.log.annotation.Log;
import vben.common.log.enums.BusinessType;
/**
* ${table.remark}
*/
@RestController
@RequestMapping("${table.name.replace("_","/")}")
@RequiredArgsConstructor
public class ${table.bunam}Controller {
/**
* ${table.remark}分页查询
* @param name ${table.remark}名称
* @return ${table.remark}分页数据
*/
@GetMapping
public R<PageData> get(String name) {
Sqler sqler = new Sqler("${table.name}");
sqler.addLike("t.name", name);
sqler.addSelect("t.notes");
return R.ok(service.findPageData(sqler));
}
/**
* ${table.remark}详情查询
* @param id ID
* @return ${table.remark}对象
*/
@GetMapping("info/{id}")
public R<${table.bunam}> info(@PathVariable Long id) {
${table.bunam} main = service.select(id);
return R.ok(main);
}
/**
* ${table.remark}新增
* @param main ${table.remark}对象
* @return ID
*/
@PostMapping
@Log(title = "${table.remark}", businessType = BusinessType.INSERT)
@RepeatSubmit
public R<Long> post(@RequestBody ${table.bunam} main) {
return R.ok(null,service.insert(main));
}
/**
* ${table.remark}修改
* @param main ${table.remark}对象
* @return ID
*/
@PutMapping
@RepeatSubmit
@Log(title = "${table.remark}", businessType = BusinessType.UPDATE)
public R<Long> put(@RequestBody ${table.bunam} main) {
return R.ok(null,service.update(main));
}
/**
* ${table.remark}删除
* @param ids ID串
* @return 删除的${table.remark}数量
*/
@DeleteMapping("{ids}")
@Log(title = "${table.remark}", businessType = BusinessType.DELETE)
public R<Integer> delete(@PathVariable Long[] ids) {
return R.ok(service.delete(ids));
}
private final ${table.bunam}Service service;
}
@@ -1,9 +1,10 @@
package ${packageName};
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import vben.common.jpa.entity.BaseMainEntity;
@Entity
@Getter
@@ -2,7 +2,7 @@ package ${packageName};
import org.springframework.data.jpa.repository.JpaRepository;
public interface ${table.bunam}Repo extends JpaRepository<${table.bunam},String> {
public interface ${table.bunam}Repo extends JpaRepository<${table.bunam},Long> {
}
@@ -0,0 +1,22 @@
package ${packageName};
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import vben.common.jpa.service.BaseMainService;
@Service
@RequiredArgsConstructor
public class ${table.bunam}Service extends BaseMainService<${table.bunam}> {
private final ${table.bunam}Repo repo;
@PostConstruct
public void initDao() {
super.setRepo(repo);
}
}
@@ -0,0 +1,85 @@
package ${packageName};
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import vben.common.core.domain.R;
import vben.common.idempotent.annotation.RepeatSubmit;
import vben.common.jdbc.dto.PageData;
import vben.common.jdbc.sqler.JdbcHelper;
import vben.common.jdbc.sqler.Sqler;
import vben.common.log.annotation.Log;
import vben.common.log.enums.BusinessType;
/**
* ${table.remark}
*/
@RestController
@RequestMapping("${table.name.replace("_","/")}")
@RequiredArgsConstructor
public class ${table.bunam}Controller {
/**
* ${table.remark}分页查询
* @param name ${table.remark}名称
* @return ${table.remark}分页数据
*/
@GetMapping
public R<PageData> get(String name) {
Sqler sqler = new Sqler("${table.name}");
sqler.addLike("t.name", name);
sqler.addSelect("t.notes");
return R.ok(jdbcHelper.findPageData(sqler));
}
/**
* ${table.remark}详情查询
* @param id ID
* @return ${table.remark}对象
*/
@GetMapping("info/{id}")
public R<${table.bunam}> info(@PathVariable Long id) {
${table.bunam} main = service.select(id);
return R.ok(main);
}
/**
* ${table.remark}新增
* @param main ${table.remark}对象
* @return ID
*/
@PostMapping
@Log(title = "${table.remark}", businessType = BusinessType.INSERT)
@RepeatSubmit
public R<Long> post(@RequestBody ${table.bunam} main) {
return R.ok(null,service.insert(main));
}
/**
* ${table.remark}修改
* @param main ${table.remark}对象
* @return ID
*/
@PutMapping
@RepeatSubmit
@Log(title = "${table.remark}", businessType = BusinessType.UPDATE)
public R<Long> put(@RequestBody ${table.bunam} main) {
return R.ok(null,service.update(main));
}
/**
* ${table.remark}删除
* @param ids ID串
* @return 删除的${table.remark}数量
*/
@DeleteMapping("{ids}")
@Log(title = "${table.remark}", businessType = BusinessType.DELETE)
public R<Integer> delete(@PathVariable Long[] ids) {
return R.ok(service.delete(ids));
}
private final ${table.bunam}Service service;
private final JdbcHelper jdbcHelper;
}
@@ -0,0 +1,44 @@
package ${packageName};
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import vben.common.mybatis.core.domain.BaseMainEntity;
import java.io.Serial;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("$table.bunam")
public class $table.bunam extends BaseMainEntity {
@Serial
private static final long serialVersionUID = 1L;
#foreach ($field in $fields)
#if($field.type=="string")
private String $field.name;
#elseif($field.type=="int")
private Integer $field.name;
#elseif($field.type=="long")
private Long $field.name;
#elseif($field.type=="bool")
private Boolean $field.name;
#elseif($field.type=="date")
private Date $field.name;
#elseif($field.type=="decimal")
private BigDecimal $field.name;
#end
#end
}
@@ -1,10 +1,10 @@
package vben.extend.oa.test.two;
package ${packageName};
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface OaTestTwoMapper extends BaseMapper<OaTestTwo>
{
public interface ${table.bunam}Mapper extends BaseMapper<${table.bunam}> {
}
}
@@ -0,0 +1,23 @@
package ${packageName};
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import vben.common.mybatis.core.service.BaseMainService;
@Service
@RequiredArgsConstructor
public class ${table.bunam}Service extends BaseMainService<${table.bunam}> {
private final ${table.bunam}Mapper mapper;
@PostConstruct
public void initDao() {
super.setMapper(mapper);
}
}
@@ -1,7 +1,7 @@
{
path: '/${table.name.replace("_","/")}',
name: '${table.bunam}',
component: () => import('/@/pages/${table.name.replace("_","/")}/index.vue'),
component: () => import('/@/views/${table.name.replace("_","/")}/index.vue'),
meta:{
title: '${table.remark}清单',
isLink: '',
@@ -17,7 +17,7 @@
{
path: '/${table.name.replace("_","/")}/edit',
name: '${table.bunam}Edit',
component: () => import('/@/pages/${table.name.replace("_","/")}/edit.vue'),
component: () => import('/@/views/${table.name.replace("_","/")}/edit.vue'),
meta: {
title: '${table.remark}编辑',
isLink: '',
@@ -29,4 +29,4 @@
icon: 'ele-Tickets',
},
},
#end
#end
@@ -1,7 +1,7 @@
 insert into sys_portal_menu (id,ornum,pid,porid,type,code,icon,path,comp,extag,catag,shtag,iftag,name,crman,avtag)
 insert into sys_menu (id,ornum,pid,porid,type,code,icon,path,comp,extag,catag,shtag,iftag,name,crman,avtag)
values ('${table.bunam}',999991,null,'sys','M','${table.bunam}','ele-Tickets','/${table.name.replace("_","/")}','/${table.name.replace("_","/")}/index',0,1,1,0,'${table.remark}清单','sa',1);
#if($table.edtyp=="tab")
insert into sys_portal_menu (id,ornum,pid,porid,type,code,icon,path,comp,extag,catag,shtag,iftag,name,crman,avtag)
insert into sys_menu (id,ornum,pid,porid,type,code,icon,path,comp,extag,catag,shtag,iftag,name,crman,avtag)
values ('${table.bunam}Edit',999992,null,'sys','M','${table.bunam}Edit','ele-Tickets','/${table.name.replace("_","/")}/edit','/${table.name.replace("_","/")}/edit',0,1,0,0,'${table.remark}编辑','sa',1);
#end
#end
@@ -0,0 +1,62 @@
<script lang="ts" setup>
import { requestClient } from '#/api/request';
import { drawerSave, reset } from '#/utils/page/edit';
const emits = defineEmits(['close']);
const state = reactive({
url: '/${table.name.replace("_","/")}',
show: false,
form: {} as any,
});
const formRef = ref();
const { form } = toRefs(state);
const open = async (data: any) => {
state.form = data && data.id ? await requestClient.get(`${state.url}/info/${data.id}`) : { avtag: true };
await reset({ formRef: formRef.value, state });
};
defineExpose({ open });
const save = async () => {
await drawerSave({ formRef: formRef.value, state });
emits('close');
};
</script>
<template>
<el-drawer v-model="state.show" size="46%">
<template #header>
<h4>${table.remark}维护</h4>
</template>
<template #default>
<el-form ref="formRef" :model="form" label-width="140px" class="zform">
<el-form-item label="${table.remark}名称" prop="name" :rules="[{ required: true, message: '${table.remark}名称不能为空' }]">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="备注" prop="notes">
<el-input v-model="form.notes" :rows="3" type="textarea" />
</el-form-item>
<template v-if="form.crtim">
<el-form-item label="创建人" style="width: 50%">
<div>{{ form.cruna }}</div>
</el-form-item>
<el-form-item label="创建时间" style="width: 50%">
<div>{{ form.crtim }}</div>
</el-form-item>
<el-form-item label="更新人" style="width: 50%">
<div>{{ form.upuna }}</div>
</el-form-item>
<el-form-item label="更新时间" style="width: 50%">
<div>{{ form.uptim }}</div>
</el-form-item>
</template>
</el-form>
</template>
<template #footer>
<div style="flex: auto; margin: 20px">
<el-button type="primary" @click="save">保 存</el-button>
<el-button @click="state.show = false">关 闭</el-button>
</div>
</template>
</el-drawer>
</template>
@@ -0,0 +1,97 @@
<script setup lang="ts">
import { Page } from '@vben/common-ui';
import { listDelete, listItemDelete, listQuery, listSelect } from '#/utils/page/list';
import DrawerEdit from './edit.vue';
const state = reactive({
url: '/${table.name.replace("_","/")}',
loading: false,
ids: [],
form: {
pageSize: 10,
} as any,
single: true,
multiple: true,
rows: [],
total: 0,
});
const editRef = ref() as any;
const editClose = async () => {
await listQuery(state);
};
onMounted(async () => {
await listQuery(state);
});
</script>
<template>
<Page auto-content-height>
<el-card class="box-card" style="height: 100%" body-style="height: 100%">
<template #header>
<div class="flex justify-between">
<el-space>
<el-input style="width: 180px" v-model="state.form.name" placeholder="输入名称回车查询" clearable @keyup.enter="listQuery(state)" />
<el-button type="primary" @click="listQuery(state)" icon="Search"> 查询</el-button>
</el-space>
<el-space>
<el-button icon="Plus" type="success" plain @click="editRef.open()">新增</el-button>
<el-button icon="Delete" type="danger" plain @click="listDelete(state)" :disabled="state.multiple">删除</el-button>
</el-space>
</div>
</template>
<el-table
@selection-change="listSelect($event, state)"
style="height: calc(100% - 90px)"
:cell-style="{ padding: '2px' }"
:row-style="{ height: '36px' }"
v-loading="state.loading"
:data="state.rows"
border
stripe
>
<el-table-column type="selection" width="44" align="center" />
<el-table-column label="#" type="index" width="50" align="center" />
<el-table-column label="${table.remark}名称">
<template #default="scope">
<span class="link_span" @click="editRef.open({ id: scope.row.id })">{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" prop="crtim" width="164" />
<el-table-column label="创建人" prop="cruna" width="86" align="center" />
<el-table-column label="更新时间" prop="uptim" width="164" />
<el-table-column label="更新人" prop="upuna" width="86" align="center" />
<el-table-column label="备注" prop="notes" />
<el-table-column label="操作" align="center" width="86" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="editRef.open({ id: scope.row.id })" />
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="listItemDelete(state, scope.row.id)" />
</el-tooltip>
</template>
</el-table-column>
</el-table>
<el-pagination
style="margin-top: 10px"
@size-change="listQuery(state)"
@current-change="listQuery(state)"
:pager-count="5"
:page-sizes="[10, 20, 30]"
background
:total="state.total"
v-model:current-page="state.form.pageNum"
v-model:page-size="state.form.pageSize"
layout="total, sizes, prev, pager, next, jumper"
/>
</el-card>
<DrawerEdit ref="editRef" @close="editClose" />
</Page>
</template>
@@ -0,0 +1,59 @@
<script lang="ts" setup>
import { requestClient } from '#/api/request';
import { modalSave } from '#/utils/page/edit';
const emits = defineEmits(['close']);
const state = reactive({
url: '/${table.name.replace("_","/")}',
show: false,
form: {} as any,
});
const formRef = ref();
const { form } = toRefs(state);
const open = async (data: any) => {
state.show = true;
await nextTick();
formRef.value?.resetFields();
state.form = data && data.id ? await requestClient.get(`${state.url}/info/${data.id}`) : { avtag: true };
};
defineExpose({ open });
const save = async () => {
await modalSave({ formRef: formRef.value, state });
emits('close');
};
</script>
<template>
<el-dialog v-model="state.show" title="${table.remark}维护" draggable width="800px">
<el-form ref="formRef" :model="form" label-width="140px" class="zform">
<el-form-item label="${table.remark}名称" prop="name" :rules="[{ required: true, message: '${table.remark}名称不能为空' }]">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="备注" prop="notes">
<el-input v-model="form.notes" :rows="3" type="textarea" />
</el-form-item>
<template v-if="form.crtim">
<el-form-item label="创建人" style="width: 50%">
<div>{{ form.cruna }}</div>
</el-form-item>
<el-form-item label="创建时间" style="width: 50%">
<div>{{ form.crtim }}</div>
</el-form-item>
<el-form-item label="更新人" style="width: 50%">
<div>{{ form.upuna }}</div>
</el-form-item>
<el-form-item label="更新时间" style="width: 50%">
<div>{{ form.uptim }}</div>
</el-form-item>
</template>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="save">保 存</el-button>
<el-button @click="state.show = false">关 闭</el-button>
</span>
</template>
</el-dialog>
</template>
@@ -0,0 +1,97 @@
<script setup lang="ts">
import { Page } from '@vben/common-ui';
import { listDelete, listItemDelete, listQuery, listSelect } from '#/utils/page/list';
import ModalEdit from './edit.vue';
const state = reactive({
url: '/${table.name.replace("_","/")}',
loading: false,
ids: [],
form: {
pageSize: 10,
} as any,
single: true,
multiple: true,
rows: [],
total: 0,
});
const editRef = ref() as any;
const editClose = async () => {
await listQuery(state);
};
onMounted(async () => {
await listQuery(state);
});
</script>
<template>
<Page auto-content-height>
<el-card class="box-card" style="height: 100%" body-style="height: 100%">
<template #header>
<div class="flex justify-between">
<el-space>
<el-input style="width: 180px" v-model="state.form.name" placeholder="输入名称回车查询" clearable @keyup.enter="listQuery(state)" />
<el-button type="primary" @click="listQuery(state)" icon="Search"> 查询</el-button>
</el-space>
<el-space>
<el-button icon="Plus" type="success" plain @click="editRef.open()">新增</el-button>
<el-button icon="Delete" type="danger" plain @click="listDelete(state)" :disabled="state.multiple">删除</el-button>
</el-space>
</div>
</template>
<el-table
@selection-change="listSelect($event, state)"
style="height: calc(100% - 90px)"
:cell-style="{ padding: '2px' }"
:row-style="{ height: '36px' }"
v-loading="state.loading"
:data="state.rows"
border
stripe
>
<el-table-column type="selection" width="44" align="center" />
<el-table-column label="#" type="index" width="50" align="center" />
<el-table-column label="${table.remark}名称">
<template #default="scope">
<span class="link_span" @click="editRef.open({ id: scope.row.id })">{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" prop="crtim" width="164" />
<el-table-column label="创建人" prop="cruna" width="86" align="center" />
<el-table-column label="更新时间" prop="uptim" width="164" />
<el-table-column label="更新人" prop="upuna" width="86" align="center" />
<el-table-column label="备注" prop="notes" />
<el-table-column label="操作" align="center" width="86" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="editRef.open({ id: scope.row.id })" />
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="listItemDelete(state, scope.row.id)" />
</el-tooltip>
</template>
</el-table-column>
</el-table>
<el-pagination
style="margin-top: 10px"
@size-change="listQuery(state)"
@current-change="listQuery(state)"
:pager-count="5"
:page-sizes="[10, 20, 30]"
background
:total="state.total"
v-model:current-page="state.form.pageNum"
v-model:page-size="state.form.pageSize"
layout="total, sizes, prev, pager, next, jumper"
/>
</el-card>
<ModalEdit ref="editRef" @close="editClose" />
</Page>
</template>
@@ -0,0 +1,86 @@
<script lang="ts" setup>
import { Page } from '@vben/common-ui';
import { useTabs } from '@vben/hooks';
import { requestClient } from '#/api/request';
import { tabSave } from '#/utils/page/edit';
const formRef = ref();
const state = reactive({
url: '/${table.name.replace("_","/")}',
show: true,
form: {} as any,
});
const rdata = reactive({} as any);
const { form } = toRefs(state);
const activeName = ref('tab1');
const permTableRef = ref();
const treeProps = reactive({
checkStrictly: true,
});
onMounted(async () => {
const id = useRoute().query?.id;
state.form = id ? await requestClient.get(`${state.url}/info/${id}`) : { avtag: true, type: 1 };
formRef?.value?.clearValidate();
});
const { closeCurrentTab } = useTabs();
const save = async () => {
const back = await tabSave({
formRef: formRef.value,
state,
});
if (back) {
await closeCurrentTab();
}
};
</script>
<template>
<Page auto-content-height>
<el-card class="box-card" style="height: 100%" body-style="height: 100%">
<template #header>
<div class="flex justify-between">
<el-space>${table.remark}维护</el-space>
<el-space>
<el-button type="primary" @click="save">保 存</el-button>
<el-button @click="closeCurrentTab()">关 闭</el-button>
</el-space>
</div>
</template>
<div style="height: calc(100% - 50px); overflow: auto; padding-top: 5px; padding-left: 0; padding-right: 0">
<el-form :inline="true" ref="formRef" :model="form" label-width="140px" class="zform">
<el-tabs type="card" v-model="activeName" style="width: 100%">
<el-tab-pane label="基本信息" name="tab1">
<el-form-item label="${table.remark}名称" prop="name" :rules="[{ required: true, message: '${table.remark}名称不能为空' }]">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="备注" prop="notes">
<el-input v-model="form.notes" :rows="3" type="textarea" />
</el-form-item>
<template v-if="form.crtim">
<el-form-item label="创建人" style="width: 50%">
<div>{{ form.cruna }}</div>
</el-form-item>
<el-form-item label="创建时间" style="width: 50%">
<div>{{ form.crtim }}</div>
</el-form-item>
<el-form-item label="更新人" style="width: 50%">
<div>{{ form.upuna }}</div>
</el-form-item>
<el-form-item label="更新时间" style="width: 50%">
<div>{{ form.uptim }}</div>
</el-form-item>
</template>
</el-tab-pane>
<el-tab-pane label="其他信息" name="tab2">
</el-tab-pane>
</el-tabs>
</el-form>
</div>
</el-card>
</Page>
</template>
@@ -0,0 +1,100 @@
<script setup lang="ts">
import { Page } from '@vben/common-ui';
import { requestClient } from '#/api/request';
import { listDelete, listItemDelete, listQuery, listSelect } from '#/utils/page/list';
const state = reactive({
url: '/${table.name.replace("_","/")}',
loading: false,
ids: [],
form: {
pageSize: 10,
} as any,
single: true,
multiple: true,
rows: [],
total: 0,
});
const router = useRouter();
function handleAdd() {
router.push('${state.url}/edit');
}
function handleEdit(row: any) {
router.push({ path: '${state.url}/edit', query: { id: row.id } });
}
onMounted(async () => {
await listQuery(state);
});
</script>
<template>
<Page auto-content-height>
<el-card class="box-card" style="height: 100%" body-style="height: 100%">
<template #header>
<div class="flex justify-between">
<el-space>
<el-input style="width: 180px" v-model="state.form.name" placeholder="输入名称回车查询" clearable @keyup.enter="listQuery(state)" />
<el-button type="primary" @click="listQuery(state)" icon="Search">查询</el-button>
</el-space>
<el-space>
<el-button icon="Plus" type="success" plain @click="handleAdd">新增</el-button>
<el-button icon="Delete" type="danger" plain @click="listDelete(state)" :disabled="state.multiple">删除</el-button>
</el-space>
</div>
</template>
<el-table
@selection-change="listSelect($event, state)"
style="height: calc(100% - 90px)"
:cell-style="{ padding: '2px' }"
:row-style="{ height: '36px' }"
v-loading="state.loading"
:data="state.rows"
border
stripe
>
<el-table-column type="selection" width="44" align="center" />
<el-table-column label="#" type="index" width="50" align="center" />
<el-table-column label="${table.remark}名称" prop="name" width="250">
<template #default="scope">
<span class="link_span" @click="handleEdit({ id: scope.row.id })">{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" prop="crtim" width="164" />
<el-table-column label="创建人" prop="cruna" width="86" align="center" />
<el-table-column label="更新时间" prop="uptim" width="164" />
<el-table-column label="更新人" prop="upuna" width="86" align="center" />
<el-table-column label="备注" prop="notes" />
<el-table-column label="备注" prop="notes" />
<el-table-column label="操作" align="center" width="86" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleEdit({ id: scope.row.id })" />
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="listItemDelete(state, scope.row.id)" />
</el-tooltip>
</template>
</el-table-column>
</el-table>
<el-pagination
style="margin-top: 10px"
@size-change="listQuery(state)"
@current-change="listQuery(state)"
:pager-count="5"
:page-sizes="[10, 20, 30]"
background
:total="state.total"
v-model:current-page="state.form.pageNum"
v-model:page-size="state.form.pageSize"
layout="total, sizes, prev, pager, next, jumper"
/>
</el-card>
</Page>
</template>
+31
View File
@@ -0,0 +1,31 @@
# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/
FROM bellsoft/liberica-openjdk-rocky:17.0.16-cds
#FROM bellsoft/liberica-openjdk-rocky:21.0.8-cds
#FROM findepi/graalvm:java17-native
LABEL maintainer="baby_fox"
RUN mkdir -p /vben/server/logs \
/vben/server/temp \
/vben/skywalking/agent
WORKDIR /vben/server
ENV SERVER_PORT=8080 SNAIL_PORT=28080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
EXPOSE ${SERVER_PORT}
# 暴露 snail job 客户端端口 用于定时任务调度中心通信
EXPOSE ${SNAIL_PORT}
ADD ./target/vben-jpa.jar ./app.jar
SHELL ["/bin/bash", "-c"]
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \
-Dsnail-job.port=${SNAIL_PORT} \
# 应用名称 如果想区分集群节点监控 改成不同的名称即可
#-Dskywalking.agent.service_name=vben-server \
#-javaagent:/vben/skywalking/agent/skywalking-agent.jar \
-XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \
-jar app.jar
+111
View File
@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>vben-apps</artifactId>
<groupId>com.zsvg</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>vben-jpa</artifactId>
<description>
Jpa示例应用
</description>
<dependencies>
<!-- Mysql驱动包 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- &lt;!&ndash; mp支持的数据库均支持 只需要增加对应的jdbc依赖即可 &ndash;&gt;-->
<!-- &lt;!&ndash; Oracle &ndash;&gt;-->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
</dependency>
<!-- &lt;!&ndash; 兼容oracle低版本 &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.oracle.database.nls</groupId>-->
<!-- <artifactId>orai18n</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; PostgreSql &ndash;&gt;-->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<!-- &lt;!&ndash; SqlServer &ndash;&gt;-->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.zsvg</groupId>
<artifactId>vben-bpm</artifactId>
</dependency>
<dependency>
<groupId>com.zsvg</groupId>
<artifactId>vben-common-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- skywalking 整合 logback -->
<!-- <dependency>-->
<!-- <groupId>org.apache.skywalking</groupId>-->
<!-- <artifactId>apm-toolkit-logback-1.x</artifactId>-->
<!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.apache.skywalking</groupId>-->
<!-- <artifactId>apm-toolkit-trace</artifactId>-->
<!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>-->
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${project.artifactId}</warName>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,18 @@
package vben;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
/**
* web容器中进行部署
*
* @author Lion Li
*/
public class DromaraServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(VbenJpa.class);
}
}
@@ -0,0 +1,22 @@
package vben;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
/**
* 启动程序
*
*/
@SpringBootApplication
public class VbenJpa {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(VbenJpa.class);
application.setApplicationStartup(new BufferingApplicationStartup(2048));
application.run(args);
System.out.println("(♥◠‿◠)ノ゙ Vben Jpa启动成功 ლ(´ڡ`ლ)゙");
}
}
@@ -0,0 +1,22 @@
package vben.jpa.demo.link.cate;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Entity;
import jakarta.persistence.Index;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import vben.common.jpa.entity.BaseCateEntity;
/**
* 关联分类表
*/
@Entity
@Getter
@Setter
@Schema(description = "关联分类表")
@Table(indexes = {@Index(columnList = "cruid"), @Index(columnList = "upuid")})
public class DemoLinkCate extends BaseCateEntity {
}
@@ -0,0 +1,120 @@
package vben.jpa.demo.link.cate;
import cn.dev33.satoken.annotation.SaCheckPermission;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import vben.common.core.domain.R;
import vben.common.idempotent.annotation.RepeatSubmit;
import vben.common.jdbc.dto.Lmove;
import vben.common.jdbc.dto.Ltree;
import vben.common.jdbc.sqler.Sqler;
import vben.common.log.annotation.Log;
import vben.common.log.enums.BusinessType;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 关联分类表案例
*/
@RestController
@RequestMapping("demo/link/cate")
@RequiredArgsConstructor
public class DemoLinkCateController {
private final String table = "demo_link_cate";
/**
* 关联分类表-树状查询
* @param name 案例名称
* @param id 排除的案例ID
* @return 案例树状数据
*/
@GetMapping("tree")
@SaCheckPermission("link:cate:query")
public R<List<Ltree>> getTree(String name, Long id) {
Sqler sqler = new Sqler(table);
List<Ltree> list = service.findTreeList(sqler, name, id);
return R.ok(list);
}
/**
* 关联分类表-列表查询
* @param name 案例名称
* @return 案例列表数据
*/
@GetMapping("list")
@SaCheckPermission("link:cate:query")
public R<List<DemoLinkCate>> getList(String name) {
Sqler sqler = new Sqler(table);
sqler.addLike("t.name", name);
sqler.addSelect("t.notes");
List<DemoLinkCate> list = service.findList(sqler, DemoLinkCate.class);
return R.ok(list);
}
/**
* 关联分类表-详情查询
* @param id 案例ID
* @return 案例对象
*/
@GetMapping("info/{id}")
@SaCheckPermission("link:cate:query")
public R<DemoLinkCate> info(@PathVariable Long id) {
DemoLinkCate cate = service.select(id);
return R.ok(cate);
}
/**
* 关联分类表-新增
* @param cate 案例对象
* @return 案例ID
*/
@PostMapping
@SaCheckPermission("link:cate:add")
@Log(title = "综合树表案例", businessType = BusinessType.INSERT)
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "{repeat.submit.message}")
public R<Long> post(@RequestBody DemoLinkCate cate) {
return R.ok(null, service.insert(cate,table));
}
/**
* 关联分类表-修改
* @param cate 案例对象
* @return 案例ID
*/
@PutMapping
@RepeatSubmit
@SaCheckPermission("link:cate:edit")
@Log(title = "关联分类表案例", businessType = BusinessType.UPDATE)
public R<Long> put(@RequestBody DemoLinkCate cate) {
return R.ok(null, service.update(cate, table));
}
/**
* 关联分类表-删除
* @param ids 案例ID串
* @return 删除的案例数量
*/
@DeleteMapping("{ids}")
@SaCheckPermission("link:cate:remove")
@Log(title = "关联分类表案例", businessType = BusinessType.DELETE)
public R<Integer> delete(@PathVariable Long[] ids) {
return R.ok(service.delete(ids));
}
/**
* 关联分类表-移动
* @param bo 移动对象
*/
@PostMapping("move")
@SaCheckPermission("link:cate:edit")
@Log(title = "关联分类表案例", businessType = BusinessType.OTHER)
public R<Void> move(@RequestBody Lmove bo) {
service.move(bo, table);
return R.ok();
}
private final DemoLinkCateService service;
}
@@ -0,0 +1,8 @@
package vben.jpa.demo.link.cate;
import org.springframework.data.jpa.repository.JpaRepository;
public interface DemoLinkCateRepo extends JpaRepository<DemoLinkCate,Long> {
}
@@ -0,0 +1,21 @@
package vben.jpa.demo.link.cate;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import vben.common.jpa.service.BaseCateService;
@Service
@RequiredArgsConstructor
public class DemoLinkCateService extends BaseCateService<DemoLinkCate> {
private final DemoLinkCateRepo repo;
@PostConstruct
public void initDao() {
super.setRepo(repo);
}
}
@@ -0,0 +1,51 @@
package vben.jpa.demo.link.item;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import lombok.Data;
/**
* 关联子表
*/
@Data
@Entity
@Schema(description = "关联子表")
public class DemoLinkItem {
/**
* 主键ID
*/
@Id
@Schema(description = "主键ID")
@Column(length = 32)
private String id;
/**
* 主表ID
*/
@Schema(description = "主表ID")
private Long maiid;
/**
* 子项目名称
*/
@Column(length = 32)
@Schema(description = "子项目名称")
private String name;
/**
* 排序号
*/
@Schema(description = "排序号")
private Integer ornum;
/**
* 备注
*/
@Schema(description = "备注")
private String notes;
}
@@ -0,0 +1,48 @@
package vben.jpa.demo.link.main;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import vben.common.jpa.entity.BaseMainEntity;
import vben.common.jpa.entity.SysOrg;
import vben.jpa.demo.link.item.DemoLinkItem;
import java.util.ArrayList;
import java.util.List;
/**
* 关联主表
*/
@Entity
@Getter
@Setter
@Schema(description = "关联主表")
@Table(indexes = {@Index(columnList = "cruid"), @Index(columnList = "upuid")})
public class DemoLinkMain extends BaseMainEntity {
/**
* 所属分类ID
*/
@Schema(description = "所属分类ID")
private Long catid;
/**
* 行项目列表(OneToMany示例)
*/
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "maiid")
@OrderBy("ornum ASC")
@Schema(description = "行项目列表")
private List<DemoLinkItem> items = new ArrayList<>();
/**
* 成员列表(ManyToMany示例)
*/
@ManyToMany
@JoinTable(name = "demo_link_main_org", joinColumns = {@JoinColumn(name = "mid")},
inverseJoinColumns = {@JoinColumn(name = "oid")})
@Schema(description = "成员信息")
private List<SysOrg> orgs;
}
@@ -0,0 +1,92 @@
package vben.jpa.demo.link.main;
import cn.dev33.satoken.annotation.SaCheckPermission;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import vben.common.core.domain.R;
import vben.common.idempotent.annotation.RepeatSubmit;
import vben.common.jdbc.dto.PageData;
import vben.common.jdbc.sqler.Sqler;
import vben.common.log.annotation.Log;
import vben.common.log.enums.BusinessType;
import java.util.concurrent.TimeUnit;
/**
* 关联主表案例
*/
@RestController
@RequestMapping("demo/link/main")
@RequiredArgsConstructor
public class DemoLinkMainController {
/**
* 关联主表-分页查询
* @param name XX名称
* @param catid 分类ID
* @return XX分页数据
*/
@SaCheckPermission("link:main:query")
@GetMapping
public R<PageData> get(String name,Long catid) {
Sqler sqler = new Sqler("demo_link_main");
sqler.addLike("t.name", name);
sqler.addSelect("t.notes");
sqler.addEqual("t.catid", catid);
sqler.addLeftJoin("c.name catna","demo_link_cate c","c.id=t.catid");
return R.ok(service.findPageData(sqler));
}
/**
* 关联主表-详情查询
* @param id ID
* @return XX对象
*/
@SaCheckPermission("link:main:query")
@GetMapping("info/{id}")
public R<DemoLinkMain> info(@PathVariable Long id) {
DemoLinkMain main = service.select(id);
return R.ok(main);
}
/**
* 关联主表-新增
* @param main XX对象
* @return ID
*/
@SaCheckPermission("link:main:add")
@Log(title = "关联主表案例", businessType = BusinessType.INSERT)
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "{repeat.submit.message}")
@PostMapping
public R<Long> post(@RequestBody DemoLinkMain main) {
return R.ok(null,service.insert(main));
}
/**
* 关联主表-修改
* @param main XX对象
* @return ID
*/
@SaCheckPermission("link:main:edit")
@Log(title = "关联主表案例", businessType = BusinessType.UPDATE)
@RepeatSubmit
@PutMapping
public R<Long> put(@RequestBody DemoLinkMain main) {
return R.ok(null,service.update(main));
}
/**
* 关联主表-删除
* @param ids ID串
* @return 删除的XX数量
*/
@SaCheckPermission("link:main:remove")
@Log(title = "关联主表案例", businessType = BusinessType.DELETE)
@DeleteMapping("{ids}")
public R<Integer> delete(@PathVariable Long[] ids) {
return R.ok(service.delete(ids));
}
private final DemoLinkMainService service;
}
@@ -0,0 +1,8 @@
package vben.jpa.demo.link.main;
import org.springframework.data.jpa.repository.JpaRepository;
public interface DemoLinkMainRepo extends JpaRepository<DemoLinkMain,Long> {
}
@@ -0,0 +1,21 @@
package vben.jpa.demo.link.main;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import vben.common.jpa.service.BaseMainService;
@Service
@RequiredArgsConstructor
public class DemoLinkMainService extends BaseMainService<DemoLinkMain> {
private final DemoLinkMainRepo repo;
@PostConstruct
public void initDao() {
super.setRepo(repo);
}
}
@@ -0,0 +1,19 @@
package vben.jpa.demo.single.cate;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Entity;
import lombok.Getter;
import lombok.Setter;
import vben.common.jpa.entity.BaseCateEntity;
/**
* 单一树表
*/
@Entity
@Getter
@Setter
@Schema(description = "单一树表")
public class DemoSingleCate extends BaseCateEntity {
}
@@ -0,0 +1,108 @@
package vben.jpa.demo.single.cate;
import cn.dev33.satoken.annotation.SaCheckPermission;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import vben.common.core.domain.R;
import vben.common.idempotent.annotation.RepeatSubmit;
import vben.common.jdbc.dto.Ltree;
import vben.common.jdbc.sqler.Sqler;
import vben.common.log.annotation.Log;
import vben.common.log.enums.BusinessType;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 单一树表案例
*/
@RestController
@RequestMapping("demo/single/cate")
@RequiredArgsConstructor
public class DemoSingleCateController {
private final String table = "demo_single_cate";
/**
* 单一树表-树状查询
* @param name XX名称
* @param id 排除的ID
* @return XX树状数据
*/
@GetMapping("tree")
@SaCheckPermission("single:cate:query")
public R<List<Ltree>> getTree(String name, Long id) {
Sqler sqler = new Sqler(table);
List<Ltree> list = service.findTreeList(sqler, name, id);
return R.ok(list);
}
/**
* 单一树表-列表查询
* @param name XX名称
* @return XX列表数据
*/
@GetMapping("list")
@SaCheckPermission("single:cate:query")
public R<List<DemoSingleCate>> getList(String name) {
Sqler sqler = new Sqler(table);
sqler.addLike("t.name", name);
sqler.addSelect("t.notes");
List<DemoSingleCate> list = service.findList(sqler, DemoSingleCate.class);
return R.ok(list);
}
/**
* 单一树表-详情查询
* @param id ID
* @return XX对象
*/
@SaCheckPermission("single:cate:query")
@GetMapping("info/{id}")
public R<DemoSingleCate> info(@PathVariable Long id) {
DemoSingleCate cate = service.select(id);
return R.ok(cate);
}
/**
* 单一树表-新增
* @param cate XX对象
* @return ID
*/
@PostMapping
@SaCheckPermission("single:cate:add")
@Log(title = "单一树表案例", businessType = BusinessType.INSERT)
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "{repeat.submit.message}")
public R<Long> post(@RequestBody DemoSingleCate cate) {
return R.ok(null, service.insert(cate,table));
}
/**
* 单一树表-修改
* @param cate XX对象
* @return ID
*/
@PutMapping
@RepeatSubmit
@SaCheckPermission("single:cate:edit")
@Log(title = "单一树表案例", businessType = BusinessType.UPDATE)
public R<Long> put(@RequestBody DemoSingleCate cate) {
return R.ok(null, service.update(cate, table));
}
/**
* 单一树表-删除
* @param ids ID串
* @return 删除的XX数量
*/
@DeleteMapping("{ids}")
@RepeatSubmit
@SaCheckPermission("single:cate:delete")
@Log(title = "单一树表案例", businessType = BusinessType.DELETE)
public R<Integer> delete(@PathVariable Long[] ids) {
return R.ok(service.delete(ids));
}
private final DemoSingleCateService service;
}
@@ -0,0 +1,8 @@
package vben.jpa.demo.single.cate;
import org.springframework.data.jpa.repository.JpaRepository;
public interface DemoSingleCateRepo extends JpaRepository<DemoSingleCate,Long> {
}
@@ -0,0 +1,21 @@
package vben.jpa.demo.single.cate;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import vben.common.jpa.service.BaseCateService;
@Service
@RequiredArgsConstructor
public class DemoSingleCateService extends BaseCateService<DemoSingleCate> {
private final DemoSingleCateRepo repo;
@PostConstruct
public void initDao() {
super.setRepo(repo);
}
}
@@ -0,0 +1,18 @@
package vben.jpa.demo.single.main;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Entity;
import lombok.Getter;
import lombok.Setter;
import vben.common.jpa.entity.BaseMainEntity;
/**
* 单一主表
*/
@Entity
@Getter
@Setter
@Schema(description = "单一主表")
public class DemoSingleMain extends BaseMainEntity {
}
@@ -0,0 +1,88 @@
package vben.jpa.demo.single.main;
import cn.dev33.satoken.annotation.SaCheckPermission;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import vben.common.core.domain.R;
import vben.common.idempotent.annotation.RepeatSubmit;
import vben.common.jdbc.dto.PageData;
import vben.common.jdbc.sqler.Sqler;
import vben.common.log.annotation.Log;
import vben.common.log.enums.BusinessType;
/**
* 单一主表案例
*/
@RestController
@RequestMapping("demo/single/main")
@RequiredArgsConstructor
public class DemoSingleMainController {
/**
* 单一主表-分页查询
* @param name XX名称
* @return XX分页数据
*/
@GetMapping
@SaCheckPermission("single:main:query")
public R<PageData> get(String name) {
Sqler sqler = new Sqler("demo_single_main");
sqler.addLike("t.name", name);
sqler.addSelect("t.notes");
return R.ok(service.findPageData(sqler));
}
/**
* 单一主表-详情查询
* @param id ID
* @return XX对象
*/
@GetMapping("info/{id}")
@SaCheckPermission("single:main:query")
public R<DemoSingleMain> info(@PathVariable Long id) {
DemoSingleMain main = service.select(id);
return R.ok(main);
}
/**
* 单一主表-新增
* @param main XX对象
* @return ID
*/
@PostMapping
@SaCheckPermission("single:main:add")
@Log(title = "单一主表案例", businessType = BusinessType.INSERT)
@RepeatSubmit
// @RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "{repeat.submit.message}")
public R<Long> post(@RequestBody DemoSingleMain main) {
return R.ok(null,service.insert(main));
}
/**
* 单一主表-修改
* @param main XX对象
* @return ID
*/
@PutMapping
@RepeatSubmit
@SaCheckPermission("single:main:edit")
@Log(title = "单一主表案例", businessType = BusinessType.UPDATE)
public R<Long> put(@RequestBody DemoSingleMain main) {
return R.ok(null,service.update(main));
}
/**
* 单一主表-删除
* @param ids ID串
* @return 删除的XX数量
*/
@DeleteMapping("{ids}")
@SaCheckPermission("single:main:remove")
@Log(title = "单一主表案例", businessType = BusinessType.DELETE)
public R<Integer> delete(@PathVariable Long[] ids) {
return R.ok(service.delete(ids));
}
private final DemoSingleMainService service;
}
@@ -0,0 +1,8 @@
package vben.jpa.demo.single.main;
import org.springframework.data.jpa.repository.JpaRepository;
public interface DemoSingleMainRepo extends JpaRepository<DemoSingleMain,Long> {
}
@@ -0,0 +1,21 @@
package vben.jpa.demo.single.main;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import vben.common.jpa.service.BaseMainService;
@Service
@RequiredArgsConstructor
public class DemoSingleMainService extends BaseMainService<DemoSingleMain> {
private final DemoSingleMainRepo repo;
@PostConstruct
public void initDao() {
super.setRepo(repo);
}
}
@@ -0,0 +1,248 @@
--- # 监控中心配置
spring.boot.admin.client:
# 增加客户端开关
enabled: false
url: http://localhost:9090/admin
instance:
service-host-type: IP
metadata:
username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@
password: @monitor.password@
--- # snail-job 配置
snail-job:
enabled: false
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group: "vben_group"
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server:
host: 127.0.0.1
port: 17888
# 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段
namespace: ${spring.profiles.active}
# 随主应用端口漂移
port: 2${server.port}
# 客户端ip指定
host:
--- # 数据源配置
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
primary:
#mysql
validationQuery: SELECT 1 FROM DUAL
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://localhost:3306/vben-java?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: root
password: 123456
# validationQuery: SELECT 1 FROM DUAL
# driverClassName: oracle.jdbc.OracleDriver
# jdbcUrl: jdbc:oracle:thin:@localhost:1521:orcl
# username:
# password:
# validationQuery: SELECT 1
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
# jdbcUrl: jdbc:sqlserver://localhost:1433;DatabaseName=vben-java;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
# username:
# password:
# validationQuery: SELECT 1
# driverClassName: org.postgresql.Driver
# jdbcUrl: jdbc:postgresql://localhost:5432/vben-java?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
# username:
# password:
jpa:
entityScan: vben
hbm2ddl:
auto: update
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring.data:
redis:
# 地址
host: localhost
# 端口,默认为6379
port: 6379
# 数据库索引
database: 0
# redis 密码必须配置
# password: vben
# 连接超时时间
timeout: 10s
# 是否开启ssl
ssl.enabled: false
# redisson 配置
redisson:
# redis key前缀
keyPrefix:
# 线程池数量
threads: 4
# Netty线程池数量
nettyThreads: 8
# 单节点配置
singleServerConfig:
# 客户端名称 不能用中文
clientName: vben-admin
# 最小空闲连接数
connectionMinimumIdleSize: 8
# 连接池大小
connectionPoolSize: 32
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
--- # mail 邮件发送
mail:
enabled: false
host: smtp.163.com
port: 465
# 是否需要用户名密码验证
auth: true
# 发送方,遵循RFC-822标准
from: xxx@163.com
# 用户名(注意:如果使用foxmail邮箱,此处user为qq号)
user: xxx@163.com
# 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助)
pass: xxxxxxxxxx
# 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。
starttlsEnable: true
# 使用SSL安全连接
sslEnable: true
# SMTP超时时长,单位毫秒,缺省值不超时
timeout: 0
# Socket连接超时值,单位毫秒,缺省值不超时
connectionTimeout: 0
--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用
sms:
# 配置源类型用于标定配置来源(interface,yaml)
config-type: yaml
# 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制
restricted: true
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
minute-max: 1
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
account-max: 30
# 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中
blends:
# 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可
# 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户
config1:
# 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: alibaba
# 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。
access-key-id: 您的accessKey
# 称为accessSecret有些称之为apiSecret
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
config2:
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: tencent
access-key-id: 您的accessKey
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
--- # 三方授权
justauth:
# 前端外网访问地址
address: http://localhost:5666
type:
maxkey:
# maxkey 服务器地址
# 注意 如下均配置均不需要修改 maxkey 已经内置好了数据
server-url: http://sso.maxkey.top
client-id: 876892492581044224
client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
redirect-uri: ${justauth.address}/social-callback?source=maxkey
topiam:
# topiam 服务器地址
server-url: http://127.0.0.1:1898/api/v1/authorize/y0q************spq***********8ol
client-id: 449c4*********937************759
client-secret: ac7***********1e0************28d
redirect-uri: ${justauth.address}/social-callback?source=topiam
scopes: [openid, email, phone, profile]
qq:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=qq
union-id: false
weibo:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=weibo
gitee:
client-id: d46cb33b700cc826680192caa8eda499235a766a96f8a06c16f5ae3da74ce55a
client-secret: 680c9d423de5e264f465b9d9741e79a0363020889abcdfa933993a5d140d95b3
redirect-uri: ${justauth.address}/#/social-callback?source=gitee
dingtalk:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=dingtalk
baidu:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=baidu
csdn:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=csdn
coding:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=coding
coding-group-name: xx
oschina:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=oschina
alipay_wallet:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet
alipay-public-key: MIIB**************DAQAB
wechat_open:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_open
wechat_mp:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
wechat_enterprise:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
agent-id: 1000002
gitlab:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab
gitea:
# 前端改动 https://gitee.com/JavaLionLi/plus-ui/pulls/204
# gitea 服务器地址
server-url: https://demo.gitea.com
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitea
--- # 其他设置
#app:
#附件地址,不设置而时默认为项目根目录下的/zsvg/atts
# attpath: C:/vben/att
@@ -0,0 +1,229 @@
--- # 监控中心配置
spring.boot.admin.client:
# 增加客户端开关
enabled: false
url: http://localhost:9090/admin
instance:
service-host-type: IP
metadata:
username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@
password: @monitor.password@
--- # snail-job 配置
snail-job:
enabled: false
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group: "vben_group"
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server:
host: 127.0.0.1
port: 17888
# 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段
namespace: ${spring.profiles.active}
# 随主应用端口漂移
port: 2${server.port}
# 客户端ip指定
host:
--- # 数据源配置
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
primary:
validationQuery: SELECT 1 FROM DUAL
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://localhost:3306/vben-java?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: root
password: 123456
jpa:
entityScan: vben
hbm2ddl:
auto: update
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring.data:
redis:
# 地址
host: localhost
# 端口,默认为6379
port: 6379
# 数据库索引
database: 0
# redis 密码必须配置
# password: vben
# 连接超时时间
timeout: 10s
# 是否开启ssl
ssl.enabled: false
# redisson 配置
redisson:
# redis key前缀
keyPrefix:
# 线程池数量
threads: 4
# Netty线程池数量
nettyThreads: 8
# 单节点配置
singleServerConfig:
# 客户端名称 不能用中文
clientName: vben-admin
# 最小空闲连接数
connectionMinimumIdleSize: 8
# 连接池大小
connectionPoolSize: 32
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
--- # mail 邮件发送
mail:
enabled: false
host: smtp.163.com
port: 465
# 是否需要用户名密码验证
auth: true
# 发送方,遵循RFC-822标准
from: xxx@163.com
# 用户名(注意:如果使用foxmail邮箱,此处user为qq号)
user: xxx@163.com
# 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助)
pass: xxxxxxxxxx
# 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。
starttlsEnable: true
# 使用SSL安全连接
sslEnable: true
# SMTP超时时长,单位毫秒,缺省值不超时
timeout: 0
# Socket连接超时值,单位毫秒,缺省值不超时
connectionTimeout: 0
--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用
sms:
# 配置源类型用于标定配置来源(interface,yaml)
config-type: yaml
# 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制
restricted: true
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
minute-max: 1
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
account-max: 30
# 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中
blends:
# 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可
# 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户
config1:
# 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: alibaba
# 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。
access-key-id: 您的accessKey
# 称为accessSecret有些称之为apiSecret
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
config2:
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: tencent
access-key-id: 您的accessKey
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
--- # 三方授权
justauth:
# 前端外网访问地址
address: http://localhost:5666
type:
maxkey:
# maxkey 服务器地址
# 注意 如下均配置均不需要修改 maxkey 已经内置好了数据
server-url: http://sso.maxkey.top
client-id: 876892492581044224
client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
redirect-uri: ${justauth.address}/social-callback?source=maxkey
topiam:
# topiam 服务器地址
server-url: http://127.0.0.1:1898/api/v1/authorize/y0q************spq***********8ol
client-id: 449c4*********937************759
client-secret: ac7***********1e0************28d
redirect-uri: ${justauth.address}/social-callback?source=topiam
scopes: [openid, email, phone, profile]
qq:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=qq
union-id: false
weibo:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=weibo
gitee:
client-id: d46cb33b700cc826680192caa8eda499235a766a96f8a06c16f5ae3da74ce55a
client-secret: 680c9d423de5e264f465b9d9741e79a0363020889abcdfa933993a5d140d95b3
redirect-uri: ${justauth.address}/#/social-callback?source=gitee
dingtalk:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=dingtalk
baidu:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=baidu
csdn:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=csdn
coding:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=coding
coding-group-name: xx
oschina:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=oschina
alipay_wallet:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet
alipay-public-key: MIIB**************DAQAB
wechat_open:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_open
wechat_mp:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
wechat_enterprise:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
agent-id: 1000002
gitlab:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab
gitea:
# 前端改动 https://gitee.com/JavaLionLi/plus-ui/pulls/204
# gitea 服务器地址
server-url: https://demo.gitea.com
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitea
--- # 其他设置
app:
# 前端外网访问地址
# attpath: C:/vben/att
# attpath: /home/app/att
@@ -0,0 +1,267 @@
# 开发环境配置
server:
# 服务器的HTTP端口,默认为8080
port: 8080
servlet:
# 应用的访问路径
context-path: /
# undertow 配置
undertow:
# HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的
max-http-post-size: -1
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
# 每块buffer的空间大小,越小的空间被利用越充分
buffer-size: 512
# 是否分配的直接内存
direct-buffers: true
threads:
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
io: 8
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
worker: 256
captcha:
# 是否启用验证码校验
enable: true
# 验证码类型 math 数组计算 char 字符验证
type: MATH
# line 线段干扰 circle 圆圈干扰 shear 扭曲干扰
category: CIRCLE
# 数字验证码位数
numberLength: 1
# 字符验证码长度
charLength: 4
# 日志配置
logging:
level:
vben: @logging.level@
org.springframework: warn
org.mybatis.spring.mapper: error
org.apache.fury: warn
config: classpath:logback.xml
# 用户配置
user:
password:
# 密码最大错误次数
maxRetryCount: 5
# 密码锁定时间(默认10分钟)
lockTime: 10
# Spring配置
spring:
application:
name: vben-admin
threads:
# 开启虚拟线程 仅jdk21可用
virtual:
enabled: true
task:
execution:
# 从 springboot 3.5 开始 spring自带线程池
# 不再需要 AsyncConfig与ThreadPoolConfig 可直接注入线程池使用
thread-name-prefix: async-
# 由spring自己初始化线程池
mode: force
# 资源信息
messages:
# 国际化资源文件路径
basename: i18n/messages
profiles:
active: @profiles.active@
# 文件上传
servlet:
multipart:
# 单个文件大小
max-file-size: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
mvc:
# 设置静态资源路径 防止所有请求都去查静态资源
static-path-pattern: /static/**
format:
date-time: yyyy-MM-dd HH:mm:ss
jackson:
# 日期格式化
date-format: yyyy-MM-dd HH:mm:ss
serialization:
# 格式化输出
indent_output: false
# 忽略无法转换的对象
fail_on_empty_beans: false
deserialization:
# 允许对象忽略json中不存在的属性
fail_on_unknown_properties: false
# Sa-Token配置
sa-token:
# token名称 (同时也是cookie名称)
token-name: Authorization
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
is-share: false
# jwt秘钥
jwt-secret-key: abcdefghijklmnopqrstuvwxyz
# security配置
security:
# 排除路径
excludes:
- /*.html
- /**/*.html
- /**/*.css
- /**/*.js
- /favicon.ico
- /error
- /*/api-docs
- /*/api-docs/**
- /warm-flow-ui/config
# 多租户配置
tenant:
# 是否开启
enable: true
# 排除表
excludes:
- sys_menu
- sys_tenant
- sys_tenant_package
- sys_role_dept
- sys_role_menu
- sys_user_post
- sys_user_role
- sys_client
- sys_oss_config
- flow_spel
# MyBatisPlus配置
# https://baomidou.com/config/
mybatis-plus:
# 自定义配置 是否全局开启逻辑删除 关闭后 所有逻辑删除功能将失效
enableLogicDelete: true
# 多包名使用 例如 vben.**.mapper,org.xxx.**.mapper
mapperPackage: vben.**.mapper
# 对应的 XML 文件位置
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: vben.**.domain
global-config:
dbConfig:
# 主键类型
# AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
# 如需改为自增 需要将数据库表全部设置为自增
idType: ASSIGN_ID
# 数据加密
mybatis-encryptor:
# 是否开启加密
enable: false
# 默认加密算法
algorithm: BASE64
# 编码方式 BASE64/HEX。默认BASE64
encode: BASE64
# 安全秘钥 对称算法的秘钥 如:AES,SM4
password:
# 公私钥 非对称算法的公私钥 如:SM2,RSA
publicKey:
privateKey:
# api接口加密
api-decrypt:
# 是否开启全局接口加密
enabled: true
# AES 加密头标识
headerFlag: encrypt-key
# 响应加密公钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换
# 对应前端解密私钥 MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJnNwrj4hi/y3CCJu868ghCG5dUj8wZK++RNlTLcXoMmdZWEQ/u02RgD5LyLAXGjLOjbMtC+/J9qofpSGTKSx/MCAwEAAQ==
# 请求解密私钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换
# 对应前端加密公钥 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y=
springdoc:
api-docs:
# 是否开启接口文档
enabled: true
info:
# 标题
title: '标题:vben-admin后台管理系统_接口文档'
# 描述
description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...'
# 版本
version: '版本号: ${project.version}'
# 作者信息
contact:
name: baby_fox
email: 676948472@qq.com
url: https://gitee.com/vben/vben-java
#这里定义了两个分组,可定义多个,也可以不定义
group-configs:
- group: 1.自定义应用
packages-to-scan: vben.admin
- group: 2.系统管理
packages-to-scan: vben.base.sys
- group: 3.监控中心
packages-to-scan: vben.base.mon
- group: 4.辅助工具
packages-to-scan: vben.base.tool
- group: 5.工作流
packages-to-scan: vben.bpm
# 防止XSS攻击
xss:
# 过滤开关
enabled: true
# 排除链接
excludeUrls:
- /system/notice
- /oa/flow/tmpl
- /bpm/bus/tmpl
--- # 分布式锁 lock4j 全局配置
lock4j:
# 获取分布式锁超时时间,默认为 3000 毫秒
acquire-timeout: 3000
# 分布式锁的超时时间,默认为 30 秒
expire: 30000
--- # Actuator 监控端点的配置项
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: ALWAYS
logfile:
external-file: ./logs/sys-console.log
--- # 默认/推荐使用sse推送
sse:
enabled: true
path: /resource/sse
--- # websocket
websocket:
# 如果关闭 需要和前端开关一起关闭
enabled: false
# 路径
path: /resource/websocket
# 设置访问源地址
allowedOrigins: '*'
--- # warm-flow工作流配置
warm-flow:
# 是否开启工作流,默认true
enabled: true
# 是否开启设计器ui
ui: true
# 是否显示流程图顶部文字
top-text-show: true
# 是否渲染节点悬浮提示,默认true
node-tooltip: true
# 默认Authorization,如果有多个token,用逗号分隔
token-name: ${sa-token.token-name},clientid
@@ -0,0 +1,14 @@
Application Version: ${revision}
Spring Boot Version: ${spring-boot.version}
8b d8 88 88
`8b d8' 88 88
`8b d8' 88 88
`8b d8' 88,dPPYba, ,adPPYba, 8b,dPPYba, 88 8b,dPPYba, ,adPPYYba,
`8b d8' 88P' "8a a8P_____88 88P' `"8a 88 88P' "8a "" `Y8
`8b d8' 88 d8 8PP""""""" 88 88 88 88 d8 ,adPPPPP88
`888' 88b, ,a8" "8b, ,aa 88 88 88, ,d88 88b, ,a8" 88, ,88
`8' 8Y"Ybbd8"' `"Ybbd8"' 88 88 "Y8888P" 88`YbbdP"' `"8bbdP"Y8
88
88
@@ -0,0 +1,10 @@
# 代码生成
gen:
# 作者
author: zsvg
# 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
packageName: com.zsvg.system
# 自动去除表前缀,默认是false
autoRemovePre: false
# 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
tablePrefix: sys_
@@ -0,0 +1,62 @@
#错误消息
not.null=* 必须填写
user.jcaptcha.error=验证码错误
user.jcaptcha.expire=验证码已失效
user.not.exists=对不起, 您的账号:{0} 不存在.
user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
user.password.delete=对不起,您的账号:{0} 已被删除
user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员
role.blocked=角色已封禁,请联系管理员
user.logout.success=退出成功
length.not.valid=长度必须在{min}到{max}个字符之间
user.username.not.blank=用户名不能为空
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
user.username.length.valid=账户长度必须在{min}到{max}个字符之间
user.password.not.blank=用户密码不能为空
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
user.password.not.valid=* 5-50个字符
user.password.format.valid=密码必须包含大写字母、小写字母、数字和特殊字符
user.email.not.valid=邮箱格式错误
user.email.not.blank=邮箱不能为空
user.phonenumber.not.blank=用户手机号不能为空
user.mobile.phone.number.not.valid=手机号格式错误
user.login.success=登录成功
user.register.success=注册成功
user.register.save.error=保存用户 {0} 失败,注册账号已存在
user.register.error=注册失败,请联系系统管理人员
user.notfound=请重新登录
user.forcelogout=管理员强制退出,请重新登录
user.unknown.error=未知错误,请重新登录
auth.grant.type.error=认证权限类型错误
auth.grant.type.blocked=认证权限类型已禁用
auth.grant.type.not.blank=认证权限类型不能为空
auth.clientid.not.blank=认证客户端id不能为空
##文件上传消息
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
upload.filename.exceed.length=上传的文件名最长{0}个字符
##权限
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
repeat.submit.message=不允许重复提交,请稍候再试
rate.limiter.message=访问过于频繁,请稍候再试
sms.code.not.blank=短信验证码不能为空
sms.code.retry.limit.count=短信验证码输入错误{0}次
sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟
email.code.not.blank=邮箱验证码不能为空
email.code.retry.limit.count=邮箱验证码输入错误{0}次
email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟
xcx.code.not.blank=小程序[code]不能为空
social.source.not.blank=第三方登录平台[source]不能为空
social.code.not.blank=第三方登录平台[code]不能为空
social.state.not.blank=第三方登录平台[state]不能为空
##租户
tenant.number.not.blank=租户编号不能为空
tenant.not.exists=对不起, 您的租户不存在,请联系管理员
tenant.blocked=对不起,您的租户已禁用,请联系管理员
tenant.expired=对不起,您的租户已过期,请联系管理员
@@ -0,0 +1,62 @@
#错误消息
not.null=* Required fill in
user.jcaptcha.error=Captcha error
user.jcaptcha.expire=Captcha invalid
user.not.exists=Sorry, your account: {0} does not exist
user.password.not.match=User does not exist/Password error
user.password.retry.limit.count=Password input error {0} times
user.password.retry.limit.exceed=Password input error {0} times, account locked for {1} minutes
user.password.delete=Sorry, your account:{0} has been deleted
user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator
role.blocked=Role disabled,please contact administrators
user.logout.success=Exit successful
length.not.valid=The length must be between {min} and {max} characters
user.username.not.blank=Username cannot be blank
user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number
user.username.length.valid=Account length must be between {min} and {max} characters
user.password.not.blank=Password cannot be empty
user.password.length.valid=Password length must be between {min} and {max} characters
user.password.not.valid=* 5-50 characters
user.password.format.valid=Password must contain uppercase, lowercase, digit, and special character
user.email.not.valid=Mailbox format error
user.email.not.blank=Mailbox cannot be blank
user.phonenumber.not.blank=Phone number cannot be blank
user.mobile.phone.number.not.valid=Phone number format error
user.login.success=Login successful
user.register.success=Register successful
user.register.save.error=Failed to save user {0}, The registered account already exists
user.register.error=Register failed, please contact system administrator
user.notfound=Please login again
user.forcelogout=The administrator is forced to exit,please login again
user.unknown.error=Unknown error, please login again
auth.grant.type.error=Auth grant type error
auth.grant.type.blocked=Auth grant type disabled
auth.grant.type.not.blank=Auth grant type cannot be blank
auth.clientid.not.blank=Auth clientid cannot be blank
##文件上传消息
upload.exceed.maxSize=The uploaded file size exceeds the limit file size!<br/>the maximum allowed file size is:{0}MB!
upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters
##权限
no.permission=You do not have permission to the data,please contact your administrator to add permissions [{0}]
no.create.permission=You do not have permission to create data,please contact your administrator to add permissions [{0}]
no.update.permission=You do not have permission to modify data,please contact your administrator to add permissions [{0}]
no.delete.permission=You do not have permission to delete data,please contact your administrator to add permissions [{0}]
no.export.permission=You do not have permission to export data,please contact your administrator to add permissions [{0}]
no.view.permission=You do not have permission to view data,please contact your administrator to add permissions [{0}]
repeat.submit.message=Repeat submit is not allowed, please try again later
rate.limiter.message=Visit too frequently, please try again later
sms.code.not.blank=Sms code cannot be blank
sms.code.retry.limit.count=Sms code input error {0} times
sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes
email.code.not.blank=Email code cannot be blank
email.code.retry.limit.count=Email code input error {0} times
email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes
xcx.code.not.blank=Mini program [code] cannot be blank
social.source.not.blank=Social login platform [source] cannot be blank
social.code.not.blank=Social login platform [code] cannot be blank
social.state.not.blank=Social login platform [state] cannot be blank
##租户
tenant.number.not.blank=Tenant number cannot be blank
tenant.not.exists=Sorry, your tenant does not exist. Please contact the administrator
tenant.blocked=Sorry, your tenant is disabled. Please contact the administrator
tenant.expired=Sorry, your tenant has expired. Please contact the administrator.

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