commit 2d6310f3ae62f0564c873193f2699fc72bebef99 Author: luoyu Date: Mon Jun 2 21:30:55 2025 +0800 boyuehasfj-java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3d92e2e --- /dev/null +++ b/.gitignore @@ -0,0 +1,50 @@ +###################################################################### +# Build Tools + +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +target/ +!.mvn/wrapper/maven-wrapper.jar + +###################################################################### +# IDE + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### JRebel ### +rebel.xml + +### NetBeans ### +nbproject/private/ +build/* +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ + +###################################################################### +# Others +*.log +*.xml.versionsBackup +*.swp +*.lck + +!*/build/*.java +!*/build/*.html +!*/build/*.xml + +effective-pom.xml \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..37717e7 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "boyueApplication", + "request": "launch", + "mainClass": "com.boyue.boyueApplication", + "projectName": "boyue-admin" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..38674ba --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,68 @@ +{ + "java.configuration.updateBuildConfiguration": "interactive", + "java.compile.nullAnalysis.mode": "disabled", + "maven.view": "hierarchical", + "maven.executable.options": "-T 4", + "maven.pomfile.autoUpdateEffectivePOM": true, + "java.debug.settings.hotCodeReplace": "auto", + "spring-boot.ls.java.home": "", + "java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=9 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx4G -Xms4G -Xlog:disable", + "maven.excludedFolders": [ + "**/.vscode", + "**/.idea", + "**/target", + "**/.*", + "**/node_modules", + "**/target", + "**/bin", + "**/archetype-resources" + ], + "boot-java.rewrite.refactorings.on": true, + "maven.executable.preferMavenWrapper": true, + "java.import.maven.enabled": true, + "java.dependency.packagePresentation": "hierarchical", + "dbcode.connections": [ + { + "connectionId": "btr-_nFe7R0oOvCj0mMun", + "name": "ry-mysql", + "driver": "mysql", + "connectionType": "host", + "host": "127.0.0.1", + "port": 3306, + "ssl": false, + "username": "root", + "password": "123456", + "savePassword": "secretStorage", + "database": "ry", + "connectionTimeout": 30, + "driverOptions": { + "retrievePublickey": true + } + }, + { + "connectionId": "7NX2UhXl__9t3Ca6TzEsB", + "name": "ry-postgres", + "driver": "postgres", + "connectionType": "host", + "host": "127.0.0.1", + "port": 5432, + "ssl": false, + "username": "postgres", + "password": "123456", + "savePassword": "secretStorage", + "connectionTimeout": 30 + }, + { + "connectionId": "fNsY4HlOb21w_5TnIGy_d", + "name": "localhost", + "driver": "redis", + "connectionType": "host", + "host": "127.0.0.1", + "port": 6379, + "ssl": false, + "savePassword": "na", + "readOnly": false, + "connectionTimeout": 30 + } + ], +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..54416f5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2018 boyue + +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. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..53d511e --- /dev/null +++ b/README.md @@ -0,0 +1,214 @@ +

+ + logo + + + + + logo + +

+

boyue-Geek v3.8.9-G

+

基于SpringBoot3+Vue3前后端分离的Java快速开发框架

+

+ +

+ +# 当前版本是3.8.9-G + +本人的其他两个推荐搭配的项目 + +1. [boyue-App-Geek: 这是若依极客生态的小程序版本 (gitee.com)](https://gitee.com/geek-xd/geek-uniapp-vue3-uview-plus-uchart) +2. [boyue-Vue3-Geek: 这是若依极客生态的Vue3版本 (gitee.com)](https://gitee.com/geek-xd/ruo-yi-vue3-geek) + +与本项目同为一个作者开发,兼容性最好,学习成本最低。 + +# 引言 + +boyue-Vue与boyue-App是基于SpringBoot2+Vue2打造的企业级开发框架,得到了广大开发者的喜爱和积极反馈。随着技术的迭代进步,SpringBoot3与Vue3逐渐进入开发者的视野。为了满足开发者对于新技术的追求,boyue官方文档提供了SpringBoot2至SpringBoot3的升级方法。与此同时,社区也涌现出了boyue-Vue3、boyue-App-Vue3的版本,展现了开发者社区对于技术升级的热情与努力。 + +然而,在升级的过程中,官方的方法为了兼顾Java1.8的特性与一些老旧的方法,未完全拥抱SpringBoot3与Java17的全部特性。而社区的boyue-Vue3、boyue-App-Vue3版本由于出自不同的团队之手,兼容性及整合性上存在些许不足。更为关键的是,尽管这些版本支持TypeScript,但缺乏与之相匹配的tsconfig.json配置文件,这使得在主流编辑器如VSCode中,TypeScript的语法提示环境并未达到最佳状态。 + +鉴于此,boyue-Geek生态应运而生。它旨在为广大开发者提供一个既保留原版本核心特性,又整合社区版优点的全新解决方案。在boyue-Geek中,我们深入调研了企业开发中常用的boyue扩展,并直接在框架中集成,确保开发者能够快速上手,高效开发。同时,我们采用了最新的SpringBoot3+Vue3技术栈,彻底移除了为了兼容Java1.8而保留的老旧方法。更为重要的是,我们为TypeScript开发环境加入了常用的tsconfig.json配置,使得开发者在VSCode等编辑器中能够获得更为舒适、便捷的语法提示体验。 + +boyue-Geek不仅仅是一个简单的升级版本,更是对于boyue生态的一次全面优化与整合。我们相信,通过boyue-Geek,开发者将能够更为高效、愉悦地开发出优秀的企业级应用。 + +## 平台简介 + +若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。 + +* 前端采用Vue3、Element Plus。 +* 后端采用Spring Boot3、Spring Security、Redis & Jwt。 +* 权限认证使用Jwt,支持多终端认证系统。 +* 支持加载动态权限菜单,多方式轻松权限控制。 +* 高效率开发,使用代码生成器可以一键生成前后端代码。 +* 多数据源与分库分表默认集成 +* 所有非基本模块可随意插拔,让开发更加简单高效 +* 提供了多个工具模块助力开发,如:在线接口模块、mybatis-jpa模块 +* 提供了多个常见业务模块简化开发,如:第三方认证模块、支付模块 +* 提供了多个常见的服务模块集成开发,如:websocket模块、minio模块 +* 特别鸣谢:[element](https://github.com/ElemeFE/element),[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin),[eladmin-web](https://github.com/elunez/eladmin-web)。 +* 阿里云折扣场:[点我进入](http://aly.boyue.vip),腾讯云秒杀场:[点我进入](http://txy.boyue.vip)   +* 阿里云优惠券:[点我领取](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link),腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)   + +## 本项目与原项目的区别 + +### 核心 + +**模块化架构设计,支持各个模块的快速安拆,对第三方认证、第三方支付模块设计了基础的规范和基础模块。** + +### 细节 + +1. 改用SpringBoot3+java17的更新的技术栈并改掉所有的弃用的方法,全面拥抱java17的全新特性。 +2. 升级了代码生成器(配合本项目的vue3版本才可用),使关联表生成更加简单! +3. 改用最新版本的SpringSecurity安全框架,以及采用最新的lambda 表达式的配置方式,更加通俗易懂! +4. 自动Api文档以springfox替代springdoc来适配knife4j框架的4.x版本,更好的适配springboot3! +5. 默认引入mybatis-plus增强mybatis,并自创工具模块mybatis-jpa简化CRUD! +6. 默认引入lombok简化代码(注:基础模块并未使用mybatis-plus和lombok,对这两个扩展有争议的小伙伴可以直接删除,不会影响到框架本身滴,以及knife4j直接删除也不会影响到springdoc,主要还是为了方便咱们开发者呢!) +7. 提供了大量可随意插拔的模块,助力快速开发!同时boyue插件集成中的常用插件也以模块的形式直接集成在了项目中,也是可以随意插拔的嗷~ + +## 模块介绍(简单开发必看) + +* 最简单的开发就是删除所有的可移除模块,按需添加模块。 +* 测试中的模块请自己使用的时候一定要测试一下。 +* 对于小白,开发中的模块请直接删除。 + +``` + + +com.boyue +├── common // 工具类 +│ └── annotation // 自定义注解 +│ └── config // 全局配置 +│ └── constant // 通用常量 +│ └── core // 核心控制 +│ └── enums // 通用枚举 +│ └── exception // 通用异常 +│ └── filter // 过滤器处理 +│ └── utils // 通用类处理 +├── framework // 框架核心 +│ └── aspectj // 注解实现 +│ └── config // 系统配置 +│ └── datasource // 数据权限 +│ └── interceptor // 拦截器 +│ └── manager // 异步处理 +│ └── security // 权限控制 +│ └── web // 前端控制 +├── boyue-admin // 后台服务 +├── boyue-pay // 支付场景(开发中) +│ └── common // 支付框架基础模块(测试中) +│ └── sqb // 收钱吧支付模块(测试中) +│ └── wx // 微信支付模块(待开发) +│ └── alipay // 支付宝支付模块(开发中) +│ └── starter // 支付场景启动器 +├── boyue-oauth // 第三方认证场景(测试中) +│ └── common // 第三方认证基础模块(开发中) +│ └── justauth // 网站第三方认证模块(测试中,参照若依扩展改进,因没有这么多场景的code,请大家测试出问题后help解决一下发出来) +│ └── wx // 微信小程序认证模块(测试中) +│ └── phone // 手机认证模块(测试中) +│ └── email // 邮箱认证模块(开发中) +│ └── starter // 第三方认证启动器 +├── boyue-middleware // 中间件场景(可移除) +│ └── minio // minio文件服务模块 +│ └── rabbitmq // rabbitmq队列服务模块 +│ └── redis // redis缓存服务模块(与ehcache插件同类,两者二选一) +│ └── starter // 中间件整合模块 +├── boyue-models // 业务场景 +│ └── online // 在线开发模块(可移除) +│ └── quartz // 定时任务(可移除) +│ └── generator // 代码生成(可移除) +│ └── starter // 业务场景启动器 +├── boyue-plugins // 插件 +│ └── ehcache // ehcache缓存插件(与redis模块同类,两者二选一) +│ └── mybatis-jpa // mybatis-jpa插件(可移除)(简化CRUD,以数据模型为基础开发) +│ └── mybatis-plus // mybatis-plus插件(可移除)(简化CRUD) +│ └── mybatis-interceptor // mybatis-interceptor插件(可移除)(简化数据鉴权和分页,扩展性强) +│ └── atomikos // atomikos分布式事务插件(可移除) +│ └── netty // netty插件(可移除) +│ └── websocket // websocket插件(可移除) +│ └── starter // 插件整合模块 +├── boyue-system // 系统代码 +``` + +## 内置功能 + +1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 +2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 +3. 岗位管理:配置系统用户所属担任职务。 +4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 +5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 +6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。 +7. 参数管理:对系统动态配置常用参数。 +8. 通知公告:系统通知公告信息发布维护。 +9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 +10. 登录日志:系统登录日志记录查询包含登录异常。 +11. 在线用户:当前系统中活跃用户状态监控。 +12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 +13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。 +14. 系统接口:根据业务代码自动生成相关的api接口文档。 +15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。 +16. 缓存监控:对系统的缓存信息查询,命令统计等。 +17. 在线构建器:拖动表单元素生成相应的HTML代码。 +18. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 +19. 支付场景 +20. 第三方登录场景 +21. 中间件场景 + +## 演示图 + +### 新加功能和增强功能演示 + + + + + + + + + + + + + + +
+ +### 原有功能演示 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +# 联系我们: + +QQ交流群:744785891 diff --git a/bin/clean.bat b/bin/clean.bat new file mode 100644 index 0000000..24c0974 --- /dev/null +++ b/bin/clean.bat @@ -0,0 +1,12 @@ +@echo off +echo. +echo [Ϣ] target· +echo. + +%~d0 +cd %~dp0 + +cd .. +call mvn clean + +pause \ No newline at end of file diff --git a/bin/package.bat b/bin/package.bat new file mode 100644 index 0000000..c693ec0 --- /dev/null +++ b/bin/package.bat @@ -0,0 +1,12 @@ +@echo off +echo. +echo [Ϣ] Weḅwar/jarļ +echo. + +%~d0 +cd %~dp0 + +cd .. +call mvn clean package -Dmaven.test.skip=true + +pause \ No newline at end of file diff --git a/bin/run.bat b/bin/run.bat new file mode 100644 index 0000000..d15561d --- /dev/null +++ b/bin/run.bat @@ -0,0 +1,14 @@ +@echo off +echo. +echo [��Ϣ] ʹ��Jar��������Web���̡� +echo. + +cd %~dp0 +cd ../boyue-admin/target + +set JAVA_OPTS=-Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m + +java -jar %JAVA_OPTS% boyue-admin.jar + +cd bin +pause \ No newline at end of file diff --git a/boyue-admin/pom.xml b/boyue-admin/pom.xml new file mode 100644 index 0000000..1850d38 --- /dev/null +++ b/boyue-admin/pom.xml @@ -0,0 +1,118 @@ + + + + boyuehasfj-java + com.boyue + 3.8.9-G + + 4.0.0 + jar + boyue-admin + + + web服务入口 + + + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + org.springframework.boot + spring-boot-devtools + true + + + + + com.mysql + mysql-connector-j + + + + org.postgresql + postgresql + + + + + com.boyue + boyue-framework + + + + + com.boyue + boyue-auth-starter + + + + + com.boyue + boyue-pay-starter + + + + + com.boyue + boyue-middleware-starter + + + + + com.boyue + boyue-plugins-starter + + + + + com.boyue + boyue-models-starter + + + + + com.boyue + boyue-file-starter + + + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.1.0 + + false + ${project.artifactId} + + + + ${project.artifactId} + + + \ No newline at end of file diff --git a/boyue-admin/src/main/java/com/boyue/BoYueApplication.java b/boyue-admin/src/main/java/com/boyue/BoYueApplication.java new file mode 100644 index 0000000..84c908a --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/BoYueApplication.java @@ -0,0 +1,43 @@ +package com.boyue; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.Environment; + +/** + * 启动程序 + * + * @author boyue + */ +@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }, + excludeName = { + // 排除Flowable自动配置 + "org.flowable.spring.boot.process.ProcessEngineAutoConfiguration", + "org.flowable.spring.boot.process.ProcessEngineServicesAutoConfiguration", + "org.flowable.spring.boot.app.AppEngineAutoConfiguration", + "org.flowable.spring.boot.app.AppEngineServicesAutoConfiguration" + } +) +public class BoYueApplication { + public static void main(String[] args) throws UnknownHostException { + // System.setProperty("spring.devtools.restart.enabled", "false"); + ConfigurableApplicationContext application = SpringApplication.run(BoYueApplication.class, args); + System.out.println("(♥◠‿◠)ノ゙ 启动成功 ლ(´ڡ`ლ)゙ \n"); + + Environment env = application.getEnvironment(); + String ip = InetAddress.getLocalHost().getHostAddress(); + String port = env.getProperty("server.port"); + System.out.println("\n----------------------------------------------------------\n" + + " Application boyue-Geek is running! Access URLs:\n" + + " Local: http://localhost:" + port + "/\n" + + " External: http://" + ip + ":" + port + "/\n" + + " Swagger文档: http://" + ip + ":" + port + "/swagger-ui/index.html\n" + + " Knife4j文档: http://" + ip + ":" + port + "/doc.html" + "" + "\n" + + "----------------------------------------------------------"); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/BoYueServletInitializer.java b/boyue-admin/src/main/java/com/boyue/BoYueServletInitializer.java new file mode 100644 index 0000000..90df777 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/BoYueServletInitializer.java @@ -0,0 +1,18 @@ +package com.boyue; + +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; + +/** + * web容器中进行部署 + * + * @author boyue + */ +public class BoYueServletInitializer extends SpringBootServletInitializer +{ + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) + { + return application.sources(BoYueApplication.class); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/common/CaptchaController.java b/boyue-admin/src/main/java/com/boyue/web/controller/common/CaptchaController.java new file mode 100644 index 0000000..f0fda88 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/common/CaptchaController.java @@ -0,0 +1,81 @@ +package com.boyue.web.controller.common; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import javax.imageio.ImageIO; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.FastByteArrayOutputStream; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.google.code.kaptcha.Producer; +import com.boyue.common.config.BoYueConfig; +import com.boyue.common.constant.CacheConstants; +import com.boyue.common.constant.Constants; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.utils.CacheUtils; +import com.boyue.common.utils.sign.Base64; +import com.boyue.common.utils.uuid.IdUtils; +import com.boyue.system.service.ISysConfigService; + +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 验证码操作处理 + * + * @author boyue + */ +@RestController +public class CaptchaController { + + @Resource(name = "captchaProducer") + private Producer captchaProducer; + + @Resource(name = "captchaProducerMath") + private Producer captchaProducerMath; + + @Autowired + private ISysConfigService configService; + + /** + * 生成验证码 + */ + @GetMapping("/captchaImage") + public AjaxResult getCode(HttpServletResponse response) throws IOException { + AjaxResult ajax = AjaxResult.success(); + boolean captchaEnabled = configService.selectCaptchaEnabled(); + ajax.put("captchaEnabled", captchaEnabled); + if (!captchaEnabled) { + return ajax; + } + // 保存验证码信息 + String uuid = IdUtils.simpleUUID(), capStr = null, code = null; + BufferedImage image = null; + // 生成验证码 + String captchaType = BoYueConfig.getCaptchaType(); + if ("math".equals(captchaType)) { + String capText = captchaProducerMath.createText(); + capStr = capText.substring(0, capText.lastIndexOf("@")); + code = capText.substring(capText.lastIndexOf("@") + 1); + image = captchaProducerMath.createImage(capStr); + } else if ("char".equals(captchaType)) { + capStr = code = captchaProducer.createText(); + image = captchaProducer.createImage(capStr); + } + CacheUtils.put(CacheConstants.CAPTCHA_CODE_KEY, uuid, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES); + // 转换流信息写出 + FastByteArrayOutputStream os = new FastByteArrayOutputStream(); + try { + ImageIO.write(image, "jpg", os); + } catch (IOException e) { + return AjaxResult.error(e.getMessage()); + } + ajax.put("uuid", uuid); + ajax.put("img", Base64.encode(os.toByteArray())); + return ajax; + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/common/CommonController.java b/boyue-admin/src/main/java/com/boyue/web/controller/common/CommonController.java new file mode 100644 index 0000000..30ca4fc --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/common/CommonController.java @@ -0,0 +1,376 @@ +package com.boyue.web.controller.common; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.multipart.MultipartFile; + +import com.boyue.common.annotation.Anonymous; +import com.boyue.common.config.BoYueConfig; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.file.FileUtils; +import com.boyue.common.utils.file.MimeTypeUtils; +import com.boyue.file.utils.FileOperateUtils; +import com.boyue.framework.config.ServerConfig; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 通用请求处理 + * + * @author boyue + */ +@Tag(name = "通用请求处理") +@RestController +@RequestMapping("/common") +public class CommonController { + + private static final Logger log = LoggerFactory.getLogger(CommonController.class); + + private static final String FILE_DELIMETER = ","; + + @Autowired + private ServerConfig serverConfig; + + /** + * 通用下载请求 + * + * @param fileName 文件名称 + * @param delete 是否删除 + */ + @Operation(summary = "通用下载请求") + @Parameters({ + @Parameter(name = "fileName", description = "文件名称"), + @Parameter(name = "delete", description = "是否删除") + }) + @GetMapping("/download") + @Anonymous + public void fileDownload( + @RequestParam("fileName") String fileName, + @RequestParam("delete") Boolean delete, + HttpServletResponse response, + HttpServletRequest request) { + try { + if (!FileUtils.checkAllowDownload(fileName)) { + throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName)); + } + String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1); + String filePath = BoYueConfig.getDownloadPath() + fileName; + + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + FileUtils.setAttachmentResponseHeader(response, realFileName); + // FileUtils.writeBytes(filePath, response.getOutputStream()); + FileOperateUtils.downLoad(filePath, response.getOutputStream()); + if (delete) { + FileOperateUtils.deleteFile(fileName); + } + } catch (Exception e) { + log.error("下载文件失败", e); + } + } + + /** + * 通用上传请求(单个) + */ + @Operation(summary = "通用上传请求(单个)") + @PostMapping("/upload") + @Anonymous + public AjaxResult uploadFile(MultipartFile file) throws Exception { + try { + if (file == null) { + return AjaxResult.error("上传的文件不能为空"); + } + + // 记录文件信息 + log.info("接收到文件上传请求,文件名: {}, 大小: {}KB", + file.getOriginalFilename(), file.getSize() / 1024); + + String url = FileOperateUtils.upload(file); + + log.info("文件上传成功,文件地址: {}", url); + + AjaxResult ajax = AjaxResult.success(); + ajax.put("url", url); + ajax.put("fileName", getFileName(file.getOriginalFilename())); + ajax.put("newFileName", FileUtils.getName(file.getOriginalFilename())); + ajax.put("originalFilename", file.getOriginalFilename()); + ajax.put("code", 200); // 确保返回正确的状态码 + + return ajax; + } catch (Exception e) { + log.error("文件上传失败", e); + return AjaxResult.error("文件上传失败: " + e.getMessage()); + } + } + + /** + * 从文件名中提取文件名(不带路径) + */ + private String getFileName(String name) { + if (name == null) { + return ""; + } + int lastIndex = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')); + return lastIndex >= 0 ? name.substring(lastIndex + 1) : name; + } + + /** + * 通用上传请求(多个) + */ + @Operation(summary = "通用上传请求(多个)") + @PostMapping("/uploads") + @Anonymous + public AjaxResult uploadFiles(@RequestBody List files) + throws Exception { + try { + // 上传文件路径 + String filePath = BoYueConfig.getUploadPath(); + List urls = new ArrayList(); + List fileNames = new ArrayList(); + List newFileNames = new ArrayList(); + List originalFilenames = new ArrayList(); + for (MultipartFile file : files) { + // 上传并返回新文件名称 + String fileName = FileOperateUtils.upload(filePath, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); + String url = serverConfig.getUrl() + fileName; + urls.add(url); + fileNames.add(fileName); + newFileNames.add(FileUtils.getName(fileName)); + originalFilenames.add(file.getOriginalFilename()); + } + AjaxResult ajax = AjaxResult.success(); + ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER)); + ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER)); + ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER)); + ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER)); + return ajax; + } catch (Exception e) { + return AjaxResult.error(e.getMessage()); + } + } + + /** + * 本地资源通用下载 + */ + @Operation(summary = "本地资源通用下载") + @GetMapping("/download/resource") + @Anonymous + public void resourceDownload(@Parameter(name = "resource", description = "资源名称") String resource, + HttpServletRequest request, HttpServletResponse response) + throws Exception { + try { + if (!FileUtils.checkAllowDownload(resource)) { + throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource)); + } + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + FileUtils.setAttachmentResponseHeader(response, resource); + FileOperateUtils.downLoad(resource, response.getOutputStream()); + } catch (Exception e) { + log.error("下载文件失败", e); + } + } + + /** + * 删除文件请求 + * + * @param filePathParam 包含文件路径的参数对象 + * @return 删除结果 + */ + @Operation(summary = "删除文件请求") + @PostMapping("/deleteFile") + @Anonymous + public AjaxResult deleteFile(@RequestBody(required = false) FilePathParam filePathParam, + @RequestParam(value = "filePath", required = false) String filePathParam2) { + try { + String filePath; + + // 支持两种方式传参:请求体或URL参数 + if (filePathParam != null && StringUtils.isNotEmpty(filePathParam.filePath)) { + filePath = filePathParam.filePath; + } else if (StringUtils.isNotEmpty(filePathParam2)) { + filePath = filePathParam2; + } else { + return AjaxResult.error("文件路径不能为空"); + } + + log.info("原始文件路径: {}", filePath); + + // 处理文件路径格式 + if (filePath.contains("http://") || filePath.contains("https://")) { + // 如果是完整URL,提取文件名或相对路径部分 + if (filePath.contains("/profile/")) { + filePath = filePath.substring(filePath.indexOf("/profile/") + 9); + } else { + // 尝试从路径中提取文件名 + filePath = filePath.substring(filePath.lastIndexOf('/') + 1); + } + } + + // 处理反斜杠 + filePath = filePath.replace('\\', '/'); + + // 去除开头的斜杠 + if (filePath.startsWith("/")) { + filePath = filePath.substring(1); + } + + log.info("处理后的文件路径: {}", filePath); + + // 安全检查 + if (!FileUtils.checkAllowDownload(filePath)) { + return AjaxResult.error(StringUtils.format("文件名称({})非法,不允许删除。", filePath)); + } + + // 执行删除 + boolean result = FileOperateUtils.deleteFile(filePath); + if (result) { + return AjaxResult.success("删除成功"); + } else { + return AjaxResult.error("文件删除失败"); + } + } catch (Exception e) { + log.error("删除文件失败", e); + return AjaxResult.error("删除文件失败: " + e.getMessage()); + } + } + + /** + * 删除文件请求 - GET方法 + * + * @param filePath 文件路径 + * @return 删除结果 + */ + @Operation(summary = "删除文件请求 - GET方式") + @GetMapping("/deleteFile") + @Anonymous + public AjaxResult deleteFileGet(@RequestParam("filePath") String filePath) { + FilePathParam param = new FilePathParam(); + param.setFilePath(filePath); + return deleteFile(param, null); + } + + /** + * 文件路径参数类 + */ + public static class FilePathParam { + public String filePath; + + public FilePathParam() { + } + + public String getFilePath() { + return filePath; + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + } + } + + /** + * 文件上传诊断工具 + */ + @Operation(summary = "文件上传诊断工具") + @GetMapping("/diagnose-upload") + @Anonymous + public AjaxResult diagnoseUpload() { + try { + Map diagnostics = new HashMap<>(); + + // 获取系统配置 + diagnostics.put("uploadPath", BoYueConfig.getProfile()); + diagnostics.put("fileServer", BoYueConfig.getFileServer()); + + // 系统信息 + Map systemInfo = new HashMap<>(); + systemInfo.put("os.name", System.getProperty("os.name")); + systemInfo.put("file.separator", File.separator); + systemInfo.put("user.dir", System.getProperty("user.dir")); + diagnostics.put("systemInfo", systemInfo); + + // 检查目录 + List pathsToCheck = new ArrayList<>(); + pathsToCheck.add(BoYueConfig.getProfile()); + pathsToCheck.add(BoYueConfig.getProfile() + "/files"); + pathsToCheck.add(BoYueConfig.getProfile() + "/files/master"); + + List> directoryChecks = new ArrayList<>(); + for (String path : pathsToCheck) { + Map check = new HashMap<>(); + File directory = new File(path); + check.put("path", path); + check.put("exists", directory.exists()); + check.put("isDirectory", directory.exists() && directory.isDirectory()); + check.put("canWrite", directory.exists() && directory.canWrite()); + check.put("canRead", directory.exists() && directory.canRead()); + check.put("absolutePath", directory.getAbsolutePath()); + directoryChecks.add(check); + } + diagnostics.put("directoryChecks", directoryChecks); + + // 尝试创建测试文件 + try { + String testDirectory = BoYueConfig.getProfile() + "/files/master"; + File dir = new File(testDirectory); + if (!dir.exists()) { + dir.mkdirs(); + } + + String testFilePath = testDirectory + "/test_" + System.currentTimeMillis() + ".txt"; + File testFile = new File(testFilePath); + boolean created = testFile.createNewFile(); + + Map testFileInfo = new HashMap<>(); + testFileInfo.put("path", testFilePath); + testFileInfo.put("created", created); + testFileInfo.put("exists", testFile.exists()); + + if (created && testFile.exists()) { + // 写入一些内容 + try (java.io.FileWriter writer = new java.io.FileWriter(testFile)) { + writer.write("Test file created at: " + new java.util.Date()); + } + + // 生成访问URL + String url = FileOperateUtils.getURL(testFilePath.substring(BoYueConfig.getProfile().length() + 1)); + testFileInfo.put("url", url); + + // 删除测试文件 + boolean deleted = testFile.delete(); + testFileInfo.put("deleted", deleted); + } + + diagnostics.put("testFileInfo", testFileInfo); + } catch (Exception e) { + Map testFileError = new HashMap<>(); + testFileError.put("error", e.getMessage()); + testFileError.put("stackTrace", e.getStackTrace()); + diagnostics.put("testFileError", testFileError); + } + + return AjaxResult.success("诊断完成").put("diagnostics", diagnostics); + } catch (Exception e) { + log.error("诊断失败", e); + return AjaxResult.error("诊断失败: " + e.getMessage()); + } + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/monitor/CacheController.java b/boyue-admin/src/main/java/com/boyue/web/controller/monitor/CacheController.java new file mode 100644 index 0000000..0ae20c6 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/monitor/CacheController.java @@ -0,0 +1,122 @@ +package com.boyue.web.controller.monitor; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.springframework.cache.Cache.ValueWrapper; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.constant.CacheConstants; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.text.Convert; +import com.boyue.common.utils.CacheUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.system.domain.SysCache; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; + +/** + * 缓存监控 + * + * @author boyue + */ +@Tag(name = "缓存监控") +@RestController +@RequestMapping("/monitor/cache") +public class CacheController { + + private static String tmpCacheName = ""; + + private final static List caches = new ArrayList(); + { + caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息")); + caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "配置信息")); + caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "数据字典")); + caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码")); + caches.add(new SysCache(CacheConstants.PHONE_CODES, "短信验证码")); + caches.add(new SysCache(CacheConstants.EMAIL_CODES, "邮箱验证码")); + caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交")); + caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理")); + caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数")); + caches.add(new SysCache(CacheConstants.IP_ERR_CNT_KEY, "IP错误次数")); + caches.add(new SysCache(CacheConstants.FILE_MD5_PATH_KEY, "path-md5")); + caches.add(new SysCache(CacheConstants.FILE_PATH_MD5_KEY, "md5-path")); + } + + @Operation(summary = "获取缓存名列表") + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @GetMapping("/getNames") + public AjaxResult cache() { + return AjaxResult.success(caches); + } + + @Operation(summary = "获取缓存键列表") + @Parameters({ + @Parameter(name = "cacheName", description = "缓存名称", required = true), + }) + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @GetMapping("/getKeys/{cacheName}") + public AjaxResult getCacheKeys(@PathVariable String cacheName) { + tmpCacheName = cacheName; + Set keyset = CacheUtils.getkeys(cacheName); + return AjaxResult.success(keyset); + } + + @Operation(summary = "获取缓存值列表") + @Parameters({ + @Parameter(name = "cacheName", description = "缓存名称", required = true), + @Parameter(name = "cacheKey", description = "缓存键名", required = true) + }) + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @GetMapping("/getValue/{cacheName}/{cacheKey}") + public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey) { + ValueWrapper valueWrapper = CacheUtils.get(cacheName, cacheKey); + SysCache sysCache = new SysCache(); + sysCache.setCacheName(cacheName); + sysCache.setCacheKey(cacheKey); + if (StringUtils.isNotNull(valueWrapper)) { + sysCache.setCacheValue(Convert.toStr(valueWrapper.get(), "")); + } + return AjaxResult.success(sysCache); + } + + @Operation(summary = "清除缓存") + @Parameters({ + @Parameter(name = "cacheName", description = "缓存名称", required = true) + }) + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @DeleteMapping("/clearCacheName/{cacheName}") + public AjaxResult clearCacheName(@PathVariable String cacheName) { + CacheUtils.clear(cacheName); + return AjaxResult.success(); + } + + @Operation(summary = "清除缓存值") + @Parameters({ + @Parameter(name = "cacheKey", description = "缓存键名", required = true) + }) + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @DeleteMapping("/clearCacheKey/{cacheKey}") + public AjaxResult clearCacheKey(@PathVariable String cacheKey) { + CacheUtils.removeIfPresent(tmpCacheName, cacheKey); + return AjaxResult.success(); + } + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @DeleteMapping("/clearCacheAll") + public AjaxResult clearCacheAll() { + for (String cacheName : CacheUtils.getCacheManager().getCacheNames()) { + CacheUtils.clear(cacheName); + } + return AjaxResult.success(); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/monitor/ServerController.java b/boyue-admin/src/main/java/com/boyue/web/controller/monitor/ServerController.java new file mode 100644 index 0000000..1f9b317 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/monitor/ServerController.java @@ -0,0 +1,32 @@ +package com.boyue.web.controller.monitor; + +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.framework.web.domain.Server; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +/** + * 服务器监控 + * + * @author boyue + */ +@Tag(name = "服务器监控") +@RestController +@RequestMapping("/monitor/server") +public class ServerController { + + @Operation(summary = "获取服务器监控信息") + @PreAuthorize("@ss.hasPermi('monitor:server:list')") + @GetMapping() + public AjaxResult getInfo() throws Exception { + Server server = new Server(); + server.copyTo(); + return AjaxResult.success(server); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/monitor/SysLogininforController.java b/boyue-admin/src/main/java/com/boyue/web/controller/monitor/SysLogininforController.java new file mode 100644 index 0000000..6cda1fb --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/monitor/SysLogininforController.java @@ -0,0 +1,96 @@ +package com.boyue.web.controller.monitor; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.framework.web.service.SysPasswordService; +import com.boyue.system.domain.SysLogininfor; +import com.boyue.system.service.ISysLogininforService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 系统访问记录 + * + * @author boyue + */ +@Tag(name = "系统访问记录") +@RestController +@RequestMapping("/monitor/logininfor") +public class SysLogininforController extends BaseController { + + @Autowired + private ISysLogininforService logininforService; + + @Autowired + private SysPasswordService passwordService; + + @Operation(summary = "获取系统访问记录列表") + @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')") + @GetMapping("/list") + public TableDataInfo list(SysLogininfor logininfor) { + startPage(); + List list = logininforService.selectLogininforList(logininfor); + return getDataTable(list); + } + + @Operation(summary = "导出系统访问记录列表") + @Log(title = "登录日志", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysLogininfor logininfor) { + List list = logininforService.selectLogininforList(logininfor); + ExcelUtil util = new ExcelUtil(SysLogininfor.class); + util.exportExcel(response, list, "登录日志"); + } + + @Operation(summary = "删除系统访问记录") + @Parameters({ + @Parameter(name = "infoIds", description = "记录id数组", required = true), + }) + @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')") + @Log(title = "登录日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{infoIds}") + public AjaxResult remove(@PathVariable(name = "infoIds") Long[] infoIds) { + return toAjax(logininforService.deleteLogininforByIds(infoIds)); + } + + @Operation(summary = "清除系统访问记录") + @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')") + @Log(title = "登录日志", businessType = BusinessType.CLEAN) + @DeleteMapping("/clean") + public AjaxResult clean() { + logininforService.cleanLogininfor(); + return success(); + } + + @Operation(summary = "账户解锁") + @Parameters({ + @Parameter(name = "userName", description = "用户名", required = true), + }) + @PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')") + @Log(title = "账户解锁", businessType = BusinessType.OTHER) + @GetMapping("/unlock/{userName}") + public AjaxResult unlock(@PathVariable("userName") String userName) { + passwordService.clearLoginRecordCache(userName); + return success(); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/monitor/SysOperlogController.java b/boyue-admin/src/main/java/com/boyue/web/controller/monitor/SysOperlogController.java new file mode 100644 index 0000000..88b72ee --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/monitor/SysOperlogController.java @@ -0,0 +1,102 @@ +package com.boyue.web.controller.monitor; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.R; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.system.domain.SysOperLog; +import com.boyue.system.service.ISysOperLogService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 操作日志记录 + * + * @author boyue + */ +@Tag(name = "操作日志记录") +@RestController +@RequestMapping("/monitor/operlog") +public class SysOperlogController extends BaseController { + + @Autowired + private ISysOperLogService operLogService; + + @Operation(summary = "获取操作日志记录列表") + @PreAuthorize("@ss.hasPermi('monitor:operlog:list')") + @GetMapping("/list") + public TableDataInfo list(SysOperLog operLog) { + startPage(); + List list = operLogService.selectOperLogList(operLog); + return getDataTable(list); + } + + @Operation(summary = "导出操作日志记录列表") + @Log(title = "操作日志", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('monitor:operlog:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysOperLog operLog) { + List list = operLogService.selectOperLogList(operLog); + ExcelUtil util = new ExcelUtil(SysOperLog.class); + util.exportExcel(response, list, "操作日志"); + } + + @Operation(summary = "删除操作日志记录") + @Parameters({ + @Parameter(name = "operIds", description = "记录id数组", required = true), + }) + @Log(title = "操作日志", businessType = BusinessType.DELETE) + @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')") + @DeleteMapping("/{operIds}") + public AjaxResult remove(@PathVariable(name = "operIds") Long[] operIds) { + return toAjax(operLogService.deleteOperLogByIds(operIds)); + } + + @Operation(summary = "清除操作日志记录") + @Log(title = "操作日志", businessType = BusinessType.CLEAN) + @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')") + @DeleteMapping("/clean") + public AjaxResult clean() { + operLogService.cleanOperLog(); + return success(); + } + + @Operation(summary = "业务监控") + @GetMapping("/business") + public R> business(SysOperLog operLog) { + // 查询并获取统计数据 + List> successStats = operLogService.getSuccessOperationStats(operLog); + List> failureStats = operLogService.getFailureOperationStats(operLog); + List> statusStats = operLogService.getStatusStats(operLog); + List> moduleOperationStats = operLogService.getModuleOperationStats(operLog); + // 创建一个新的 Map 来组织数据 + Map result = new LinkedHashMap<>(); + result.put("successStats", successStats); + result.put("failureStats", failureStats); + result.put("statusStats", statusStats); + result.put("moduleOperationStats", moduleOperationStats); + result.put("total", + successStats.size() + failureStats.size() + statusStats.size() + moduleOperationStats.size()); + return R.ok(result); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/monitor/SysUserOnlineController.java b/boyue-admin/src/main/java/com/boyue/web/controller/monitor/SysUserOnlineController.java new file mode 100644 index 0000000..208e021 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/monitor/SysUserOnlineController.java @@ -0,0 +1,72 @@ +package com.boyue.web.controller.monitor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.constant.CacheConstants; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.CacheUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.system.domain.SysUserOnline; +import com.boyue.system.service.ISysUserOnlineService; + +/** + * 在线用户监控 + * + * @author boyue + */ +@RestController +@RequestMapping("/monitor/online") +public class SysUserOnlineController extends BaseController { + + @Autowired + private ISysUserOnlineService userOnlineService; + + @PreAuthorize("@ss.hasPermi('monitor:online:list')") + @GetMapping("/list") + public TableDataInfo list(String ipaddr, String userName) { + Collection keys = CacheUtils.getkeys(CacheConstants.LOGIN_TOKEN_KEY); + List userOnlineList = new ArrayList(); + for (String key : keys) { + LoginUser user = CacheUtils.get(CacheConstants.LOGIN_TOKEN_KEY, key, LoginUser.class); + if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) { + userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user)); + } else if (StringUtils.isNotEmpty(ipaddr)) { + userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user)); + } else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser())) { + userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user)); + } else { + userOnlineList.add(userOnlineService.loginUserToUserOnline(user)); + } + } + Collections.reverse(userOnlineList); + userOnlineList.removeAll(Collections.singleton(null)); + return getDataTable(userOnlineList); + } + + /** + * 强退用户 + */ + @PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')") + @Log(title = "在线用户", businessType = BusinessType.FORCE) + @DeleteMapping("/{tokenId}") + public AjaxResult forceLogout(@PathVariable String tokenId) { + CacheUtils.removeIfPresent(CacheConstants.LOGIN_TOKEN_KEY, tokenId); + return success(); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/system/SysConfigController.java b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysConfigController.java new file mode 100644 index 0000000..e8bbcba --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysConfigController.java @@ -0,0 +1,139 @@ +package com.boyue.web.controller.system; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Anonymous; +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.system.domain.SysConfig; +import com.boyue.system.service.ISysConfigService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 参数配置 信息操作处理 + * + * @author boyue + */ +@Tag(name = "参数配置") +@RestController +@RequestMapping("/system/config") +public class SysConfigController extends BaseController { + + @Autowired + private ISysConfigService configService; + + /** + * 获取参数配置列表 + */ + @Operation(summary = "获取参数配置列表") + @PreAuthorize("@ss.hasPermi('system:config:list')") + @GetMapping("/list") + public TableDataInfo list(SysConfig config) { + startPage(); + List list = configService.selectConfigList(config); + return getDataTable(list); + } + + @Operation(summary = "参数管理") + @Log(title = "参数管理", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:config:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysConfig config) { + List list = configService.selectConfigList(config); + ExcelUtil util = new ExcelUtil(SysConfig.class); + util.exportExcel(response, list, "参数数据"); + } + + /** + * 根据参数编号获取详细信息 + */ + @Operation(summary = "根据参数编号获取详细信息") + @PreAuthorize("@ss.hasPermi('system:config:query')") + @GetMapping(value = "/{configId}") + public AjaxResult getInfo(@PathVariable(name = "configId") Long configId) { + return success(configService.selectConfigById(configId)); + } + + /** + * 根据参数键名查询参数值 + */ + @Operation(summary = "根据参数键名查询参数值") + @GetMapping(value = "/configKey/{configKey}") + @Anonymous + public AjaxResult getConfigKey(@PathVariable(name = "configKey") String configKey) { + return success(configService.selectConfigByKey(configKey)); + } + + /** + * 新增参数配置 + */ + @Operation(summary = "新增参数配置") + @PreAuthorize("@ss.hasPermi('system:config:add')") + @Log(title = "参数管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysConfig config) { + if (!configService.checkConfigKeyUnique(config)) { + return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + config.setCreateBy(getUsername()); + return toAjax(configService.insertConfig(config)); + } + + /** + * 修改参数配置 + */ + @Operation(summary = "修改参数配置") + @PreAuthorize("@ss.hasPermi('system:config:edit')") + @Log(title = "参数管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysConfig config) { + if (!configService.checkConfigKeyUnique(config)) { + return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + config.setUpdateBy(getUsername()); + return toAjax(configService.updateConfig(config)); + } + + /** + * 删除参数配置 + */ + @Operation(summary = "删除参数配置") + @PreAuthorize("@ss.hasPermi('system:config:remove')") + @Log(title = "参数管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{configIds}") + public AjaxResult remove(@PathVariable(name = "configIds") Long[] configIds) { + configService.deleteConfigByIds(configIds); + return success(); + } + + /** + * 刷新参数缓存 + */ + @Operation(summary = "刷新参数缓存") + @PreAuthorize("@ss.hasPermi('system:config:remove')") + @Log(title = "参数管理", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public AjaxResult refreshCache() { + configService.resetConfigCache(); + return success(); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/system/SysDeptController.java b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysDeptController.java new file mode 100644 index 0000000..f79b4be --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysDeptController.java @@ -0,0 +1,132 @@ +package com.boyue.web.controller.system; + +import java.util.List; + +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.constant.UserConstants; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.entity.SysDept; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.StringUtils; +import com.boyue.system.service.ISysDeptService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +/** + * 部门信息 + * + * @author boyue + */ +@Tag(name = "部门信息") +@RestController +@RequestMapping("/system/dept") +public class SysDeptController extends BaseController { + + @Autowired + private ISysDeptService deptService; + + /** + * 获取部门列表 + */ + @Operation(summary = "获取部门列表") + @PreAuthorize("@ss.hasPermi('system:dept:list')") + @GetMapping("/list") + public AjaxResult list(SysDept dept) { + List depts = deptService.selectDeptList(dept); + return success(depts); + } + + /** + * 查询部门列表(排除节点) + */ + @Operation(summary = "查询部门列表", description = "排除节点") + @PreAuthorize("@ss.hasPermi('system:dept:list')") + @GetMapping("/list/exclude/{deptId}") + public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) { + List depts = deptService.selectDeptList(new SysDept()); + depts.removeIf(d -> d.getDeptId().intValue() == deptId + || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + "")); + return success(depts); + } + + /** + * 根据部门编号获取详细信息 + */ + @Operation(summary = "根据部门编号获取详细信息") + @PreAuthorize("@ss.hasPermi('system:dept:query')") + @GetMapping(value = "/{deptId}") + public AjaxResult getInfo(@PathVariable(name = "deptId") Long deptId) { + deptService.checkDeptDataScope(deptId); + return success(deptService.selectDeptById(deptId)); + } + + /** + * 新增部门 + */ + @Operation(summary = "新增部门") + @PreAuthorize("@ss.hasPermi('system:dept:add')") + @Log(title = "部门管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysDept dept) { + if (!deptService.checkDeptNameUnique(dept)) { + return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } + dept.setCreateBy(getUsername()); + return toAjax(deptService.insertDept(dept)); + } + + /** + * 修改部门 + */ + @Operation(summary = "修改部门") + @PreAuthorize("@ss.hasPermi('system:dept:edit')") + @Log(title = "部门管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysDept dept) { + Long deptId = dept.getDeptId(); + deptService.checkDeptDataScope(deptId); + if (!deptService.checkDeptNameUnique(dept)) { + return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } else if (dept.getParentId().equals(deptId)) { + return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); + } else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) + && deptService.selectNormalChildrenDeptById(deptId) > 0) { + return error("该部门包含未停用的子部门!"); + } + dept.setUpdateBy(getUsername()); + return toAjax(deptService.updateDept(dept)); + } + + /** + * 删除部门 + */ + @Operation(summary = "删除部门") + @PreAuthorize("@ss.hasPermi('system:dept:remove')") + @Log(title = "部门管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{deptId}") + public AjaxResult remove(@PathVariable(name = "deptId") Long deptId) { + if (deptService.hasChildByDeptId(deptId)) { + return warn("存在下级部门,不允许删除"); + } + if (deptService.checkDeptExistUser(deptId)) { + return warn("部门存在用户,不允许删除"); + } + deptService.checkDeptDataScope(deptId); + return toAjax(deptService.deleteDeptById(deptId)); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/system/SysDictDataController.java b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysDictDataController.java new file mode 100644 index 0000000..e960505 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysDictDataController.java @@ -0,0 +1,126 @@ +package com.boyue.web.controller.system; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.entity.SysDictData; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.system.service.ISysDictDataService; +import com.boyue.system.service.ISysDictTypeService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 数据字典信息 + * + * @author boyue + */ +@Tag(name = "数据字典信息(数据)") +@RestController +@RequestMapping("/system/dict/data") +public class SysDictDataController extends BaseController { + + @Autowired + private ISysDictDataService dictDataService; + + @Autowired + private ISysDictTypeService dictTypeService; + + @Operation(summary = "查询字典数据列表") + @PreAuthorize("@ss.hasPermi('system:dict:list')") + @GetMapping("/list") + public TableDataInfo list(SysDictData dictData) { + startPage(); + List list = dictDataService.selectDictDataList(dictData); + return getDataTable(list); + } + + @Operation(summary = "导出字典数据列表") + @Log(title = "字典数据", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:dict:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysDictData dictData) { + List list = dictDataService.selectDictDataList(dictData); + ExcelUtil util = new ExcelUtil(SysDictData.class); + util.exportExcel(response, list, "字典数据"); + } + + /** + * 查询字典数据详细 + */ + @Operation(summary = "查询字典数据详细") + @PreAuthorize("@ss.hasPermi('system:dict:query')") + @GetMapping(value = "/{dictCode}") + public AjaxResult getInfo(@PathVariable(name = "dictCode") Long dictCode) { + return success(dictDataService.selectDictDataById(dictCode)); + } + + /** + * 根据字典类型查询字典数据信息 + */ + @Operation(summary = "根据字典类型查询字典数据信息") + @GetMapping(value = "/type/{dictType}") + public AjaxResult dictType(@PathVariable(name = "dictType") String dictType) { + List data = dictTypeService.selectDictDataByType(dictType); + if (StringUtils.isNull(data)) { + data = new ArrayList(); + } + return success(data); + } + + /** + * 新增字典类型 + */ + @Operation(summary = "新增字典类型") + @PreAuthorize("@ss.hasPermi('system:dict:add')") + @Log(title = "字典数据", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysDictData dict) { + dict.setCreateBy(getUsername()); + return toAjax(dictDataService.insertDictData(dict)); + } + + /** + * 修改保存字典类型 + */ + @Operation(summary = "修改保存字典类型") + @PreAuthorize("@ss.hasPermi('system:dict:edit')") + @Log(title = "字典数据", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysDictData dict) { + dict.setUpdateBy(getUsername()); + return toAjax(dictDataService.updateDictData(dict)); + } + + /** + * 删除字典类型 + */ + @Operation(summary = "删除字典类型") + @PreAuthorize("@ss.hasPermi('system:dict:remove')") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictCodes}") + public AjaxResult remove(@PathVariable(name = "dictCodes") Long[] dictCodes) { + dictDataService.deleteDictDataByIds(dictCodes); + return success(); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/system/SysDictTypeController.java b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysDictTypeController.java new file mode 100644 index 0000000..98fd465 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysDictTypeController.java @@ -0,0 +1,135 @@ +package com.boyue.web.controller.system; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.entity.SysDictType; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.system.service.ISysDictTypeService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 数据字典信息 + * + * @author boyue + */ +@Tag(name = "数据字典信息(类型)") +@RestController +@RequestMapping("/system/dict/type") +public class SysDictTypeController extends BaseController { + + @Autowired + private ISysDictTypeService dictTypeService; + + @Operation(summary = "查询字典类型列表") + @PreAuthorize("@ss.hasPermi('system:dict:list')") + @GetMapping("/list") + public TableDataInfo list(SysDictType dictType) { + startPage(); + List list = dictTypeService.selectDictTypeList(dictType); + return getDataTable(list); + } + + @Operation(summary = "导出字典类型列表") + @Log(title = "字典类型", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:dict:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysDictType dictType) { + List list = dictTypeService.selectDictTypeList(dictType); + ExcelUtil util = new ExcelUtil(SysDictType.class); + util.exportExcel(response, list, "字典类型"); + } + + /** + * 查询字典类型详细 + */ + @Operation(summary = "查询字典类型详细") + @PreAuthorize("@ss.hasPermi('system:dict:query')") + @GetMapping(value = "/{dictId}") + public AjaxResult getInfo(@PathVariable(name = "dictId") Long dictId) { + return success(dictTypeService.selectDictTypeById(dictId)); + } + + /** + * 新增字典类型 + */ + @Operation(summary = "新增字典类型") + @PreAuthorize("@ss.hasPermi('system:dict:add')") + @Log(title = "字典类型", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysDictType dict) { + if (!dictTypeService.checkDictTypeUnique(dict)) { + return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dict.setCreateBy(getUsername()); + return toAjax(dictTypeService.insertDictType(dict)); + } + + /** + * 修改字典类型 + */ + @Operation(summary = "修改字典类型") + @PreAuthorize("@ss.hasPermi('system:dict:edit')") + @Log(title = "字典类型", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysDictType dict) { + if (!dictTypeService.checkDictTypeUnique(dict)) { + return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dict.setUpdateBy(getUsername()); + return toAjax(dictTypeService.updateDictType(dict)); + } + + /** + * 删除字典类型 + */ + @Operation(summary = "删除字典类型") + @PreAuthorize("@ss.hasPermi('system:dict:remove')") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictIds}") + public AjaxResult remove(@PathVariable(name = "dictIds") Long[] dictIds) { + dictTypeService.deleteDictTypeByIds(dictIds); + return success(); + } + + /** + * 刷新字典缓存 + */ + @Operation(summary = "刷新字典缓存") + @PreAuthorize("@ss.hasPermi('system:dict:remove')") + @Log(title = "字典类型", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public AjaxResult refreshCache() { + dictTypeService.resetDictCache(); + return success(); + } + + /** + * 获取字典选择框列表 + */ + @Operation(summary = "获取字典选择框列表") + @GetMapping("/optionselect") + public AjaxResult optionselect() { + List dictTypes = dictTypeService.selectDictTypeAll(); + return success(dictTypes); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/system/SysIndexController.java b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysIndexController.java new file mode 100644 index 0000000..8777739 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysIndexController.java @@ -0,0 +1,34 @@ +package com.boyue.web.controller.system; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.config.BoYueConfig; +import com.boyue.common.utils.StringUtils; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +/** + * 首页 + * + * @author boyue + */ +@Tag(name = "首页") +@RestController +public class SysIndexController { + + /** 系统基础配置 */ + @Autowired + private BoYueConfig BoYueConfig; + + /** + * 访问首页,提示语 + */ + @Operation(summary = "访问首页", description = "提示语") + @RequestMapping("/") + public String index() { + return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", BoYueConfig.getName(), BoYueConfig.getVersion()); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/system/SysLoginController.java b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysLoginController.java new file mode 100644 index 0000000..f93f477 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysLoginController.java @@ -0,0 +1,112 @@ +package com.boyue.web.controller.system; + +import java.util.List; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.constant.Constants; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.entity.SysMenu; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.domain.model.LoginBody; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.file.utils.FileOperateUtils; +import com.boyue.framework.web.service.SysLoginService; +import com.boyue.framework.web.service.SysPermissionService; +import com.boyue.framework.web.service.TokenService; +import com.boyue.system.service.ISysMenuService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +/** + * 登录验证 + * + * @author boyue + */ +@Tag(name = "登录验证") +@RestController +public class SysLoginController { + + @Autowired + private SysLoginService loginService; + + @Autowired + private ISysMenuService menuService; + + @Autowired + private SysPermissionService permissionService; + + @Autowired + private TokenService tokenService; + + /** + * 登录方法 + * + * @param loginBody 登录信息 + * @return 结果 + */ + @Operation(summary = "登录方法") + @PostMapping("/login") + public AjaxResult login(@RequestBody LoginBody loginBody) { + AjaxResult ajax = AjaxResult.success(); + // 生成令牌 + String token = loginService.login( + loginBody.getUsername(), + loginBody.getPassword(), + loginBody.getCode(), + loginBody.getUuid()); + ajax.put(Constants.TOKEN, token); + return ajax; + } + + /** + * 获取用户信息 + * + * @return 用户信息 + */ + @Operation(summary = "获取用户信息") + @GetMapping("getInfo") + public AjaxResult getInfo() { + LoginUser loginUser = SecurityUtils.getLoginUser(); + SysUser user = loginUser.getUser(); + // 角色集合 + Set roles = permissionService.getRolePermission(user); + // 权限集合 + Set permissions = permissionService.getMenuPermission(user); + if (!loginUser.getPermissions().equals(permissions)) { + loginUser.setPermissions(permissions); + tokenService.refreshToken(loginUser); + } + if (user.getAvatar() != null) { + try { + user.setAvatar(FileOperateUtils.getURL(user.getAvatar())); + } catch (Exception e) { + } + } + AjaxResult ajax = AjaxResult.success(); + ajax.put("user", user); + ajax.put("roles", roles); + ajax.put("permissions", permissions); + return ajax; + } + + /** + * 获取路由信息 + * + * @return 路由信息 + */ + @Operation(summary = "获取路由信息") + @GetMapping("getRouters") + public AjaxResult getRouters() { + Long userId = SecurityUtils.getUserId(); + List menus = menuService.selectMenuTreeByUserId(userId); + return AjaxResult.success(menuService.buildMenus(menus)); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/system/SysMenuController.java b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysMenuController.java new file mode 100644 index 0000000..736a276 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysMenuController.java @@ -0,0 +1,138 @@ +package com.boyue.web.controller.system; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.constant.UserConstants; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.entity.SysMenu; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.StringUtils; +import com.boyue.system.service.ISysMenuService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +/** + * 菜单信息 + * + * @author boyue + */ +@Tag(name = "菜单信息") +@RestController +@RequestMapping("/system/menu") +public class SysMenuController extends BaseController { + + @Autowired + private ISysMenuService menuService; + + /** + * 获取菜单列表 + */ + @Operation(summary = "获取菜单列表") + @PreAuthorize("@ss.hasPermi('system:menu:list')") + @GetMapping("/list") + public AjaxResult list(SysMenu menu) { + List menus = menuService.selectMenuList(menu, getUserId()); + return success(menus); + } + + /** + * 根据菜单编号获取详细信息 + */ + @Operation(summary = "根据菜单编号获取详细信息") + @PreAuthorize("@ss.hasPermi('system:menu:query')") + @GetMapping(value = "/{menuId}") + public AjaxResult getInfo(@PathVariable(name = "menuId") Long menuId) { + return success(menuService.selectMenuById(menuId)); + } + + /** + * 获取菜单下拉树列表 + */ + @Operation(summary = "获取菜单下拉树列表") + @GetMapping("/treeselect") + public AjaxResult treeselect(SysMenu menu) { + List menus = menuService.selectMenuList(menu, getUserId()); + return success(menuService.buildMenuTreeSelect(menus)); + } + + /** + * 加载对应角色菜单列表树 + */ + @Operation(summary = "加载对应角色菜单列表树") + @GetMapping(value = "/roleMenuTreeselect/{roleId}") + public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId) { + List menus = menuService.selectMenuList(getUserId()); + AjaxResult ajax = AjaxResult.success(); + ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId)); + ajax.put("menus", menuService.buildMenuTreeSelect(menus)); + return ajax; + } + + /** + * 新增菜单 + */ + @Operation(summary = "新增菜单") + @PreAuthorize("@ss.hasPermi('system:menu:add')") + @Log(title = "菜单管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysMenu menu) { + if (!menuService.checkMenuNameUnique(menu)) { + return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { + return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } + menu.setCreateBy(getUsername()); + return toAjax(menuService.insertMenu(menu)); + } + + /** + * 修改菜单 + */ + @Operation(summary = "修改菜单") + @PreAuthorize("@ss.hasPermi('system:menu:edit')") + @Log(title = "菜单管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysMenu menu) { + if (!menuService.checkMenuNameUnique(menu)) { + return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { + return error("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } else if (menu.getMenuId().equals(menu.getParentId())) { + return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); + } + menu.setUpdateBy(getUsername()); + return toAjax(menuService.updateMenu(menu)); + } + + /** + * 删除菜单 + */ + @Operation(summary = "删除菜单") + @PreAuthorize("@ss.hasPermi('system:menu:remove')") + @Log(title = "菜单管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{menuId}") + public AjaxResult remove(@PathVariable("menuId") Long menuId) { + if (menuService.hasChildByMenuId(menuId)) { + return warn("存在子菜单,不允许删除"); + } + if (menuService.checkMenuExistRole(menuId)) { + return warn("菜单已分配,不允许删除"); + } + return toAjax(menuService.deleteMenuById(menuId)); + } +} \ No newline at end of file diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/system/SysNoticeController.java b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysNoticeController.java new file mode 100644 index 0000000..1e5c0c6 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysNoticeController.java @@ -0,0 +1,97 @@ +package com.boyue.web.controller.system; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.system.domain.SysNotice; +import com.boyue.system.service.ISysNoticeService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +/** + * 公告 信息操作处理 + * + * @author boyue + */ +@Tag(name = "公告", description = "信息操作处理") +@RestController +@RequestMapping("/system/notice") +public class SysNoticeController extends BaseController { + + @Autowired + private ISysNoticeService noticeService; + + /** + * 获取通知公告列表 + */ + @Operation(summary = "获取通知公告列表") + @PreAuthorize("@ss.hasPermi('system:notice:list')") + @GetMapping("/list") + public TableDataInfo list(SysNotice notice) { + startPage(); + List list = noticeService.selectNoticeList(notice); + return getDataTable(list); + } + + /** + * 根据通知公告编号获取详细信息 + */ + @Operation(summary = "根据通知公告编号获取详细信息") + @PreAuthorize("@ss.hasPermi('system:notice:query')") + @GetMapping(value = "/{noticeId}") + public AjaxResult getInfo(@PathVariable(name = "noticeId") Long noticeId) { + return success(noticeService.selectNoticeById(noticeId)); + } + + /** + * 新增通知公告 + */ + @Operation(summary = "新增通知公告") + @PreAuthorize("@ss.hasPermi('system:notice:add')") + @Log(title = "通知公告", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysNotice notice) { + notice.setCreateBy(getUsername()); + return toAjax(noticeService.insertNotice(notice)); + } + + /** + * 修改通知公告 + */ + @Operation(summary = "修改通知公告") + @PreAuthorize("@ss.hasPermi('system:notice:edit')") + @Log(title = "通知公告", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysNotice notice) { + notice.setUpdateBy(getUsername()); + return toAjax(noticeService.updateNotice(notice)); + } + + /** + * 删除通知公告 + */ + @Operation(summary = "删除通知公告") + @PreAuthorize("@ss.hasPermi('system:notice:remove')") + @Log(title = "通知公告", businessType = BusinessType.DELETE) + @DeleteMapping("/{noticeIds}") + public AjaxResult remove(@PathVariable(name = "noticeIds") Long[] noticeIds) { + return toAjax(noticeService.deleteNoticeByIds(noticeIds)); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/system/SysPostController.java b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysPostController.java new file mode 100644 index 0000000..8de7786 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysPostController.java @@ -0,0 +1,129 @@ +package com.boyue.web.controller.system; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.system.domain.SysPost; +import com.boyue.system.service.ISysPostService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 岗位信息操作处理 + * + * @author boyue + */ +@Tag(name = "岗位信息操作处理") +@RestController +@RequestMapping("/system/post") +public class SysPostController extends BaseController { + + @Autowired + private ISysPostService postService; + + /** + * 获取岗位列表 + */ + @Operation(summary = "获取岗位列表") + @PreAuthorize("@ss.hasPermi('system:post:list')") + @GetMapping("/list") + public TableDataInfo list(SysPost post) { + startPage(); + List list = postService.selectPostList(post); + return getDataTable(list); + } + + @Operation(summary = "导出岗位列表") + @Log(title = "岗位管理", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:post:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysPost post) { + List list = postService.selectPostList(post); + ExcelUtil util = new ExcelUtil(SysPost.class); + util.exportExcel(response, list, "岗位数据"); + } + + /** + * 根据岗位编号获取详细信息 + */ + @Operation(summary = "根据岗位编号获取详细信息") + @PreAuthorize("@ss.hasPermi('system:post:query')") + @GetMapping(value = "/{postId}") + public AjaxResult getInfo(@PathVariable(name = "postId") Long postId) { + return success(postService.selectPostById(postId)); + } + + /** + * 新增岗位 + */ + @Operation(summary = "新增岗位") + @PreAuthorize("@ss.hasPermi('system:post:add')") + @Log(title = "岗位管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysPost post) { + if (!postService.checkPostNameUnique(post)) { + return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } else if (!postService.checkPostCodeUnique(post)) { + return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } + post.setCreateBy(getUsername()); + return toAjax(postService.insertPost(post)); + } + + /** + * 修改岗位 + */ + @Operation(summary = "修改岗位") + @PreAuthorize("@ss.hasPermi('system:post:edit')") + @Log(title = "岗位管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysPost post) { + if (!postService.checkPostNameUnique(post)) { + return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } else if (!postService.checkPostCodeUnique(post)) { + return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } + post.setUpdateBy(getUsername()); + return toAjax(postService.updatePost(post)); + } + + /** + * 删除岗位 + */ + @Operation(summary = "删除岗位") + @PreAuthorize("@ss.hasPermi('system:post:remove')") + @Log(title = "岗位管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{postIds}") + public AjaxResult remove(@PathVariable(name = "postIds") Long[] postIds) { + return toAjax(postService.deletePostByIds(postIds)); + } + + /** + * 获取岗位选择框列表 + */ + @Operation(summary = "获取岗位选择框列表") + @GetMapping("/optionselect") + public AjaxResult optionselect() { + List posts = postService.selectPostAll(); + return success(posts); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/system/SysProfileController.java b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysProfileController.java new file mode 100644 index 0000000..e712933 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysProfileController.java @@ -0,0 +1,149 @@ +package com.boyue.web.controller.system; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.DateUtils; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.file.FileUtils; +import com.boyue.common.utils.file.MimeTypeUtils; +import com.boyue.file.utils.FileOperateUtils; +import com.boyue.framework.web.service.TokenService; +import com.boyue.system.service.ISysUserService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +/** + * 个人信息 业务处理 + * + * @author boyue + */ +@Tag(name = "个人信息", description = "业务处理") +@RestController +@RequestMapping("/system/user/profile") +public class SysProfileController extends BaseController { + + @Autowired + private ISysUserService userService; + + @Autowired + private TokenService tokenService; + + /** + * 个人信息 + */ + @Operation(summary = "个人信息") + @GetMapping + public AjaxResult profile() { + LoginUser loginUser = getLoginUser(); + SysUser user = loginUser.getUser(); + if (user.getAvatar() != null) { + try { + user.setAvatar(FileOperateUtils.getURL(user.getAvatar())); + } catch (Exception e) { + } + } + AjaxResult ajax = AjaxResult.success(user); + ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername())); + ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername())); + return ajax; + } + + /** + * 修改用户 + */ + @Operation(summary = "修改用户") + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult updateProfile(@RequestBody SysUser user) { + LoginUser loginUser = getLoginUser(); + SysUser sysUser = loginUser.getUser(); + user.setUserName(sysUser.getUserName()); + if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { + return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); + } + if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { + return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + user.setUserId(sysUser.getUserId()); + user.setPassword(null); + user.setAvatar(null); + user.setDeptId(null); + if (userService.updateUserProfile(user) > 0) { + // 更新缓存用户信息 + sysUser.setNickName(user.getNickName()); + sysUser.setPhonenumber(user.getPhonenumber()); + sysUser.setEmail(user.getEmail()); + sysUser.setSex(user.getSex()); + tokenService.setLoginUser(loginUser); + return success(); + } + return error("修改个人信息异常,请联系管理员"); + } + + /** + * 重置密码 + */ + @Operation(summary = "重置密码") + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping("/updatePwd") + public AjaxResult updatePwd(String oldPassword, String newPassword) { + LoginUser loginUser = getLoginUser(); + String userName = loginUser.getUsername(); + String password = loginUser.getPassword(); + if (!SecurityUtils.matchesPassword(oldPassword, password)) { + return error("修改密码失败,旧密码错误"); + } + if (SecurityUtils.matchesPassword(newPassword, password)) { + return error("新密码不能与旧密码相同"); + } + newPassword = SecurityUtils.encryptPassword(newPassword); + if (userService.resetUserPwd(userName, newPassword) > 0) { + // 更新缓存用户密码 + loginUser.getUser().setPassword(newPassword); + tokenService.setLoginUser(loginUser); + return success(); + } + return error("修改密码异常,请联系管理员"); + } + + /** + * 头像上传 + */ + @Operation(summary = "头像上传") + @Log(title = "用户头像", businessType = BusinessType.UPDATE) + @PostMapping("/avatar") + public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception { + if (!file.isEmpty()) { + LoginUser loginUser = getLoginUser(); + String extractPath = loginUser.getUsername() + "/" + loginUser.getUserId() + ""; + String fileName = DateUtils.dateTimeNow() + "-avatar." + FileUtils.getExtension(file); + String filePath = "avatar/" + extractPath + "/" + fileName; + String url = FileOperateUtils.upload(filePath, file, MimeTypeUtils.IMAGE_EXTENSION); + if (userService.updateUserAvatar(loginUser.getUsername(), filePath)) { + AjaxResult ajax = AjaxResult.success(); + ajax.put("imgUrl", url); + // 更新缓存用户头像 + loginUser.getUser().setAvatar(filePath); + tokenService.setLoginUser(loginUser); + return ajax; + } + } + return error("上传图片异常,请联系管理员"); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/system/SysRegisterController.java b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysRegisterController.java new file mode 100644 index 0000000..f9ae8f4 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysRegisterController.java @@ -0,0 +1,42 @@ +package com.boyue.web.controller.system; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.model.RegisterBody; +import com.boyue.common.utils.StringUtils; +import com.boyue.framework.web.service.SysRegisterService; +import com.boyue.system.service.ISysConfigService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +/** + * 注册验证 + * + * @author boyue + */ +@Tag(name = "注册验证") +@RestController +public class SysRegisterController extends BaseController { + + @Autowired + private SysRegisterService registerService; + + @Autowired + private ISysConfigService configService; + + @Operation(summary = "注册方法") + @PostMapping("/register") + public AjaxResult register(@RequestBody RegisterBody user) { + if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) { + return error("当前系统没有开启注册功能!"); + } + String msg = registerService.register(user); + return StringUtils.isEmpty(msg) ? success() : error(msg); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/system/SysRoleController.java b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysRoleController.java new file mode 100644 index 0000000..5ea5176 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysRoleController.java @@ -0,0 +1,260 @@ +package com.boyue.web.controller.system; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.entity.SysDept; +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.framework.web.service.SysPermissionService; +import com.boyue.framework.web.service.TokenService; +import com.boyue.system.domain.SysUserRole; +import com.boyue.system.service.ISysDeptService; +import com.boyue.system.service.ISysRoleService; +import com.boyue.system.service.ISysUserService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 角色信息 + * + * @author boyue + */ +@Tag(name = "角色信息") +@RestController +@RequestMapping("/system/role") +public class SysRoleController extends BaseController { + + @Autowired + private ISysRoleService roleService; + + @Autowired + private TokenService tokenService; + + @Autowired + private SysPermissionService permissionService; + + @Autowired + private ISysUserService userService; + + @Autowired + private ISysDeptService deptService; + + @Operation(summary = "获取角色列表") + @PreAuthorize("@ss.hasPermi('system:role:list')") + @GetMapping("/list") + public TableDataInfo list(SysRole role) { + startPage(); + List list = roleService.selectRoleList(role); + return getDataTable(list); + } + + @Operation(summary = "导出角色列表") + @Log(title = "角色管理", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:role:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysRole role) { + List list = roleService.selectRoleList(role); + ExcelUtil util = new ExcelUtil(SysRole.class); + util.exportExcel(response, list, "角色数据"); + } + + /** + * 根据角色编号获取详细信息 + */ + @Operation(summary = "根据角色编号获取详细信息") + @PreAuthorize("@ss.hasPermi('system:role:query')") + @GetMapping(value = "/{roleId}") + public AjaxResult getInfo(@PathVariable(name = "roleId") Long roleId) { + roleService.checkRoleDataScope(roleId); + return success(roleService.selectRoleById(roleId)); + } + + /** + * 新增角色 + */ + @Operation(summary = "新增角色") + @PreAuthorize("@ss.hasPermi('system:role:add')") + @Log(title = "角色管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysRole role) { + if (!roleService.checkRoleNameUnique(role)) { + return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } else if (!roleService.checkRoleKeyUnique(role)) { + return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + role.setCreateBy(getUsername()); + return toAjax(roleService.insertRole(role)); + + } + + /** + * 修改保存角色 + */ + @Operation(summary = "修改保存角色") + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysRole role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + if (!roleService.checkRoleNameUnique(role)) { + return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } else if (!roleService.checkRoleKeyUnique(role)) { + return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + role.setUpdateBy(getUsername()); + + if (roleService.updateRole(role) > 0) { + // 更新缓存用户权限 + LoginUser loginUser = getLoginUser(); + if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin()) { + loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName())); + loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser())); + tokenService.setLoginUser(loginUser); + } + return success(); + } + return error("修改角色'" + role.getRoleName() + "'失败,请联系管理员"); + } + + /** + * 修改保存数据权限 + */ + @Operation(summary = "修改保存数据权限") + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping("/dataScope") + public AjaxResult dataScope(@RequestBody SysRole role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + return toAjax(roleService.authDataScope(role)); + } + + /** + * 状态修改 + */ + @Operation(summary = "状态修改") + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody SysRole role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + role.setUpdateBy(getUsername()); + return toAjax(roleService.updateRoleStatus(role)); + } + + /** + * 删除角色 + */ + @Operation(summary = "删除角色") + @PreAuthorize("@ss.hasPermi('system:role:remove')") + @Log(title = "角色管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{roleIds}") + public AjaxResult remove(@PathVariable(name = "roleIds") Long[] roleIds) { + return toAjax(roleService.deleteRoleByIds(roleIds)); + } + + /** + * 获取角色选择框列表 + */ + @Operation(summary = "获取角色选择框列表") + @PreAuthorize("@ss.hasPermi('system:role:query')") + @GetMapping("/optionselect") + public AjaxResult optionselect() { + return success(roleService.selectRoleAll()); + } + + /** + * 查询已分配用户角色列表 + */ + @Operation(summary = "查询已分配用户角色列表") + @PreAuthorize("@ss.hasPermi('system:role:list')") + @GetMapping("/authUser/allocatedList") + public TableDataInfo allocatedList(SysUser user) { + startPage(); + List list = userService.selectAllocatedList(user); + return getDataTable(list); + } + + /** + * 查询未分配用户角色列表 + */ + @Operation(summary = "查询未分配用户角色列表") + @PreAuthorize("@ss.hasPermi('system:role:list')") + @GetMapping("/authUser/unallocatedList") + public TableDataInfo unallocatedList(SysUser user) { + startPage(); + List list = userService.selectUnallocatedList(user); + return getDataTable(list); + } + + /** + * 取消授权用户 + */ + @Operation(summary = "取消授权用户") + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancel") + public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole) { + return toAjax(roleService.deleteAuthUser(userRole)); + } + + /** + * 批量取消授权用户 + */ + @Operation(summary = "批量取消授权用户") + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancelAll") + public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds) { + return toAjax(roleService.deleteAuthUsers(roleId, userIds)); + } + + /** + * 批量选择用户授权 + */ + @Operation(summary = "批量选择用户授权") + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/selectAll") + public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds) { + roleService.checkRoleDataScope(roleId); + return toAjax(roleService.insertAuthUsers(roleId, userIds)); + } + + /** + * 获取对应角色部门树列表 + */ + @Operation(summary = "获取对应角色部门树列表") + @PreAuthorize("@ss.hasPermi('system:role:query')") + @GetMapping(value = "/deptTree/{roleId}") + public AjaxResult deptTree(@PathVariable("roleId") Long roleId) { + AjaxResult ajax = AjaxResult.success(); + ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId)); + ajax.put("depts", deptService.selectDeptTreeList(new SysDept())); + return ajax; + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/controller/system/SysUserController.java b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysUserController.java new file mode 100644 index 0000000..2b64476 --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/controller/system/SysUserController.java @@ -0,0 +1,247 @@ +package com.boyue.web.controller.system; + +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.entity.SysDept; +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.system.service.ISysDeptService; +import com.boyue.system.service.ISysPostService; +import com.boyue.system.service.ISysRoleService; +import com.boyue.system.service.ISysUserService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 用户信息 + * + * @author boyue + */ +@Tag(name = "用户信息") +@RestController +@RequestMapping("/system/user") +public class SysUserController extends BaseController { + + @Autowired + private ISysUserService userService; + + @Autowired + private ISysRoleService roleService; + + @Autowired + private ISysDeptService deptService; + + @Autowired + private ISysPostService postService; + + /** + * 获取用户列表 + */ + @Operation(summary = "获取用户列表") + @PreAuthorize("@ss.hasPermi('system:user:list')") + @GetMapping("/list") + public TableDataInfo list(SysUser user) { + startPage(); + List list = userService.selectUserList(user); + return getDataTable(list); + } + + @Operation(summary = "导出用户列表") + @Log(title = "用户管理", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:user:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysUser user) { + List list = userService.selectUserList(user); + ExcelUtil util = new ExcelUtil(SysUser.class); + util.exportExcel(response, list, "用户数据"); + } + + @Operation(summary = "导入用户列表") + @Log(title = "用户管理", businessType = BusinessType.IMPORT) + @PreAuthorize("@ss.hasPermi('system:user:import')") + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception { + ExcelUtil util = new ExcelUtil(SysUser.class); + List userList = util.importExcel(file.getInputStream()); + String operName = getUsername(); + String message = userService.importUser(userList, updateSupport, operName); + return success(message); + } + + @Operation(summary = "获取导入用户模板") + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelUtil util = new ExcelUtil(SysUser.class); + util.importTemplateExcel(response, "用户数据"); + } + + /** + * 根据用户编号获取详细信息 + */ + @Operation(summary = "根据用户编号获取详细信息") + @PreAuthorize("@ss.hasPermi('system:user:query')") + @GetMapping(value = { "/", "/{userId}" }) + public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) { + AjaxResult ajax = AjaxResult.success(); + if (StringUtils.isNotNull(userId)) { + userService.checkUserDataScope(userId); + SysUser sysUser = userService.selectUserById(userId); + ajax.put(AjaxResult.DATA_TAG, sysUser); + ajax.put("postIds", postService.selectPostListByUserId(userId)); + ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList())); + } + List roles = roleService.selectRoleAll(); + ajax.put("roles", SysUser.isAdmin(userId) ? roles + : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); + ajax.put("posts", postService.selectPostAll()); + return ajax; + } + + /** + * 新增用户 + */ + @Operation(summary = "新增用户") + @PreAuthorize("@ss.hasPermi('system:user:add')") + @Log(title = "用户管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysUser user) { + if (!userService.checkUserNameUnique(user)) { + return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); + } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { + return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); + } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { + return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + user.setCreateBy(getUsername()); + user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); + return toAjax(userService.insertUser(user)); + } + + /** + * 修改用户 + */ + @Operation(summary = "修改用户") + @PreAuthorize("@ss.hasPermi('system:user:edit')") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysUser user) { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + if (!userService.checkUserNameUnique(user)) { + return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在"); + } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { + return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); + } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { + return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + user.setUpdateBy(getUsername()); + return toAjax(userService.updateUser(user)); + } + + /** + * 删除用户 + */ + @Operation(summary = "删除用户") + @PreAuthorize("@ss.hasPermi('system:user:remove')") + @Log(title = "用户管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{userIds}") + public AjaxResult remove(@PathVariable(name = "userIds") Long[] userIds) { + if (ArrayUtils.contains(userIds, getUserId())) { + return error("当前用户不能删除"); + } + return toAjax(userService.deleteUserByIds(userIds)); + } + + /** + * 重置密码 + */ + @Operation(summary = "重置密码") + @PreAuthorize("@ss.hasPermi('system:user:resetPwd')") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/resetPwd") + public AjaxResult resetPwd(@RequestBody SysUser user) { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); + user.setUpdateBy(getUsername()); + return toAjax(userService.resetPwd(user)); + } + + /** + * 状态修改 + */ + @Operation(summary = "状态修改") + @PreAuthorize("@ss.hasPermi('system:user:edit')") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody SysUser user) { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + user.setUpdateBy(getUsername()); + return toAjax(userService.updateUserStatus(user)); + } + + /** + * 根据用户编号获取授权角色 + */ + @Operation(summary = "根据用户编号获取授权角色") + @PreAuthorize("@ss.hasPermi('system:user:query')") + @GetMapping("/authRole/{userId}") + public AjaxResult authRole(@PathVariable("userId") Long userId) { + AjaxResult ajax = AjaxResult.success(); + SysUser user = userService.selectUserById(userId); + List roles = roleService.selectRolesByUserId(userId); + ajax.put("user", user); + ajax.put("roles", SysUser.isAdmin(userId) ? roles + : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); + return ajax; + } + + /** + * 用户授权角色 + */ + @Operation(summary = "用户授权角色") + @PreAuthorize("@ss.hasPermi('system:user:edit')") + @Log(title = "用户管理", businessType = BusinessType.GRANT) + @PutMapping("/authRole") + public AjaxResult insertAuthRole(Long userId, Long[] roleIds) { + userService.checkUserDataScope(userId); + userService.insertUserAuth(userId, roleIds); + return success(); + } + + /** + * 获取部门树列表 + */ + @Operation(summary = "获取部门树列表") + @PreAuthorize("@ss.hasPermi('system:user:list')") + @GetMapping("/deptTree") + public AjaxResult deptTree(SysDept dept) { + return success(deptService.selectDeptTreeList(dept)); + } +} diff --git a/boyue-admin/src/main/java/com/boyue/web/core/config/SwaggerConfig.java b/boyue-admin/src/main/java/com/boyue/web/core/config/SwaggerConfig.java new file mode 100644 index 0000000..66f8ddf --- /dev/null +++ b/boyue-admin/src/main/java/com/boyue/web/core/config/SwaggerConfig.java @@ -0,0 +1,104 @@ +package com.boyue.web.core.config; + +import org.springdoc.core.models.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.boyue.common.constant.HttpStatus; +import com.boyue.common.core.domain.AjaxResult; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.ExternalDocumentation; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.media.IntegerSchema; +import io.swagger.v3.oas.models.media.ObjectSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.media.StringSchema; + +/** + * 验证码操作处理 + * + * @author Dftre + */ +@Configuration +public class SwaggerConfig { + + @Bean + public OpenAPI springShopOpenApi() { + Schema codeSchema = new IntegerSchema().example(HttpStatus.SUCCESS); // 示例状态码 + Schema msgSchema = new StringSchema().example("操作成功"); // 示例消息 + ObjectSchema dataSchema = new ObjectSchema(); // 数据可以是任意类型,这里简单定义为ObjectSchema + + // 定义AjaxResult的Schema + ObjectSchema ajaxResultSchema = new ObjectSchema(); + ajaxResultSchema.addProperty(AjaxResult.CODE_TAG, codeSchema); + ajaxResultSchema.addProperty(AjaxResult.MSG_TAG, msgSchema); + ajaxResultSchema.addProperty(AjaxResult.DATA_TAG, dataSchema); + Components components = new Components(); + components.addSchemas("AjaxResult", ajaxResultSchema); + + return new OpenAPI() + .components(components) + .info(new Info().title("boyue 二开接口") + .description("boyue 二开接口 API文档") + .version("v1") + .license(new License().name("Apache 2.0").url("http://springdoc.org"))) + .externalDocs(new ExternalDocumentation() + .description("外部文档") + .url("/doc.html")); + } + + @Bean + public GroupedOpenApi sysApi() { + return GroupedOpenApi.builder() + .group("sys系统模块") + .packagesToScan("com.boyue.web.controller.system") + .build(); + } + + @Bean + public GroupedOpenApi commonApi() { + return GroupedOpenApi.builder() + .group("基础模块") + .packagesToScan("com.boyue.web.controller.common") + .build(); + } + + @Bean + public GroupedOpenApi payApi() { + return GroupedOpenApi.builder() + .group("支付模块") + .pathsToMatch("/pay/**") + .build(); + } + + @Bean + public GroupedOpenApi fileApi() { + return GroupedOpenApi.builder() + .group("文件模块") + .packagesToScan("com.boyue.file.controller") + .build(); + } + + @Bean + public GroupedOpenApi authApi() { + return GroupedOpenApi.builder() + .group("认证模块") + .packagesToScan("com.boyue.auth.controller") + .build(); + } + + /** + * 确保扫描到模块化后的司法局模块 + */ + @Bean + public GroupedOpenApi hasfjModelsApi() { + return GroupedOpenApi.builder() + .group("淮安市司法局模块(models)") + .packagesToScan("com.boyue.hasfj.controller") + .pathsToMatch("/hasfj/**") + .build(); + } +} diff --git a/boyue-admin/src/main/resources/META-INF/spring-devtools.properties b/boyue-admin/src/main/resources/META-INF/spring-devtools.properties new file mode 100644 index 0000000..37e7b58 --- /dev/null +++ b/boyue-admin/src/main/resources/META-INF/spring-devtools.properties @@ -0,0 +1 @@ +restart.include.json=/com.alibaba.fastjson2.*.jar \ No newline at end of file diff --git a/boyue-admin/src/main/resources/application-auth.yml b/boyue-admin/src/main/resources/application-auth.yml new file mode 100644 index 0000000..c9109b7 --- /dev/null +++ b/boyue-admin/src/main/resources/application-auth.yml @@ -0,0 +1,37 @@ +# 请输入自己的appid和appsecret +oauth: + wx: + miniapp: + appId: appId + appSecret: appSecret + url: https://api.weixin.qq.com/sns/jscode2session + pub: + appId: appId + appSecret: appSecret + url: https://api.weixin.qq.com/sns/oauth2/access_token + +tfa: + phone: + dysms: + # 阿里云 AccessKey ID + accessKeyId: appId + # 阿里云 AccessKey Secret + accessKeySecret: appSecret + # 短信模板 + template: + VerificationCode: + # 短信模板编码 + templateCode: SMS_123456789 + # 短信签名 + signName: 阿里云短信测试 + # 短信模板必需的数据名称,多个key以逗号分隔,此处配置作为校验 + keys: code + + +spring: + mail: + host: smtp.qq.com + # 邮箱地址 + username: email + # 授权码 + password: password diff --git a/boyue-admin/src/main/resources/application-druid.yml b/boyue-admin/src/main/resources/application-druid.yml new file mode 100644 index 0000000..4df2e13 --- /dev/null +++ b/boyue-admin/src/main/resources/application-druid.yml @@ -0,0 +1,91 @@ +# 数据源配置 +spring: + datasource: + type: com.alibaba.druid.pool.DruidDataSource + driverClassName: com.mysql.cj.jdbc.Driver + dynamic: + primary: MASTER + xa: true + datasource: +# # 主库数据源开发 +# MASTER: +# url: jdbc:mysql://127.0.0.1/boyuehasfj?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 +# username: root +# password: 123456 + # 主库数据源开发 + MASTER: + url: jdbc:mysql://222.184.49.22:3307/boyuehasfj?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + username: root + password: boyue1!Z +# MASTER: +# url: jdbc:mysql://127.0.0.1/boyuekfcode +# username: root +# password: 123456 + # 从库数据源 + # SLAVE: + # url: jdbc:mysql://127.0.0.1/boyue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + # username: root + # password: 123456 + druid: + # 初始连接数 + initialSize: 5 + # 最小连接池数量 + minIdle: 10 + # 最大连接池数量 + maxActive: 20 + # 配置获取连接等待超时的时间 + maxWait: 60000 + # 配置连接超时时间 + connectTimeout: 30000 + # 配置网络超时时间 + socketTimeout: 60000 + # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + timeBetweenEvictionRunsMillis: 60000 + # 配置一个连接在池中最小生存的时间,单位是毫秒 + minEvictableIdleTimeMillis: 300000 + # 配置一个连接在池中最大生存的时间,单位是毫秒 + maxEvictableIdleTimeMillis: 900000 + # 配置检测连接是否有效 + validationQuery: SELECT 1 + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + # 配置监控统计拦截的filters stat=>监控统计 wall=>防SQL注入 slf4j log4j2=>日志记录 + filters: stat,wall,slf4j,log4j2 + # 通过connectProperties属性来打开mergeSql功能;慢SQL记录 + connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 + + # 配置spring监控的匹配类 + aop-patterns: com.boyue.*.service.*,com.boyue.*.mapper.* + + + # Web应用 和 URL监控 配置 + web-stat-filter: + enabled: true + url-pattern: /* + exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" + session-stat-enable: false # 是否开启session统计功能 + + # 监控视图配置 + stat-view-servlet: + enabled: true + url-pattern: /druid/* + reset-enable: true # 是否可以重置日志 + login-username: boyue # 用户名 + login-password: boyue123 # 密码 + allow: "" # IP白名单 (没有配置或者为空,则允许所有访问) + deny: "" # IP黑名单 (存在共同时,deny优先于allow) + filter: + stat: + enabled: true + # 慢SQL记录 + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true + +# 是否开启分布式事务,如不开启,请删除atomikos插件,否则atomikos相关驱动虽不生效但仍会启动 +atomikos: + enabled: false \ No newline at end of file diff --git a/boyue-admin/src/main/resources/application-file.yml b/boyue-admin/src/main/resources/application-file.yml new file mode 100644 index 0000000..173cccc --- /dev/null +++ b/boyue-admin/src/main/resources/application-file.yml @@ -0,0 +1,53 @@ +# local配置 +local: + enable: true + primary: MASTER + client: + MASTER: + permission: public + path: /data/files/master + # 建议public权限的api以 /profile开头就不需要再从SecurityConfig配置权限了 + api: /profile/files/master + # SLAVE: + # permission: private + # path: /data/files/slave + # private需要自己编写一个api例如FileController中的/file/resource + # api: /file/resource + +# Minio配置 +minio: + enable: false + primary: MASTER + client: + MASTER: + permission: public + url: http://localhost:9000 + accessKey: + secretKey: + bucketName: boyue + # SLAVE: + # permission: private + # url: http://localhost:9000 + # accessKey: minioadmin + # secretKey: minioadmin + # bucketName: ry + +# oss配置 +oss: + enable: false + primary: MASTER + client: + MASTER: + permission: public + accessKeyId: accessKeyId + accessKeySecret: accessKeySecret + bucketName: boyue + endpoint: oss-cn-beijing.aliyuncs.com + # SLAVE: + # permission: private + # accessKeyId: + # accessKeySecret: + # bucketName: + # endpoint: + + diff --git a/boyue-admin/src/main/resources/application-lp.yml b/boyue-admin/src/main/resources/application-lp.yml new file mode 100644 index 0000000..66ea810 --- /dev/null +++ b/boyue-admin/src/main/resources/application-lp.yml @@ -0,0 +1,7 @@ +netty: + websocket: + maxMessageSize: 65536 + bossThreads: 4 + workerThreads: 16 + port: 8081 + enable: true \ No newline at end of file diff --git a/boyue-admin/src/main/resources/application-middleware.yml b/boyue-admin/src/main/resources/application-middleware.yml new file mode 100644 index 0000000..f347d74 --- /dev/null +++ b/boyue-admin/src/main/resources/application-middleware.yml @@ -0,0 +1,39 @@ +spring: + data: + # redis 配置 + redis: + # 地址 开发环境 +# host: localhost + # 地址 生产环境 + host: 222.184.49.22 + + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 0 + # 密码 开发环境 +# password: 123456 + # 密码 生产环境 + password: boyue123 + # 连接超时时间 + timeout: 10s + lettuce: + pool: + # 连接池中的最小空闲连接 + min-idle: 0 + # 连接池中的最大空闲连接 + max-idle: 8 + # 连接池的最大数据库连接数 + max-active: 8 + # #连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1ms + + #配置rabbitMq 服务器 + rabbitmq: + enable: false + host: 127.0.0.1 + port: 5672 + username: guest + password: guest + + diff --git a/boyue-admin/src/main/resources/application-mybatis.yml b/boyue-admin/src/main/resources/application-mybatis.yml new file mode 100644 index 0000000..111eced --- /dev/null +++ b/boyue-admin/src/main/resources/application-mybatis.yml @@ -0,0 +1,27 @@ +# PageHelper分页插件 +pagehelper: + helperDialect: mysql + supportMethodsArguments: true + params: count=countSql + +createSqlSessionFactory: + # 选择MyBatis配置方式,mybatis / mybatis-plus + use: mybatis-plus + +# MyBatis配置 +mybatis: + # 搜索指定包别名 + typeAliasesPackage: com.boyue.**.domain + # 配置mapper的扫描,找到所有的mapper.xml映射文件 + mapperLocations: classpath*:mapper/**/*Mapper.xml + # 加载全局的配置文件 + configLocation: classpath:mybatis/mybatis-config.xml + +# MyBatis Plus配置 +mybatis-plus: + # 搜索指定包别名 + typeAliasesPackage: com.boyue.**.domain + # 配置mapper的扫描,找到所有的mapper.xml映射文件 + mapperLocations: classpath*:mapper/**/*Mapper.xml + # 加载全局的配置文件 + configLocation: classpath:mybatis/mybatis-config.xml diff --git a/boyue-admin/src/main/resources/application-pay.yml b/boyue-admin/src/main/resources/application-pay.yml new file mode 100644 index 0000000..58a297e --- /dev/null +++ b/boyue-admin/src/main/resources/application-pay.yml @@ -0,0 +1,30 @@ +# 当前支付模块写的并不完善,请根据自己的业务需求进行修改 +# 回调地址使用的内网穿透http://e2vca6.natappfree.cc +pay: + # https://doc.shouqianba.com/zh-cn/ + sqb: + enabled: false + appId: "appId" + apiDomain: "apiDomain" + terminalSn: "terminalSn" + terminalKey: "terminalKey" + vendorSn: "vendorSn" + vendorKey: "vendorKey" + publicKey: classpath:pay/sqb/sqb_public_key.pem + notifyUrl: http://e2vca6.natappfree.cc/pay/sqb/notify + # https://opendocs.alipay.com/open/02np95 + alipay: + enabled: false + appId: appid + appPrivateKey: classpath:pay/alipay/alipay_private_key.pem + alipayPublicKey: classpath:pay/alipay/alipay_public_key.pem + notifyUrl: http://e2vca6.natappfree.cc/alipay/notify + # https://github.com/wechatpay-apiv3/wechatpay-java + wechat: + enabled: false + appId: appid + apiV3Key: apiV3Key + privateKeyPath: classpath:pay/wx/apiclient_key.pem + merchantId: merchantId + merchantSerialNumber: merchantSerialNumber + notifyUrl: http://e2vca6.natappfree.cc/pay/wechat/notify diff --git a/boyue-admin/src/main/resources/application.yml b/boyue-admin/src/main/resources/application.yml new file mode 100644 index 0000000..6a64fec --- /dev/null +++ b/boyue-admin/src/main/resources/application.yml @@ -0,0 +1,121 @@ +# 项目相关配置 +boyue: + # 名称 + name: boyue + # 版本 + version: 3.8.5 + # 版权年份 + copyrightYear: 2025 + # 文件路径 示例( Windows配置D:/boyue/uploadPath,Linux配置 /home/boyue/uploadPath) +# profile: D:/boyue/hasfj/uploadPath + profile: /home/boyue/hasfj/uploadPath + # 获取ip地址开关 + addressEnabled: false + # 验证码类型 math 数组计算 char 字符验证 + captchaType: math + # 指定默认文件服务类型(值为local代表使用本地作为文件操作服务,minio代表使用minio作为文件操作服务,oss代表使用oss作为文件操作服务) + fileServer: local + # 指定默认文件上传方法最大文件大小(MB) + fileMaxSize: 500 + +# 开发环境配置 +server: + # 服务器的HTTP端口,默认为8080 + port: 9799 + servlet: + # 应用的访问路径 + context-path: / + tomcat: + # tomcat的URI编码 + uri-encoding: UTF-8 + # 连接数满后的排队数,默认为100 + accept-count: 1000 + threads: + # tomcat最大线程数,默认为200 + max: 800 + # Tomcat启动初始化的线程数,默认值10 + min-spare: 100 + +# 日志配置 +logging: + level: + "[com.boyue]": DEBUG + "[org]": WARN + "[org.springframework]": WARN + "[org.apache]": WARN + "[org.springframework.context.support.PostProcessorRegistrationDelegate]": ERROR + "[com.alibaba.druid.spring.boot3.autoconfigure.stat.DruidSpringAopConfiguration]": ERROR + "[com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties]": ERROR + +# 用户配置 +user: + password: + # 密码最大错误次数 + maxRetryCount: 5 + # 密码锁定时间(默认10分钟) + lockTime: 10 + ip: + maxRetryCount: 15 + lockTime: 15 + +# Spring配置 +spring: + #给项目来个名字 + application: + name: boyue + cache: + # 指定缓存类型 jcache 本地缓存 redis 缓存 + type: redis + redis: + # 指定存活时间(ms) + time-to-live: 86400000 + # 指定前缀 + use-key-prefix: true + # 是否缓存空值,可以防止缓存穿透 + cache-null-values: true + mvc: + pathmatch: + matching-strategy: ANT_PATH_MATCHER + # 资源信息 + messages: + # 国际化资源文件路径 + basename: i18n/messages + profiles: + active: druid,mybatis,auth,pay,middleware,lp,file + # 文件上传 + servlet: + multipart: + # 单个文件大小 + max-file-size: 100MB + # 设置总上传的文件大小 + max-request-size: 200MB + # 服务模块 + devtools: + restart: + # 热部署开关 + enabled: true + +# token配置 +token: + # 令牌自定义标识 + header: Authorization + # 令牌密钥 + secret: abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz + # 令牌有效期(默认30分钟) + expireTime: 30 + +# Swagger配置 +swagger: + # 是否开启swagger + enabled: true + # 请求前缀 + pathMapping: /dev-api + +# 防止XSS攻击 +xss: + # 过滤开关 + enabled: true + # 排除链接(多个用逗号分隔) + excludes: /system/notice + # 匹配链接 + urlPatterns: /system/*,/monitor/*,/tool/* \ No newline at end of file diff --git a/boyue-admin/src/main/resources/banner.txt b/boyue-admin/src/main/resources/banner.txt new file mode 100644 index 0000000..a961e09 --- /dev/null +++ b/boyue-admin/src/main/resources/banner.txt @@ -0,0 +1,24 @@ +Application Version: ${boyue.version} +Spring Boot Version: ${spring-boot.version} +//////////////////////////////////////////////////////////////////// +// _ooOoo_ // +// o8888888o // +// 88" . "88 // +// (| ^_^ |) // +// O\ = /O // +// ____/`---'\____ // +// .' \\| |// `. // +// / \\||| : |||// \ // +// / _||||| -:- |||||- \ // +// | | \\\ - /// | | // +// | \_| ''\---/'' | | // +// \ .-\__ `-` ___/-. / // +// ___`. .' /--.--\ `. . ___ // +// ."" '< `.___\_<|>_/___.' >'"". // +// | | : `- \`.;`\ _ /`;.`/ - ` : | | // +// \ \ `-. \_ __\ /__ _/ .-` / / // +// ========`-.____`-.___\_____/___.-`____.-'======== // +// `=---=' // +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // +// 佛祖保佑 永不宕机 永无BUG // +//////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/boyue-admin/src/main/resources/i18n/messages.properties b/boyue-admin/src/main/resources/i18n/messages.properties new file mode 100644 index 0000000..93de005 --- /dev/null +++ b/boyue-admin/src/main/resources/i18n/messages.properties @@ -0,0 +1,38 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=用户不存在/密码错误 +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 +user.password.delete=对不起,您的账号已被删除 +user.blocked=用户已封禁,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +login.blocked=很遗憾,访问IP已被列入系统黑名单 +user.logout.success=退出成功 + +length.not.valid=长度必须在{min}到{max}个字符之间 + +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.password.not.valid=* 5-50个字符 + +user.email.not.valid=邮箱格式错误 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 + +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{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}] diff --git a/boyue-admin/src/main/resources/logback.xml b/boyue-admin/src/main/resources/logback.xml new file mode 100644 index 0000000..33526c1 --- /dev/null +++ b/boyue-admin/src/main/resources/logback.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + ${log.pattern} + + + + + + ${log.path}/sys-info.log + + + + ${log.path}/sys-info.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + INFO + + ACCEPT + + DENY + + + + + ${log.path}/sys-error.log + + + + ${log.path}/sys-error.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + ERROR + + ACCEPT + + DENY + + + + + + ${log.path}/sys-user.log + + + ${log.path}/sys-user.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/boyue-admin/src/main/resources/mybatis/mybatis-config.xml b/boyue-admin/src/main/resources/mybatis/mybatis-config.xml new file mode 100644 index 0000000..d19ff94 --- /dev/null +++ b/boyue-admin/src/main/resources/mybatis/mybatis-config.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/boyue-admin/src/main/resources/templates/hasfj/case.html b/boyue-admin/src/main/resources/templates/hasfj/case.html new file mode 100644 index 0000000..667061a --- /dev/null +++ b/boyue-admin/src/main/resources/templates/hasfj/case.html @@ -0,0 +1,71 @@ + + + + + + 典型案例 + + + + + + + +
+
+
+

典型案例标题

+
+
+ 发布时间:2025-05-28 + | + 作者:管理员 + | + 浏览次数:0 +
+
+ 案例摘要:这是一个典型案例的摘要描述... +
+
+ +

典型案例内容将在这里显示...

+
+
+
+ + + + + \ No newline at end of file diff --git a/boyue-admin/src/main/resources/templates/hasfj/case_list.html b/boyue-admin/src/main/resources/templates/hasfj/case_list.html new file mode 100644 index 0000000..4e91f91 --- /dev/null +++ b/boyue-admin/src/main/resources/templates/hasfj/case_list.html @@ -0,0 +1,80 @@ + + + + + + 典型案例列表 - 淮安市司法局 + + + + + + + +
+
+ + +
+ +
+ + +
+
+ + + + + \ No newline at end of file diff --git a/boyue-admin/src/main/resources/templates/hasfj/form.html b/boyue-admin/src/main/resources/templates/hasfj/form.html new file mode 100644 index 0000000..7c087cd --- /dev/null +++ b/boyue-admin/src/main/resources/templates/hasfj/form.html @@ -0,0 +1,74 @@ + + + + + + 表单下载 + + + + + + + +
+
+
+

表单下载标题

+
+
+ 发布时间:2025-05-28 + | + 作者:管理员 + | + 浏览次数:0 +
+
+ +

表单说明内容将在这里显示...

+
+ +
+
+ + + + + \ No newline at end of file diff --git a/boyue-admin/src/main/resources/templates/hasfj/form_list.html b/boyue-admin/src/main/resources/templates/hasfj/form_list.html new file mode 100644 index 0000000..e90f73e --- /dev/null +++ b/boyue-admin/src/main/resources/templates/hasfj/form_list.html @@ -0,0 +1,86 @@ + + + + + + 表单下载列表 - 淮安市司法局 + + + + + + + +
+
+ + +
+ +
+ + +
+
+ + + + + \ No newline at end of file diff --git a/boyue-admin/src/main/resources/templates/hasfj/index.html b/boyue-admin/src/main/resources/templates/hasfj/index.html new file mode 100644 index 0000000..188e2f5 --- /dev/null +++ b/boyue-admin/src/main/resources/templates/hasfj/index.html @@ -0,0 +1,225 @@ + + + + + + 淮安市司法局 + + + + + + + +
+
+ + + +
+ +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+
+
+
+ +
+
+
+
+
法律规定
+

查看最新的法律法规和相关规定

+ 查看详情 +
+
+
+
+
+
+
典型案例
+

浏览各类典型法律案例分析

+ 查看详情 +
+
+
+
+
+
+
表单下载
+

下载各类法律相关表单

+ 查看详情 +
+
+
+
+ + + + + + \ No newline at end of file diff --git a/boyue-admin/src/main/resources/templates/hasfj/law.html b/boyue-admin/src/main/resources/templates/hasfj/law.html new file mode 100644 index 0000000..6ac8650 --- /dev/null +++ b/boyue-admin/src/main/resources/templates/hasfj/law.html @@ -0,0 +1,61 @@ + + + + + + 法律规定 + + + + + + + +
+
+
+

法律规定标题

+
+
+ 发布时间:2025-05-28 + | + 作者:管理员 + | + 浏览次数:0 +
+
+ +

法律规定内容将在这里显示...

+
+
+
+ + + + + \ No newline at end of file diff --git a/boyue-admin/src/main/resources/templates/hasfj/law_list.html b/boyue-admin/src/main/resources/templates/hasfj/law_list.html new file mode 100644 index 0000000..27f6706 --- /dev/null +++ b/boyue-admin/src/main/resources/templates/hasfj/law_list.html @@ -0,0 +1,80 @@ + + + + + + 法律规定列表 - 淮安市司法局 + + + + + + + +
+
+ + +
+ +
+ + +
+
+ + + + + \ No newline at end of file diff --git a/boyue-admin/src/main/resources/vite.config.ts b/boyue-admin/src/main/resources/vite.config.ts new file mode 100644 index 0000000..4a7ef67 --- /dev/null +++ b/boyue-admin/src/main/resources/vite.config.ts @@ -0,0 +1,32 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueJsx from '@vitejs/plugin-vue-jsx' + +// https://vitejs.dev/config/ +export default defineConfig({ + server: { + port: 80, + proxy: { + '/dev-api': { + target: 'http://localhost:8080', + changeOrigin: true, + rewrite: (path) => path.replace(/^\/dev-api/, '') + }, + '/profile': { + target: 'http://localhost:8080', + changeOrigin: true + } + } + }, + plugins: [ + vue(), + vueJsx(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) \ No newline at end of file diff --git a/boyue-auth/boyue-auth-common/pom.xml b/boyue-auth/boyue-auth-common/pom.xml new file mode 100644 index 0000000..b4220a6 --- /dev/null +++ b/boyue-auth/boyue-auth-common/pom.xml @@ -0,0 +1,33 @@ + + + + boyue-auth + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-auth-common + + + system系统模块 + + + + + + + com.boyue + boyue-framework + + + + + org.apache.httpcomponents + httpclient + + + + + \ No newline at end of file diff --git a/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/domain/OauthUser.java b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/domain/OauthUser.java new file mode 100644 index 0000000..9a53fa7 --- /dev/null +++ b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/domain/OauthUser.java @@ -0,0 +1,293 @@ +package com.boyue.auth.common.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 第三方认证对象 oauth_user + * + * @author Dftre + * @date 2024-01-18 + */ +@Schema(description = "第三方认证对象") +public class OauthUser extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** 主键 */ + @Schema(title = "主键") + private Long id; + + /** 第三方系统的唯一ID,详细解释请参考:名词解释 */ + @Schema(title = "第三方系统的唯一ID,详细解释请参考:名词解释") + @Excel(name = "第三方系统的唯一ID,详细解释请参考:名词解释") + private String uuid; + + /** 用户ID */ + @Schema(title = "用户ID") + @Excel(name = "用户ID") + private Long userId; + + /** + * 第三方用户来源,可选值:GITHUB、GITEE、QQ,更多请参考:AuthDefaultSource.java(opens new window) + */ + @Schema(title = "第三方用户来源,可选值:GITHUB、GITEE、QQ,更多请参考:AuthDefaultSource.java(opens new window)") + @Excel(name = "第三方用户来源,可选值:GITHUB、GITEE、QQ,更多请参考:AuthDefaultSource.java(opens new window)") + private String source; + + /** 用户的授权令牌 */ + @Schema(title = "用户的授权令牌") + @Excel(name = "用户的授权令牌") + private String accessToken; + + /** 第三方用户的授权令牌的有效期,部分平台可能没有 */ + @Schema(title = "第三方用户的授权令牌的有效期,部分平台可能没有") + @Excel(name = "第三方用户的授权令牌的有效期,部分平台可能没有") + private Long expireIn; + + /** 刷新令牌,部分平台可能没有 */ + @Schema(title = "刷新令牌,部分平台可能没有") + @Excel(name = "刷新令牌,部分平台可能没有") + private String refreshToken; + + /** 第三方用户的 open id,部分平台可能没有 */ + @Schema(title = "第三方用户的 open id,部分平台可能没有") + @Excel(name = "第三方用户的 open id,部分平台可能没有") + private String openId; + + /** 第三方用户的 ID,部分平台可能没有 */ + @Schema(title = "第三方用户的 ID,部分平台可能没有") + @Excel(name = "第三方用户的 ID,部分平台可能没有") + private String uid; + + /** 个别平台的授权信息,部分平台可能没有 */ + @Schema(title = "个别平台的授权信息,部分平台可能没有") + @Excel(name = "个别平台的授权信息,部分平台可能没有") + private String accessCode; + + /** 第三方用户的 union id,部分平台可能没有 */ + @Schema(title = "第三方用户的 union id,部分平台可能没有") + @Excel(name = "第三方用户的 union id,部分平台可能没有") + private String unionId; + + /** 第三方用户授予的权限,部分平台可能没有 */ + @Schema(title = "第三方用户授予的权限,部分平台可能没有") + @Excel(name = "第三方用户授予的权限,部分平台可能没有") + private String scope; + + /** 个别平台的授权信息,部分平台可能没有 */ + @Schema(title = "个别平台的授权信息,部分平台可能没有") + @Excel(name = "个别平台的授权信息,部分平台可能没有") + private String tokenType; + + /** id token,部分平台可能没有 */ + @Schema(title = "id token,部分平台可能没有") + @Excel(name = "id token,部分平台可能没有") + private String idToken; + + /** 小米平台用户的附带属性,部分平台可能没有 */ + @Schema(title = "小米平台用户的附带属性,部分平台可能没有") + @Excel(name = "小米平台用户的附带属性,部分平台可能没有") + private String macAlgorithm; + + /** 小米平台用户的附带属性,部分平台可能没有 */ + @Schema(title = "小米平台用户的附带属性,部分平台可能没有") + @Excel(name = "小米平台用户的附带属性,部分平台可能没有") + private String macKey; + + /** 用户的授权code,部分平台可能没有 */ + @Schema(title = "用户的授权code,部分平台可能没有") + @Excel(name = "用户的授权code,部分平台可能没有") + private String code; + + /** Twitter平台用户的附带属性,部分平台可能没有 */ + @Schema(title = "Twitter平台用户的附带属性,部分平台可能没有") + @Excel(name = "Twitter平台用户的附带属性,部分平台可能没有") + private String oauthToken; + + /** Twitter平台用户的附带属性,部分平台可能没有 */ + @Schema(title = "Twitter平台用户的附带属性,部分平台可能没有") + @Excel(name = "Twitter平台用户的附带属性,部分平台可能没有") + private String oauthTokenSecret; + + public void setId(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getUuid() { + return uuid; + } + + public void setUserId(Long userId) { + this.userId = userId; + } + + public Long getUserId() { + return userId; + } + + public void setSource(String source) { + this.source = source; + } + + public String getSource() { + return source; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public String getAccessToken() { + return accessToken; + } + + public void setExpireIn(Long expireIn) { + this.expireIn = expireIn; + } + + public Long getExpireIn() { + return expireIn; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } + + public String getRefreshToken() { + return refreshToken; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getOpenId() { + return openId; + } + + public void setUid(String uid) { + this.uid = uid; + } + + public String getUid() { + return uid; + } + + public void setAccessCode(String accessCode) { + this.accessCode = accessCode; + } + + public String getAccessCode() { + return accessCode; + } + + public void setUnionId(String unionId) { + this.unionId = unionId; + } + + public String getUnionId() { + return unionId; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public String getScope() { + return scope; + } + + public void setTokenType(String tokenType) { + this.tokenType = tokenType; + } + + public String getTokenType() { + return tokenType; + } + + public void setIdToken(String idToken) { + this.idToken = idToken; + } + + public String getIdToken() { + return idToken; + } + + public void setMacAlgorithm(String macAlgorithm) { + this.macAlgorithm = macAlgorithm; + } + + public String getMacAlgorithm() { + return macAlgorithm; + } + + public void setMacKey(String macKey) { + this.macKey = macKey; + } + + public String getMacKey() { + return macKey; + } + + public void setCode(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + + public void setOauthToken(String oauthToken) { + this.oauthToken = oauthToken; + } + + public String getOauthToken() { + return oauthToken; + } + + public void setOauthTokenSecret(String oauthTokenSecret) { + this.oauthTokenSecret = oauthTokenSecret; + } + + public String getOauthTokenSecret() { + return oauthTokenSecret; + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("uuid", getUuid()) + .append("userId", getUserId()) + .append("source", getSource()) + .append("accessToken", getAccessToken()) + .append("expireIn", getExpireIn()) + .append("refreshToken", getRefreshToken()) + .append("openId", getOpenId()) + .append("uid", getUid()) + .append("accessCode", getAccessCode()) + .append("unionId", getUnionId()) + .append("scope", getScope()) + .append("tokenType", getTokenType()) + .append("idToken", getIdToken()) + .append("macAlgorithm", getMacAlgorithm()) + .append("macKey", getMacKey()) + .append("code", getCode()) + .append("oauthToken", getOauthToken()) + .append("oauthTokenSecret", getOauthTokenSecret()) + .toString(); + } +} diff --git a/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/enums/OauthVerificationUse.java b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/enums/OauthVerificationUse.java new file mode 100644 index 0000000..5b5131f --- /dev/null +++ b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/enums/OauthVerificationUse.java @@ -0,0 +1,59 @@ +package com.boyue.auth.common.enums; + +public enum OauthVerificationUse { + + /** 用于登录 */ + LOGIN("登录", "login"), + /** 用于注册 */ + REGISTER("注册", "register"), + /** 用于禁用 */ + DISABLE("禁用", "disable"), + /** 用于重置信息 */ + RESET("重置", "reset"), + /** 用于绑定信息 */ + BIND("绑定", "bind"), + /** 其他用途 */ + OTHER("其他", "other"); + + private String name; + private String value; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public static OauthVerificationUse getByValue(String value) { + for (OauthVerificationUse use : OauthVerificationUse.values()) { + if (use.getValue().equals(value)) { + return use; + } + } + return null; + } + + public static OauthVerificationUse getByName(String name) { + for (OauthVerificationUse use : OauthVerificationUse.values()) { + if (use.getName().equals(name)) { + return use; + } + } + return null; + } + + private OauthVerificationUse(String name, String value) { + this.name = name; + this.value = value; + } +} diff --git a/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/mapper/OauthUserMapper.java b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/mapper/OauthUserMapper.java new file mode 100644 index 0000000..12aafe3 --- /dev/null +++ b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/mapper/OauthUserMapper.java @@ -0,0 +1,112 @@ +package com.boyue.auth.common.mapper; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.boyue.auth.common.domain.OauthUser; + +/** + * 第三方认证Mapper接口 + * + * @author Dftre + * @date 2024-01-18 + */ +public interface OauthUserMapper { + /** + * 查询第三方认证 + * + * @param id 第三方认证主键 + * @return 第三方认证 + */ + public OauthUser selectOauthUserById(Long id); + + public OauthUser selectOauthUserByUserId(Long userId); + + /** + * 查询第三方认证 + * 钉钉、抖音:uuid 为用户的 unionid + * 微信公众平台登录、京东、酷家乐、美团:uuid 为用户的 openId + * 微信开放平台登录、QQ:uuid 为用户的 openId,平台支持获取unionid, unionid 在 AuthToken + * 中(如果支持),在登录完成后,可以通过 response.getData().getToken().getUnionId() 获取 + * Google:uuid 为用户的 sub,sub为Google的所有账户体系中用户唯一的身份标识符,详见:OpenID Connect + * + * @param uuid + * @return + */ + public OauthUser selectOauthUserByUUID(String uuid); + + /** + * 查询第三方认证列表 + * + * @param oauthUser 第三方认证 + * @return 第三方认证集合 + */ + public List selectOauthUserList(OauthUser oauthUser); + + /** + * 新增第三方认证 + * + * @param oauthUser 第三方认证 + * @return 结果 + */ + public int insertOauthUser(OauthUser oauthUser); + + /** + * 修改第三方认证 + * + * @param oauthUser 第三方认证 + * @return 结果 + */ + public int updateOauthUser(OauthUser oauthUser); + + /** + * 删除第三方认证 + * + * @param id 第三方认证主键 + * @return 结果 + */ + public int deleteOauthUserById(Long id); + + /** + * 批量删除第三方认证 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteOauthUserByIds(Long[] ids); + + /** + * 校验source平台是否绑定 + * + * @param userId 用户编号 + * @param source 绑定平台 + * @return 结果 + */ + public int checkAuthUser(@Param("userId") Long userId, @Param("source") String source); + + /** + * 校验用户名称是否唯一 + * + * @param userName 用户名称 + * @return 结果 + */ + public int checkUserNameUnique(String userName); + + /** + * 校验手机号码是否唯一 + * + * @param phonenumber 手机号码 + * @return 结果 + */ + public int checkPhoneUnique(String phonenumber); + + /** + * 校验email是否唯一 + * + * @param email 用户邮箱 + * @return 结果 + */ + public int checkEmailUnique(String email); + +} diff --git a/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/service/IOauthUserService.java b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/service/IOauthUserService.java new file mode 100644 index 0000000..8c86e9b --- /dev/null +++ b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/service/IOauthUserService.java @@ -0,0 +1,102 @@ +package com.boyue.auth.common.service; + +import java.util.List; + +import com.boyue.auth.common.domain.OauthUser; +import com.boyue.common.core.domain.entity.SysUser; + +/** + * 第三方认证Service接口 + * + * @author Dftre + * @date 2024-01-18 + */ +public interface IOauthUserService { + /** + * 查询第三方认证 + * + * @param id 第三方认证主键 + * @return 第三方认证 + */ + public OauthUser selectOauthUserById(Long id); + + public OauthUser selectOauthUserByUUID(String uuid); + + public OauthUser selectOauthUserByUserId(Long userId); + + public SysUser selectSysUserByUUID(String uuid); + + /** + * 查询第三方认证列表 + * + * @param oauthUser 第三方认证 + * @return 第三方认证集合 + */ + public List selectOauthUserList(OauthUser oauthUser); + + /** + * 新增第三方认证 + * + * @param oauthUser 第三方认证 + * @return 结果 + */ + public int insertOauthUser(OauthUser oauthUser); + + /** + * 修改第三方认证 + * + * @param oauthUser 第三方认证 + * @return 结果 + */ + public int updateOauthUser(OauthUser oauthUser); + + /** + * 批量删除第三方认证 + * + * @param ids 需要删除的第三方认证主键集合 + * @return 结果 + */ + public int deleteOauthUserByIds(Long[] ids); + + /** + * 删除第三方认证信息 + * + * @param id 第三方认证主键 + * @return 结果 + */ + public int deleteOauthUserById(Long id); + + /** + * 校验source平台是否绑定 + * + * @param userId 用户编号 + * @param source 绑定平台 + * @return 结果 + */ + public boolean checkAuthUser(Long userId, String source); + + /** + * 校验用户名称是否唯一 + * + * @param userName 用户名称 + * @return 结果 + */ + public boolean checkUserNameUnique(String userName); + + /** + * 校验手机号码是否唯一 + * + * @param phonenumber 手机号码 + * @return 结果 + */ + public boolean checkPhoneUnique(String phonenumber); + + /** + * 校验email是否唯一 + * + * @param email 用户邮箱 + * @return 结果 + */ + public boolean checkEmailUnique(String email); + +} diff --git a/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/service/OauthVerificationCodeService.java b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/service/OauthVerificationCodeService.java new file mode 100644 index 0000000..880a3c5 --- /dev/null +++ b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/service/OauthVerificationCodeService.java @@ -0,0 +1,15 @@ +package com.boyue.auth.common.service; + +import com.boyue.auth.common.enums.OauthVerificationUse; + +/** + * code认证方式接口 + * + * @author zlh + * @date 2024-04-16 + */ +public interface OauthVerificationCodeService { + public boolean sendCode(String o, String code,OauthVerificationUse use) throws Exception; + public boolean checkCode(String o, String code,OauthVerificationUse use) throws Exception; + +} diff --git a/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/service/TfaService.java b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/service/TfaService.java new file mode 100644 index 0000000..d66755b --- /dev/null +++ b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/service/TfaService.java @@ -0,0 +1,73 @@ +package com.boyue.auth.common.service; + +import com.boyue.common.core.domain.model.LoginBody; +import com.boyue.common.core.domain.model.RegisterBody; + +/** + * 双因素认证(TFA)操作的服务接口。 + * 该接口提供处理TFA绑定、注册和登录流程的方法, + * 包括它们的验证步骤。 + * + *

+ * 双因素认证通过要求用户提供两种不同的认证因素, + * 为认证过程增加了额外的安全层。 + *

+ */ +public interface TfaService { + /** + * 启动将TFA方法绑定到用户账户的流程。 + * + * @param loginBody 包含TFA绑定所需数据的登录信息 + */ + public void doBind(LoginBody loginBody); + + /** + * 使用验证码或其他确认方式验证TFA绑定流程。 + * + * @param loginBody 包含验证数据的登录信息 + */ + public void doBindVerify(LoginBody loginBody); + + /** + * 处理包含TFA设置的注册流程。 + * + * @param registerBody 包含用户详情和TFA设置的注册信息 + */ + public void doRegister(RegisterBody registerBody); + + /** + * 验证包含TFA设置的注册流程。 + * + * @param registerBody 包含验证数据的注册信息 + */ + public void doRegisterVerify(RegisterBody registerBody); + + /** + * 启动TFA登录流程的第一步。 + * + * @param loginBody 包含用户凭证的登录信息 + */ + public void doLogin(LoginBody loginBody); + + /** + * 验证TFA登录流程的第二步并完成认证。 + * + * @param loginBody 包含TFA验证码的登录信息 + * @return 已认证会话的字符串令牌或会话标识符 + */ + public String doLoginVerify(LoginBody loginBody); + + /** + * 启动TFA重置流程的第一步。 + * + * @param registerBody 包含用户凭证的注册信息 + */ + public void doReset(RegisterBody registerBody); + + /** + * 验证TFA重置流程的第二步并完成重置。 + * + * @param registerBody 包含TFA验证码的注册信息 + */ + public void doResetVerify(RegisterBody registerBody); +} diff --git a/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/service/impl/OauthUserServiceImpl.java b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/service/impl/OauthUserServiceImpl.java new file mode 100644 index 0000000..f2d5e59 --- /dev/null +++ b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/service/impl/OauthUserServiceImpl.java @@ -0,0 +1,149 @@ +package com.boyue.auth.common.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.boyue.auth.common.domain.OauthUser; +import com.boyue.auth.common.mapper.OauthUserMapper; +import com.boyue.auth.common.service.IOauthUserService; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.system.mapper.SysUserMapper; + +/** + * 第三方认证Service业务层处理 + * + * @author Dftre + * @date 2024-01-18 + */ +@Service +public class OauthUserServiceImpl implements IOauthUserService { + @Autowired + private OauthUserMapper oauthUserMapper; + + @Autowired + private SysUserMapper sysUserMapper; + + /** + * 查询第三方认证 + * + * @param id 第三方认证主键 + * @return 第三方认证 + */ + @Override + public OauthUser selectOauthUserById(Long id) { + return oauthUserMapper.selectOauthUserById(id); + } + + @Override + public OauthUser selectOauthUserByUUID(String uuid) { + return oauthUserMapper.selectOauthUserByUUID(uuid); + } + + @Override + public OauthUser selectOauthUserByUserId(Long userId) { + return oauthUserMapper.selectOauthUserByUserId(userId); + } + + /** + * 查询第三方认证列表 + * + * @param oauthUser 第三方认证 + * @return 第三方认证 + */ + @Override + public List selectOauthUserList(OauthUser oauthUser) { + return oauthUserMapper.selectOauthUserList(oauthUser); + } + + /** + * 新增第三方认证 + * + * @param oauthUser 第三方认证 + * @return 结果 + */ + @Override + public int insertOauthUser(OauthUser oauthUser) { + return oauthUserMapper.insertOauthUser(oauthUser); + } + + /** + * 修改第三方认证 + * + * @param oauthUser 第三方认证 + * @return 结果 + */ + @Override + public int updateOauthUser(OauthUser oauthUser) { + return oauthUserMapper.updateOauthUser(oauthUser); + } + + /** + * 批量删除第三方认证 + * + * @param ids 需要删除的第三方认证主键 + * @return 结果 + */ + @Override + public int deleteOauthUserByIds(Long[] ids) { + return oauthUserMapper.deleteOauthUserByIds(ids); + } + + /** + * 删除第三方认证信息 + * + * @param id 第三方认证主键 + * @return 结果 + */ + @Override + public int deleteOauthUserById(Long id) { + return oauthUserMapper.deleteOauthUserById(id); + } + + public SysUser selectSysUserByUUID(String uuid) { + OauthUser oauthUser = oauthUserMapper.selectOauthUserByUUID(uuid); + return sysUserMapper.selectUserById(oauthUser.getUserId()); + } + + /** + * 校验source平台是否绑定 + * + * @param userId 用户编号 + * @param source 绑定平台 + * @return 结果 + */ + public boolean checkAuthUser(Long userId, String source) { + return oauthUserMapper.checkAuthUser(userId, source) > 0; + }; + + /** + * 校验用户名称是否唯一 + * + * @param userName 用户名称 + * @return 结果 + */ + public boolean checkUserNameUnique(String userName) { + return oauthUserMapper.checkUserNameUnique(userName) > 0; + }; + + /** + * 校验手机号码是否唯一 + * + * @param phonenumber 手机号码 + * @return 结果 + */ + public boolean checkPhoneUnique(String phonenumber) { + return oauthUserMapper.checkPhoneUnique(phonenumber) > 0; + }; + + /** + * 校验email是否唯一 + * + * @param email 用户邮箱 + * @return 结果 + */ + public boolean checkEmailUnique(String email) { + return oauthUserMapper.checkEmailUnique(email) > 0; + }; +} diff --git a/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/utils/RandomCodeUtil.java b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/utils/RandomCodeUtil.java new file mode 100644 index 0000000..8e09667 --- /dev/null +++ b/boyue-auth/boyue-auth-common/src/main/java/com/boyue/auth/common/utils/RandomCodeUtil.java @@ -0,0 +1,28 @@ +package com.boyue.auth.common.utils; + +import java.security.SecureRandom; + +public class RandomCodeUtil { + + public static String randomString(String characters, int length) { + StringBuilder result = new StringBuilder(); + SecureRandom random = new SecureRandom(); + + for (int i = 0; i < length; i++) { + int index = random.nextInt(characters.length()); + result.append(characters.charAt(index)); + } + + return result.toString(); + } + + public static String numberCode(int length) { + String characters = "0123456789"; + return randomString(characters, length); + } + + public static String code(int length) { + String characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + return randomString(characters, length); + } +} diff --git a/boyue-auth/boyue-auth-common/src/main/resources/mapper/common/OauthUserMapper.xml b/boyue-auth/boyue-auth-common/src/main/resources/mapper/common/OauthUserMapper.xml new file mode 100644 index 0000000..bbf64ad --- /dev/null +++ b/boyue-auth/boyue-auth-common/src/main/resources/mapper/common/OauthUserMapper.xml @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + select id, uuid, user_id, source, access_token, expire_in, refresh_token, open_id, uid, access_code, union_id, scope, token_type, id_token, mac_algorithm, mac_key, code, oauth_token, oauth_token_secret from oauth_user + + + + + + + + + + + + + + + + + + + + insert into oauth_user + + id, + uuid, + user_id, + source, + access_token, + expire_in, + refresh_token, + open_id, + uid, + access_code, + union_id, + scope, + token_type, + id_token, + mac_algorithm, + mac_key, + code, + oauth_token, + oauth_token_secret, + + + #{id}, + #{uuid}, + #{userId}, + #{source}, + #{accessToken}, + #{expireIn}, + #{refreshToken}, + #{openId}, + #{uid}, + #{accessCode}, + #{unionId}, + #{scope}, + #{tokenType}, + #{idToken}, + #{macAlgorithm}, + #{macKey}, + #{code}, + #{oauthToken}, + #{oauthTokenSecret}, + + + + + update oauth_user + + uuid = #{uuid}, + user_id = #{userId}, + source = #{source}, + access_token = #{accessToken}, + expire_in = #{expireIn}, + refresh_token = #{refreshToken}, + open_id = #{openId}, + uid = #{uid}, + access_code = #{accessCode}, + union_id = #{unionId}, + scope = #{scope}, + token_type = #{tokenType}, + id_token = #{idToken}, + mac_algorithm = #{macAlgorithm}, + mac_key = #{macKey}, + code = #{code}, + oauth_token = #{oauthToken}, + oauth_token_secret = #{oauthTokenSecret}, + + where oauth_user.id = #{id} + + + + delete from oauth_user where id = #{id} + + + + delete from oauth_user where id in + + #{id} + + + \ No newline at end of file diff --git a/boyue-auth/boyue-auth-starter/pom.xml b/boyue-auth/boyue-auth-starter/pom.xml new file mode 100644 index 0000000..d46344a --- /dev/null +++ b/boyue-auth/boyue-auth-starter/pom.xml @@ -0,0 +1,50 @@ + + + + boyue-auth + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-auth-starter + + + 第三方认证模块 + + + + + + com.boyue + boyue-auth-common + + + + + com.boyue + boyue-oauth-justauth + + + + + com.boyue + boyue-oauth-wx + + + + + com.boyue + boyue-tfa-phone + + + + + com.boyue + boyue-tfa-email + + + + \ No newline at end of file diff --git a/boyue-auth/boyue-auth-starter/src/main/java/com/boyue/auth/controller/OauthUserController.java b/boyue-auth/boyue-auth-starter/src/main/java/com/boyue/auth/controller/OauthUserController.java new file mode 100644 index 0000000..30e7530 --- /dev/null +++ b/boyue-auth/boyue-auth-starter/src/main/java/com/boyue/auth/controller/OauthUserController.java @@ -0,0 +1,109 @@ +package com.boyue.auth.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.auth.common.domain.OauthUser; +import com.boyue.auth.common.service.IOauthUserService; +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 第三方认证Controller + * + * @author Dftre + * @date 2024-01-18 + */ +@RestController +@RequestMapping("/system/oauth") +@Tag(name = "【第三方认证】管理") +public class OauthUserController extends BaseController { + @Autowired + private IOauthUserService oauthUserService; + + /** + * 查询第三方认证列表 + */ + @Operation(summary = "查询第三方认证列表") + @PreAuthorize("@ss.hasPermi('system:oauth:list')") + @GetMapping("/list") + public TableDataInfo list(OauthUser oauthUser) { + startPage(); + List list = oauthUserService.selectOauthUserList(oauthUser); + return getDataTable(list); + } + + /** + * 导出第三方认证列表 + */ + @Operation(summary = "导出第三方认证列表") + @PreAuthorize("@ss.hasPermi('system:oauth:export')") + @Log(title = "第三方认证", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, OauthUser oauthUser) { + List list = oauthUserService.selectOauthUserList(oauthUser); + ExcelUtil util = new ExcelUtil(OauthUser.class); + util.exportExcel(response, list, "第三方认证数据"); + } + + /** + * 获取第三方认证详细信息 + */ + @Operation(summary = "获取第三方认证详细信息") + @PreAuthorize("@ss.hasPermi('system:oauth:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return success(oauthUserService.selectOauthUserById(id)); + } + + /** + * 新增第三方认证 + */ + @Operation(summary = "新增第三方认证") + @PreAuthorize("@ss.hasPermi('system:oauth:add')") + @Log(title = "第三方认证", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody OauthUser oauthUser) { + return toAjax(oauthUserService.insertOauthUser(oauthUser)); + } + + /** + * 修改第三方认证 + */ + @Operation(summary = "修改第三方认证") + @PreAuthorize("@ss.hasPermi('system:oauth:edit')") + @Log(title = "第三方认证", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody OauthUser oauthUser) { + return toAjax(oauthUserService.updateOauthUser(oauthUser)); + } + + /** + * 删除第三方认证 + */ + @Operation(summary = "删除第三方认证") + @PreAuthorize("@ss.hasPermi('system:oauth:remove')") + @Log(title = "第三方认证", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable(name = "ids") Long[] ids) { + return toAjax(oauthUserService.deleteOauthUserByIds(ids)); + } +} diff --git a/boyue-auth/boyue-auth-starter/src/main/java/com/boyue/auth/controller/TfaController.java b/boyue-auth/boyue-auth-starter/src/main/java/com/boyue/auth/controller/TfaController.java new file mode 100644 index 0000000..dd8fd86 --- /dev/null +++ b/boyue-auth/boyue-auth-starter/src/main/java/com/boyue/auth/controller/TfaController.java @@ -0,0 +1,110 @@ +package com.boyue.auth.controller; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.auth.common.service.TfaService; +import com.boyue.common.annotation.Anonymous; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.model.LoginBody; +import com.boyue.common.core.domain.model.RegisterBody; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.PostConstruct; + +@RestController +@RequestMapping("/auth/{channel}") // dySms mail +@Tag(name = "【第三方认证】双因素认证") +public class TfaController extends BaseController { + + @Autowired(required = false) + Map tfaServiceMap; + + @PostConstruct + public void init() { + if (tfaServiceMap == null) { + tfaServiceMap = new HashMap<>(); + logger.warn("请注意,没有加载任何双认证服务"); + } else { + tfaServiceMap.forEach((k, v) -> { + logger.info("已加载双认证服务 {}", k); + }); + } + } + + @Operation(summary = "发送注册验证码") + @PostMapping("/send/register") + @Anonymous + public AjaxResult sendRegister(@PathVariable String channel, @RequestBody RegisterBody registerBody) { + TfaService tfaService = tfaServiceMap.get("auth:service:" + channel); + tfaService.doRegister(registerBody); + return success(); + } + + @Operation(summary = "验证注册验证码") + @PostMapping("/verify/register") + @Anonymous + public AjaxResult verifyRegister(@PathVariable String channel, @RequestBody RegisterBody registerBody) { + TfaService tfaService = tfaServiceMap.get("auth:service:" + channel); + tfaService.doRegisterVerify(registerBody); + return success(); + } + + @Operation(summary = "发送登录验证码") + @PostMapping("/send/login") + @Anonymous + public AjaxResult sendLogin(@PathVariable String channel, @RequestBody LoginBody loginBody) { + TfaService tfaService = tfaServiceMap.get("auth:service:" + channel); + tfaService.doLogin(loginBody); + return success(); + } + + @Operation(summary = "验证登录验证码") + @PostMapping("/verify/login") + @Anonymous + public AjaxResult verifyLogin(@PathVariable String channel, @RequestBody LoginBody loginBody) { + TfaService tfaService = tfaServiceMap.get("auth:service:" + channel); + return success(tfaService.doLoginVerify(loginBody)); + } + + @Operation(summary = "发送绑定验证码") + @PostMapping("/send/bind") + public AjaxResult send(@PathVariable String channel, @RequestBody LoginBody loginBody) { + TfaService tfaService = tfaServiceMap.get("auth:service:" + channel); + tfaService.doBind(loginBody); + return success(); + } + + @Operation(summary = "验证绑定验证码") + @PostMapping("/verify/bind") // 发送验证码 + public AjaxResult verify(@PathVariable String channel, @RequestBody LoginBody loginBody) { + TfaService tfaService = tfaServiceMap.get("auth:service:" + channel); + tfaService.doBindVerify(loginBody); + return success(); + } + + @Operation(summary = "发送重置验证码") + @PostMapping("/send/reset") + public AjaxResult sendReset(@PathVariable String channel, @RequestBody RegisterBody registerBody) { + TfaService tfaService = tfaServiceMap.get("auth:service:" + channel); + tfaService.doReset(registerBody); + return success(); + } + + @Operation(summary = "验证重置验证码") + @PostMapping("/verify/reset") + public AjaxResult verifyReset(@PathVariable String channel, @RequestBody RegisterBody registerBody) { + TfaService tfaService = tfaServiceMap.get("auth:service:" + channel); + tfaService.doReset(registerBody); + return success(); + } +} diff --git a/boyue-auth/boyue-oauth-justauth/pom.xml b/boyue-auth/boyue-oauth-justauth/pom.xml new file mode 100644 index 0000000..7a7dc98 --- /dev/null +++ b/boyue-auth/boyue-oauth-justauth/pom.xml @@ -0,0 +1,37 @@ + + + + boyue-auth + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-oauth-justauth + + + justauth框架认证模块 + + + + + + + com.boyue + boyue-auth-common + + + + me.zhyd.oauth + JustAuth + + + + com.alipay.sdk + alipay-sdk-java + + + + + \ No newline at end of file diff --git a/boyue-auth/boyue-oauth-justauth/src/main/java/com/boyue/oauth/justauth/controller/SysAuthController.java b/boyue-auth/boyue-oauth-justauth/src/main/java/com/boyue/oauth/justauth/controller/SysAuthController.java new file mode 100644 index 0000000..fc6b583 --- /dev/null +++ b/boyue-auth/boyue-oauth-justauth/src/main/java/com/boyue/oauth/justauth/controller/SysAuthController.java @@ -0,0 +1,180 @@ +package com.boyue.oauth.justauth.controller; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +import com.alibaba.fastjson2.JSONObject; +import com.boyue.auth.common.domain.OauthUser; +import com.boyue.auth.common.service.IOauthUserService; +import com.boyue.common.annotation.Anonymous; +import com.boyue.common.constant.Constants; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.enums.UserStatus; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.framework.web.service.SysPermissionService; +import com.boyue.framework.web.service.TokenService; +import com.boyue.oauth.justauth.utils.JustAuthUtils; +import com.boyue.system.service.ISysUserService; + +import jakarta.servlet.http.HttpServletRequest; +import me.zhyd.oauth.cache.AuthDefaultStateCache; +import me.zhyd.oauth.cache.AuthStateCache; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthRequest; +import me.zhyd.oauth.utils.AuthStateUtils; + +/** + * 第三方认证授权处理 + * + * @author boyue + */ +@RestController +@RequestMapping("/system/auth") +public class SysAuthController extends BaseController +{ + private AuthStateCache authStateCache; + + @Autowired + private ISysUserService userService; + + @Autowired + private SysPermissionService permissionService; + + @Autowired + private TokenService tokenService; + + @Autowired + private IOauthUserService oauthUserService; + + private final static Map auths = new HashMap(); + { + auths.put("gitee", "{\"clientId\":\"d83265831bf1b09765c27a9fd9860a9fbb2d939b13460454e85d3d551eebb157\",\"clientSecret\":\"23e3d066c85fc5ee6eaad91067ad006bb5475796f9b9c024eaf5bd26acadd7a3\",\"redirectUri\":\"http://127.0.0.1:80/social-login?source=gitee\"}"); + auths.put("github", "{\"clientId\":\"Iv1.1be0cdcd71aca63b\",\"clientSecret\":\"0d59d28b43152bc8906011624db37b0fed88d154\",\"redirectUri\":\"http://127.0.0.1:80/social-login?source=github\"}"); + authStateCache = AuthDefaultStateCache.INSTANCE; + } + + /** + * 认证授权 + * + * @param source + * @throws IOException + */ + @GetMapping("/binding/{source}") + @ResponseBody + public AjaxResult authBinding(@PathVariable("source") String source, HttpServletRequest request) throws IOException + { + LoginUser tokenUser = tokenService.getLoginUser(request); + if (StringUtils.isNotNull(tokenUser) && oauthUserService.checkAuthUser(tokenUser.getUserId(), source)) + { + return error(source + "平台账号已经绑定"); + } + + String obj = auths.get(source); + if (StringUtils.isEmpty(obj)) + { + return error(source + "平台账号暂不支持"); + } + JSONObject json = JSONObject.parseObject(obj); + AuthRequest authRequest = JustAuthUtils.getAuthRequest(source, json.getString("clientId"), json.getString("clientSecret"), json.getString("redirectUri"), authStateCache); + String authorizeUrl = authRequest.authorize(AuthStateUtils.createState()); + return success(authorizeUrl); + } + + /** + * 第三方登录回调 + * @param source + * @param callback + * @param request + * @return + */ + @Anonymous + @GetMapping("/social-login/{source}") + public AjaxResult socialLogin(@PathVariable("source") String source, AuthCallback callback, HttpServletRequest request) + { + String obj = auths.get(source); + if (StringUtils.isEmpty(obj)) + { + return AjaxResult.error(10002, "第三方平台系统不支持或未提供来源"); + } + JSONObject json = JSONObject.parseObject(obj); + AuthRequest authRequest = JustAuthUtils.getAuthRequest(source, json.getString("clientId"), json.getString("clientSecret"), json.getString("redirectUri"), authStateCache); + AuthResponse response = authRequest.login(callback); + if (response.ok()) + { + LoginUser tokenUser = tokenService.getLoginUser(request); + if (StringUtils.isNotNull(tokenUser)) + { + SysUser user = oauthUserService.selectSysUserByUUID(source + response.getData().getUuid()); + if (StringUtils.isNotNull(user)) + { + String token = tokenService.createToken(SecurityUtils.getLoginUser()); + return success().put(Constants.TOKEN, token); + } + // 若已经登录则直接绑定系统账号 + OauthUser authUser = new OauthUser(); + // SysUser sysUser = new SysUser(); + // sysUser.setAvatar(response.getData().getAvatar()); + authUser.setUuid(source + response.getData().getUuid()); + authUser.setUserId(SecurityUtils.getUserId()); + // sysUser.setUserName(response.getData().getUsername()); + // sysUser.setNickName(response.getData().getNickname()); + // sysUser.setEmail(response.getData().getEmail()); + authUser.setSource(source); + oauthUserService.insertOauthUser(authUser); + // userService.insertUser(sysUser); + String token = tokenService.createToken(SecurityUtils.getLoginUser()); + return success().put(Constants.TOKEN, token); + } + SysUser authUser = oauthUserService.selectSysUserByUUID(source + response.getData().getUuid()); + if (StringUtils.isNotNull(authUser)) + { + SysUser user = userService.selectUserByUserName(authUser.getUserName()); + if (StringUtils.isNull(user)) + { + throw new ServiceException("登录用户:" + user.getUserName() + " 不存在"); + } + else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) + { + throw new ServiceException("对不起,您的账号:" + user.getUserName() + " 已被删除"); + } + else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) + { + throw new ServiceException("对不起,您的账号:" + user.getUserName() + " 已停用"); + } + LoginUser loginUser = new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user)); + String token = tokenService.createToken(loginUser); + return success().put(Constants.TOKEN, token); + } + else + { + return AjaxResult.error(10002, "对不起,您没有绑定注册用户,请先注册后在个人中心绑定第三方授权信息!"); + } + } + return AjaxResult.error(10002, "对不起,授权信息验证不通过,请联系管理员"); + } + + /** + * 取消授权 + */ + @DeleteMapping(value = "/unlock/{authId}") + public AjaxResult unlockAuth(@PathVariable Long authId) + { + return toAjax(oauthUserService.deleteOauthUserById(authId)); + } +} diff --git a/boyue-auth/boyue-oauth-justauth/src/main/java/com/boyue/oauth/justauth/utils/JustAuthUtils.java b/boyue-auth/boyue-oauth-justauth/src/main/java/com/boyue/oauth/justauth/utils/JustAuthUtils.java new file mode 100644 index 0000000..66bee70 --- /dev/null +++ b/boyue-auth/boyue-oauth-justauth/src/main/java/com/boyue/oauth/justauth/utils/JustAuthUtils.java @@ -0,0 +1,177 @@ +package com.boyue.oauth.justauth.utils; + +import me.zhyd.oauth.cache.AuthStateCache; +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.exception.AuthException; +import me.zhyd.oauth.request.AuthAlipayRequest; +import me.zhyd.oauth.request.AuthAliyunRequest; +import me.zhyd.oauth.request.AuthBaiduRequest; +import me.zhyd.oauth.request.AuthCodingRequest; +// import me.zhyd.oauth.request.AuthCsdnRequest; +import me.zhyd.oauth.request.AuthDingTalkRequest; +import me.zhyd.oauth.request.AuthDouyinRequest; +import me.zhyd.oauth.request.AuthElemeRequest; +import me.zhyd.oauth.request.AuthGiteeRequest; +import me.zhyd.oauth.request.AuthGithubRequest; +import me.zhyd.oauth.request.AuthGitlabRequest; +import me.zhyd.oauth.request.AuthHuaweiRequest; +import me.zhyd.oauth.request.AuthKujialeRequest; +import me.zhyd.oauth.request.AuthLinkedinRequest; +import me.zhyd.oauth.request.AuthMeituanRequest; +import me.zhyd.oauth.request.AuthMiRequest; +import me.zhyd.oauth.request.AuthMicrosoftRequest; +import me.zhyd.oauth.request.AuthOschinaRequest; +import me.zhyd.oauth.request.AuthPinterestRequest; +import me.zhyd.oauth.request.AuthQqRequest; +import me.zhyd.oauth.request.AuthRenrenRequest; +import me.zhyd.oauth.request.AuthRequest; +import me.zhyd.oauth.request.AuthStackOverflowRequest; +import me.zhyd.oauth.request.AuthTaobaoRequest; +import me.zhyd.oauth.request.AuthTeambitionRequest; +import me.zhyd.oauth.request.AuthToutiaoRequest; +import me.zhyd.oauth.request.AuthWeChatMpRequest; +import me.zhyd.oauth.request.AuthWeChatOpenRequest; +import me.zhyd.oauth.request.AuthWeiboRequest; + +/** + * 认证授权工具类 + * + * @author boyue + */ +public class JustAuthUtils +{ + @SuppressWarnings("deprecation") + public static AuthRequest getAuthRequest(String source, String clientId, String clientSecret, String redirectUri, + AuthStateCache authStateCache) + { + AuthRequest authRequest = null; + switch (source.toLowerCase()) + { + case "dingtalk": + authRequest = new AuthDingTalkRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "baidu": + authRequest = new AuthBaiduRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "github": + authRequest = new AuthGithubRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "gitee": + authRequest = new AuthGiteeRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "weibo": + authRequest = new AuthWeiboRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "coding": + authRequest = new AuthCodingRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "oschina": + authRequest = new AuthOschinaRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "alipay": + // 支付宝在创建回调地址时,不允许使用localhost或者127.0.0.1,所以这儿的回调地址使用的局域网内的ip + authRequest = new AuthAlipayRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .alipayPublicKey("").redirectUri(redirectUri).build(), authStateCache); + break; + case "qq": + authRequest = new AuthQqRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "wechat_open": + authRequest = new AuthWeChatOpenRequest(AuthConfig.builder().clientId(clientId) + .clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache); + break; + // case "csdn": + // authRequest = new AuthCsdnRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + // .redirectUri(redirectUri).build(), authStateCache); + // break; + case "taobao": + authRequest = new AuthTaobaoRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "douyin": + authRequest = new AuthDouyinRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "linkedin": + authRequest = new AuthLinkedinRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "microsoft": + authRequest = new AuthMicrosoftRequest(AuthConfig.builder().clientId(clientId) + .clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache); + break; + case "mi": + authRequest = new AuthMiRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "toutiao": + authRequest = new AuthToutiaoRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "teambition": + authRequest = new AuthTeambitionRequest(AuthConfig.builder().clientId(clientId) + .clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache); + break; + case "pinterest": + authRequest = new AuthPinterestRequest(AuthConfig.builder().clientId(clientId) + .clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache); + break; + case "renren": + authRequest = new AuthRenrenRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "stack_overflow": + authRequest = new AuthStackOverflowRequest(AuthConfig.builder().clientId(clientId) + .clientSecret(clientSecret).redirectUri(redirectUri).stackOverflowKey("").build(), + authStateCache); + break; + case "huawei": + authRequest = new AuthHuaweiRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + // case "wechat_enterprise": + // authRequest = new AuthWeChatEnterpriseRequest(AuthConfig.builder().clientId(clientId) + // .clientSecret(clientSecret).redirectUri(redirectUri).agentId("").build(), authStateCache); + // break; + case "kujiale": + authRequest = new AuthKujialeRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "gitlab": + authRequest = new AuthGitlabRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "meituan": + authRequest = new AuthMeituanRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "eleme": + authRequest = new AuthElemeRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build()); + break; + case "wechat_mp": + authRequest = new AuthWeChatMpRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + case "aliyun": + authRequest = new AuthAliyunRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret) + .redirectUri(redirectUri).build(), authStateCache); + break; + default: + break; + } + if (null == authRequest) + { + throw new AuthException("未获取到有效的Auth配置"); + } + return authRequest; + } +} diff --git a/boyue-auth/boyue-oauth-wx/pom.xml b/boyue-auth/boyue-oauth-wx/pom.xml new file mode 100644 index 0000000..8ca9b11 --- /dev/null +++ b/boyue-auth/boyue-oauth-wx/pom.xml @@ -0,0 +1,29 @@ + + + + boyue-auth + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-oauth-wx + + + 微信认证模块 + + + + + + + com.boyue + boyue-auth-common + + + + + + \ No newline at end of file diff --git a/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/constant/WxMiniAppConstant.java b/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/constant/WxMiniAppConstant.java new file mode 100644 index 0000000..6b3ff48 --- /dev/null +++ b/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/constant/WxMiniAppConstant.java @@ -0,0 +1,42 @@ +package com.boyue.oauth.wx.constant; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class WxMiniAppConstant { + @Value("${oauth.wx.miniapp.appId}") + private String appId; + + @Value("${oauth.wx.miniapp.appSecret}") + private String appSecret; + + @Value("${oauth.wx.miniapp.url}") + private String url; + + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppSecret() { + return appSecret; + } + + public void setAppSecret(String appSecret) { + this.appSecret = appSecret; + } + +} diff --git a/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/constant/WxPubConstant.java b/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/constant/WxPubConstant.java new file mode 100644 index 0000000..6f7694d --- /dev/null +++ b/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/constant/WxPubConstant.java @@ -0,0 +1,41 @@ +package com.boyue.oauth.wx.constant; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class WxPubConstant { + @Value("${oauth.wx.pub.appId}") + private String appId; + + @Value("${oauth.wx.pub.appSecret}") + private String appSecret; + + @Value("${oauth.wx.pub.url}") + private String url; + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppSecret() { + return appSecret; + } + + public void setAppSecret(String appSecret) { + this.appSecret = appSecret; + } + +} diff --git a/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/controller/WxLoginController.java b/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/controller/WxLoginController.java new file mode 100644 index 0000000..5e683c7 --- /dev/null +++ b/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/controller/WxLoginController.java @@ -0,0 +1,69 @@ +package com.boyue.oauth.wx.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.auth.common.domain.OauthUser; +import com.boyue.auth.common.service.IOauthUserService; +import com.boyue.common.annotation.Anonymous; +import com.boyue.common.constant.Constants; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.utils.StringUtils; +import com.boyue.oauth.wx.service.Impl.WxMiniAppLoginServiceImpl; +import com.boyue.oauth.wx.service.Impl.WxPubLoginServiceImpl; + +@RestController +@RequestMapping("/oauth/wx") +public class WxLoginController extends BaseController { + + @Autowired + private IOauthUserService oauthUserService; + + @Autowired + private WxMiniAppLoginServiceImpl wxMiniAppLoginServiceImpl; + + @Autowired + private WxPubLoginServiceImpl wxPubLoginServiceImpl; + + @Anonymous + @PostMapping("/login/{source}/{code}") + public AjaxResult loginMiniApp(@PathVariable("source") String source, @PathVariable("code") String code) { + String token = null; + AjaxResult ajax = AjaxResult.success(); + if ("miniapp".equals(source)) { + token = wxMiniAppLoginServiceImpl.doLogin(code); + } else if ("pub".equals(source)) { + token = wxPubLoginServiceImpl.doLogin(code); + } else { + return error("错误的登录方式"); + } + ajax.put(Constants.TOKEN, token); + return ajax; + } + + @PostMapping("/register/{source}/{code}") + public AjaxResult register(@PathVariable("source") String source, @PathVariable("code") String code) { + OauthUser oauthUser = oauthUserService.selectOauthUserByUserId(getUserId()); + if (oauthUser != null) { + return error("不可以重复绑定"); + } else { + String msg = ""; + oauthUser = new OauthUser(); + oauthUser.setUserId(getUserId()); + oauthUser.setCode(code); + if ("miniapp".equals(source)) { + msg = wxMiniAppLoginServiceImpl.doRegister(oauthUser); + } else if ("pub".equals(source)) { + msg = wxPubLoginServiceImpl.doRegister(oauthUser); + } else { + return error("错误的注册方式"); + } + return StringUtils.isEmpty(msg) ? success() : error(msg); + } + } + +} diff --git a/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/service/Impl/WxMiniAppLoginServiceImpl.java b/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/service/Impl/WxMiniAppLoginServiceImpl.java new file mode 100644 index 0000000..9445769 --- /dev/null +++ b/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/service/Impl/WxMiniAppLoginServiceImpl.java @@ -0,0 +1,76 @@ +package com.boyue.oauth.wx.service.Impl; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson2.JSONObject; +import com.boyue.auth.common.domain.OauthUser; +import com.boyue.auth.common.service.IOauthUserService; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.StringUtils; +import com.boyue.framework.web.service.TokenService; +import com.boyue.framework.web.service.UserDetailsServiceImpl; +import com.boyue.oauth.wx.constant.WxMiniAppConstant; +import com.boyue.oauth.wx.service.WxLoginService; +import com.boyue.system.service.ISysUserService; + +@Service +public class WxMiniAppLoginServiceImpl implements WxLoginService { + @Autowired + private WxMiniAppConstant wxAppConstant; + + @Autowired + private TokenService tokenService; + + @Autowired + private UserDetailsServiceImpl userDetailsServiceImpl; + + @Autowired + private ISysUserService userService; + + @Autowired + private IOauthUserService oauthUserService; + + @Override + public String doLogin(String code) { + String openid = doAuth( + wxAppConstant.getUrl(), + wxAppConstant.getAppId(), + wxAppConstant.getAppSecret(), + code).getString("openid"); + OauthUser selectOauthUser = oauthUserService.selectOauthUserByUUID(openid); + if (selectOauthUser == null) { + return null; + } + SysUser sysUser = userService.selectUserById(selectOauthUser.getUserId()); + if (sysUser == null) { + throw new ServiceException("该微信未绑定用户"); + } + LoginUser loginUser = (LoginUser) userDetailsServiceImpl.createLoginUser(sysUser); + return tokenService.createToken(loginUser); + } + + @Override + public String doRegister(OauthUser oauthUser) { + if (StringUtils.isEmpty(oauthUser.getCode())) { + return "没有凭证"; + } + if (oauthUser.getUserId() == null) { + return "请先注册账号"; + } + JSONObject doAuth = doAuth( + wxAppConstant.getUrl(), + wxAppConstant.getAppId(), + wxAppConstant.getAppSecret(), + oauthUser.getCode()); + oauthUser.setOpenId(doAuth.getString("openid")); + oauthUser.setUuid(doAuth.getString("openid")); + oauthUser.setSource("WXMiniApp"); + oauthUser.setAccessToken(doAuth.getString("sessionKey")); + oauthUserService.insertOauthUser(oauthUser); + return ""; + } + +} diff --git a/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/service/Impl/WxPubLoginServiceImpl.java b/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/service/Impl/WxPubLoginServiceImpl.java new file mode 100644 index 0000000..5efa898 --- /dev/null +++ b/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/service/Impl/WxPubLoginServiceImpl.java @@ -0,0 +1,77 @@ +package com.boyue.oauth.wx.service.Impl; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson2.JSONObject; +import com.boyue.auth.common.domain.OauthUser; +import com.boyue.auth.common.service.IOauthUserService; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.StringUtils; +import com.boyue.framework.web.service.TokenService; +import com.boyue.framework.web.service.UserDetailsServiceImpl; +import com.boyue.oauth.wx.constant.WxPubConstant; +import com.boyue.oauth.wx.service.WxLoginService; +import com.boyue.system.service.ISysUserService; + +@Service +public class WxPubLoginServiceImpl implements WxLoginService { + + @Autowired + private WxPubConstant wxH5Constant; + + @Autowired + private TokenService tokenService; + + @Autowired + private UserDetailsServiceImpl userDetailsServiceImpl; + + @Autowired + private ISysUserService userService; + + @Autowired + private IOauthUserService oauthUserService; + + @Override + public String doLogin(String code) { + String openid = doAuth( + wxH5Constant.getUrl(), + wxH5Constant.getAppId(), + wxH5Constant.getAppSecret(), + code).getString("openid"); + OauthUser selectOauthUser = oauthUserService.selectOauthUserByUUID(openid); + if (selectOauthUser == null) { + return null; + } + SysUser sysUser = userService.selectUserById(selectOauthUser.getUserId()); + if (sysUser == null) { + throw new ServiceException("该微信未绑定用户"); + } + LoginUser loginUser = (LoginUser) userDetailsServiceImpl.createLoginUser(sysUser); + return tokenService.createToken(loginUser); + } + + @Override + public String doRegister(OauthUser oauthUser) { + if (StringUtils.isEmpty(oauthUser.getCode())) { + return "没有凭证"; + } + if (oauthUser.getUserId() == null) { + return "请先注册账号"; + } + JSONObject doAuth = doAuth( + wxH5Constant.getUrl(), + wxH5Constant.getAppId(), + wxH5Constant.getAppSecret(), + oauthUser.getCode()); + oauthUser.setOpenId(doAuth.getString("openid")); + oauthUser.setUuid(doAuth.getString("openid")); + oauthUser.setSource("WXPub"); + oauthUser.setAccessToken(doAuth.getString("sessionKey")); + oauthUserService.insertOauthUser(oauthUser); + return ""; + } + +} diff --git a/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/service/WxLoginService.java b/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/service/WxLoginService.java new file mode 100644 index 0000000..6d4915c --- /dev/null +++ b/boyue-auth/boyue-oauth-wx/src/main/java/com/boyue/oauth/wx/service/WxLoginService.java @@ -0,0 +1,34 @@ +package com.boyue.oauth.wx.service; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.boyue.auth.common.domain.OauthUser; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.http.HttpClientUtil; + +public interface WxLoginService { + + public String doLogin(String code); + + public String doRegister(OauthUser oauthUser); + + public default JSONObject doAuth(String url, String appid, String secret, String code) { + StringBuilder builder = new StringBuilder(url); + builder.append("?appid=").append(appid) + .append("&secret=").append(secret) + .append("&js_code=").append(code) + .append("&grant_type=").append("authorization_code"); + String getMessageUrl = builder.toString(); + String result = HttpClientUtil.sendHttpGet(getMessageUrl); + JSONObject jsonObject = JSON.parseObject(result); + if (jsonObject.containsKey("openid")) { + String openid = jsonObject.getString("openid"); + String sessionKey = jsonObject.getString("session_key"); + System.out.println("openid:" + openid); + System.out.println("sessionKey:" + sessionKey); + return jsonObject; + } else { + throw new ServiceException(jsonObject.getString("errmsg"), jsonObject.getIntValue("errcode")); + } + } +} diff --git a/boyue-auth/boyue-oauth-wx/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/boyue-auth/boyue-oauth-wx/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000..8af98a8 --- /dev/null +++ b/boyue-auth/boyue-oauth-wx/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,34 @@ +{ + "properties": [ + { + "name": "oauth.wx.miniapp.app-id", + "type": "java.lang.String", + "description": "微信小程序appid" + }, + { + "name": "oauth.wx.miniapp.app-secret", + "type": "java.lang.String", + "description": "微信小程序appSecret" + }, + { + "name": "oauth.wx.miniapp.url", + "type": "java.lang.String", + "description": "微信小程序认证地址" + }, + { + "name": "oauth.wx.pub.app-id", + "type": "java.lang.String", + "description": "微信公众号appid" + }, + { + "name": "oauth.wx.pub.app-secret", + "type": "java.lang.String", + "description": "微信公众号appSecret" + }, + { + "name": "oauth.wx.pub.url", + "type": "java.lang.String", + "description": "微信公众号认证地址" + } + ] +} \ No newline at end of file diff --git a/boyue-auth/boyue-tfa-email/pom.xml b/boyue-auth/boyue-tfa-email/pom.xml new file mode 100644 index 0000000..2a87986 --- /dev/null +++ b/boyue-auth/boyue-tfa-email/pom.xml @@ -0,0 +1,41 @@ + + + + boyue-auth + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-tfa-email + + + 邮箱认证模块 + + + + + + + com.boyue + boyue-auth-common + + + org.springframework.boot + spring-boot-starter-mail + + + + jakarta.mail + jakarta.mail-api + + + + com.sun.mail + jakarta.mail + + + + + \ No newline at end of file diff --git a/boyue-auth/boyue-tfa-email/src/main/java/com/boyue/tfa/email/service/IMailService.java b/boyue-auth/boyue-tfa-email/src/main/java/com/boyue/tfa/email/service/IMailService.java new file mode 100644 index 0000000..4829b0d --- /dev/null +++ b/boyue-auth/boyue-tfa-email/src/main/java/com/boyue/tfa/email/service/IMailService.java @@ -0,0 +1,7 @@ +package com.boyue.tfa.email.service; + +import com.boyue.auth.common.service.OauthVerificationCodeService; +import com.boyue.auth.common.service.TfaService; + +public interface IMailService extends OauthVerificationCodeService,TfaService { +} diff --git a/boyue-auth/boyue-tfa-email/src/main/java/com/boyue/tfa/email/service/impl/MailServiceImpl.java b/boyue-auth/boyue-tfa-email/src/main/java/com/boyue/tfa/email/service/impl/MailServiceImpl.java new file mode 100644 index 0000000..cedd68a --- /dev/null +++ b/boyue-auth/boyue-tfa-email/src/main/java/com/boyue/tfa/email/service/impl/MailServiceImpl.java @@ -0,0 +1,174 @@ +package com.boyue.tfa.email.service.impl; + +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.boyue.auth.common.enums.OauthVerificationUse; +import com.boyue.auth.common.utils.RandomCodeUtil; +import com.boyue.common.constant.CacheConstants; +import com.boyue.common.constant.Constants; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.domain.model.LoginBody; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.core.domain.model.RegisterBody; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.CacheUtils; +import com.boyue.common.utils.MessageUtils; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.framework.manager.AsyncManager; +import com.boyue.framework.manager.factory.AsyncFactory; +import com.boyue.framework.web.service.SysLoginService; +import com.boyue.framework.web.service.TokenService; +import com.boyue.framework.web.service.UserDetailsServiceImpl; +import com.boyue.system.service.ISysUserService; +import com.boyue.tfa.email.service.IMailService; +import com.boyue.tfa.email.utils.EmailUtil; + +@Service("auth:service:mail") +public class MailServiceImpl implements IMailService { + + @Autowired + private ISysUserService userService; + @Autowired + private TokenService tokenService; + @Autowired + private UserDetailsServiceImpl userDetailsServiceImpl; + @Autowired + private SysLoginService sysLoginService; + + private static final Logger log = LoggerFactory.getLogger(MailServiceImpl.class); + + @Override + public boolean sendCode(String email, String code, OauthVerificationUse use) { + if (CacheUtils.hasKey(CacheConstants.EMAIL_CODES, use.getValue() + email)) { + throw new ServiceException("当前验证码未失效,请在1分钟后再发送"); + } + + try { + EmailUtil.sendMessage(email, "验证码邮件", "您收到的验证码是:" + code); + CacheUtils.put(CacheConstants.EMAIL_CODES, use.getValue() + email, code, 1, TimeUnit.MINUTES); + log.info("发送邮箱验证码成功:{ email: " + email + " code:" + code + "}"); + return true; + } catch (Exception e) { + throw new ServiceException("发送邮箱验证码异常:" + email); + } + } + + @Override + public boolean checkCode(String email, String code, OauthVerificationUse use) { + if (StringUtils.isEmpty(code)) { + return false; + } + String cachedCode = CacheUtils.get(CacheConstants.EMAIL_CODES, use.getValue() + email, String.class); // 从缓存中获取验证码 + boolean isValid = code.equals(cachedCode); + if (isValid) { + CacheUtils.remove(CacheConstants.EMAIL_CODES, use.getValue() + email); + } + return isValid; + } + + @Override + public void doLogin(LoginBody loginBody) { + SysUser sysUser = userService.selectUserByEmail(loginBody.getEmail()); + if (sysUser == null) { + throw new ServiceException("该邮箱未绑定用户"); + } else { + sendCode(loginBody.getEmail(), RandomCodeUtil.numberCode(6), OauthVerificationUse.LOGIN); + } + } + + @Override + public String doLoginVerify(LoginBody loginBody) { + if (checkCode(loginBody.getEmail(), loginBody.getCode(), OauthVerificationUse.LOGIN)) { + SysUser sysUser = userService.selectUserByEmail(loginBody.getEmail()); + if (sysUser == null) { + throw new ServiceException("该邮箱未绑定用户"); + } + AsyncManager.me().execute(AsyncFactory.recordLogininfor(sysUser.getUserName(), Constants.LOGIN_SUCCESS, + MessageUtils.message("user.login.success"))); + LoginUser loginUser = (LoginUser) userDetailsServiceImpl.createLoginUser(sysUser); + sysLoginService.recordLoginInfo(loginUser.getUserId()); + return tokenService.createToken(loginUser); + } else { + throw new ServiceException("验证码错误"); + } + } + + @Override + public void doRegister(RegisterBody registerBody) { + SysUser sysUser = userService.selectUserByEmail(registerBody.getEmail()); + if (sysUser != null) { + throw new ServiceException("该邮箱已绑定用户"); + } else { + sendCode(registerBody.getEmail(), RandomCodeUtil.numberCode(6), OauthVerificationUse.REGISTER); + } + } + + @Override + public void doRegisterVerify(RegisterBody registerBody) { + if (checkCode(registerBody.getEmail(), registerBody.getCode(), OauthVerificationUse.REGISTER)) { + SysUser sysUser = new SysUser(); + sysUser.setUserName(registerBody.getEmail()); + sysUser.setNickName(registerBody.getEmail()); + sysUser.setPassword(SecurityUtils.encryptPassword(registerBody.getPassword())); + sysUser.setEmail(registerBody.getEmail()); + userService.registerUser(sysUser); + AsyncManager.me().execute(AsyncFactory.recordLogininfor(sysUser.getUserName(), Constants.REGISTER, + MessageUtils.message("user.register.success"))); + } else { + throw new ServiceException("验证码错误"); + } + } + + public void doReset(RegisterBody registerBody) { + SysUser sysUser = userService.selectUserByEmail(registerBody.getEmail()); + if (sysUser == null) { + throw new ServiceException("该邮箱未绑定用户"); + } else { + sendCode(registerBody.getEmail(), RandomCodeUtil.numberCode(6), OauthVerificationUse.RESET); + } + } + + public void doResetVerify(RegisterBody registerBody) { + if (checkCode(registerBody.getEmail(), registerBody.getCode(), OauthVerificationUse.RESET)) { + SysUser sysUser = userService.selectUserById(SecurityUtils.getUserId()); + sysUser.setEmail(registerBody.getEmail()); + userService.updateUser(sysUser); + } else { + throw new ServiceException("验证码错误"); + } + } + + @Override + public void doBind(LoginBody loginBody) { + SysUser sysUser = userService.selectUserByEmail(loginBody.getEmail()); + if (sysUser != null) { + throw new ServiceException("该邮箱已绑定用户"); + } + sysUser = userService.selectUserById(SecurityUtils.getUserId()); + if (!SecurityUtils.matchesPassword(loginBody.getPassword(), sysUser.getPassword())) { + throw new ServiceException("密码错误"); + } + sendCode(loginBody.getEmail(), RandomCodeUtil.numberCode(6), OauthVerificationUse.BIND); + } + + @Override + public void doBindVerify(LoginBody loginBody) { + if (checkCode(loginBody.getEmail(), loginBody.getCode(), OauthVerificationUse.BIND)) { + SysUser sysUser = userService.selectUserById(SecurityUtils.getUserId()); + if (!SecurityUtils.matchesPassword(loginBody.getPassword(), sysUser.getPassword())) { + throw new ServiceException("密码错误"); + } + sysUser.setEmail(loginBody.getEmail()); + userService.updateUser(sysUser); + } else { + throw new ServiceException("验证码错误"); + } + } + +} diff --git a/boyue-auth/boyue-tfa-email/src/main/java/com/boyue/tfa/email/utils/EmailUtil.java b/boyue-auth/boyue-tfa-email/src/main/java/com/boyue/tfa/email/utils/EmailUtil.java new file mode 100644 index 0000000..2c0afa0 --- /dev/null +++ b/boyue-auth/boyue-tfa-email/src/main/java/com/boyue/tfa/email/utils/EmailUtil.java @@ -0,0 +1,25 @@ +package com.boyue.tfa.email.utils; + +import org.springframework.boot.autoconfigure.mail.MailProperties; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSenderImpl; + +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.spring.SpringUtils; + +public class EmailUtil { + public static void sendMessage(String email, String title, String message) { + if (StringUtils.isEmpty(email)) { + throw new ServiceException("邮箱不能为空"); + } + MailProperties mailProperties = SpringUtils.getBean(MailProperties.class); + JavaMailSenderImpl mailSender = SpringUtils.getBean(JavaMailSenderImpl.class); + SimpleMailMessage simpleMailMessage = new SimpleMailMessage(); + simpleMailMessage.setSubject(title); + simpleMailMessage.setText(message); + simpleMailMessage.setFrom(mailProperties.getUsername()); + simpleMailMessage.setTo(email); + mailSender.send(simpleMailMessage); + } +} diff --git a/boyue-auth/boyue-tfa-phone/pom.xml b/boyue-auth/boyue-tfa-phone/pom.xml new file mode 100644 index 0000000..2f416ea --- /dev/null +++ b/boyue-auth/boyue-tfa-phone/pom.xml @@ -0,0 +1,33 @@ + + + + boyue-auth + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-tfa-phone + + + 手机号认证模块 + + + + + + + com.boyue + boyue-auth-common + + + + com.aliyun + dysmsapi20170525 + + + + + \ No newline at end of file diff --git a/boyue-auth/boyue-tfa-phone/src/main/java/com/boyue/tfa/phone/config/DySmsConfig.java b/boyue-auth/boyue-tfa-phone/src/main/java/com/boyue/tfa/phone/config/DySmsConfig.java new file mode 100644 index 0000000..48f5b7d --- /dev/null +++ b/boyue-auth/boyue-tfa-phone/src/main/java/com/boyue/tfa/phone/config/DySmsConfig.java @@ -0,0 +1,47 @@ +package com.boyue.tfa.phone.config; + +import java.util.Map; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import com.boyue.tfa.phone.domain.DySmsTemplate; + +/** + * 手机号认证数据 + * + * @author Dftre + * @date 2024-04-16 + */ +@Configuration +@ConfigurationProperties("tfa.phone.dysms") +public class DySmsConfig { + private String accessKeyId; + private String accessKeySecret; + private Map template; + + public String getAccessKeyId() { + return accessKeyId; + } + + public void setAccessKeyId(String accessKeyId) { + this.accessKeyId = accessKeyId; + } + + public String getAccessKeySecret() { + return accessKeySecret; + } + + public void setAccessKeySecret(String accessKeySecret) { + this.accessKeySecret = accessKeySecret; + } + + public Map getTemplate() { + return template; + } + + public void setTemplate(Map template) { + this.template = template; + } + +} \ No newline at end of file diff --git a/boyue-auth/boyue-tfa-phone/src/main/java/com/boyue/tfa/phone/domain/DySmsTemplate.java b/boyue-auth/boyue-tfa-phone/src/main/java/com/boyue/tfa/phone/domain/DySmsTemplate.java new file mode 100644 index 0000000..a4c0b88 --- /dev/null +++ b/boyue-auth/boyue-tfa-phone/src/main/java/com/boyue/tfa/phone/domain/DySmsTemplate.java @@ -0,0 +1,46 @@ +package com.boyue.tfa.phone.domain; + +/** + * 手机号认证短信模板 + * + * @author Dftre + * @date 2024-04-16 + */ +public class DySmsTemplate { + /** + * 短信模板编码 + */ + private String templateCode; + /** + * 签名 + */ + private String signName; + /** + * 短信模板必需的数据名称,多个key以逗号分隔,此处配置作为校验 + */ + private String keys; + + public String getTemplateCode() { + return templateCode; + } + + public void setTemplateCode(String templateCode) { + this.templateCode = templateCode; + } + + public String getSignName() { + return signName; + } + + public void setSignName(String signName) { + this.signName = signName; + } + + public String getKeys() { + return keys; + } + + public void setKeys(String keys) { + this.keys = keys; + } +} diff --git a/boyue-auth/boyue-tfa-phone/src/main/java/com/boyue/tfa/phone/service/DySmsService.java b/boyue-auth/boyue-tfa-phone/src/main/java/com/boyue/tfa/phone/service/DySmsService.java new file mode 100644 index 0000000..3c1f6aa --- /dev/null +++ b/boyue-auth/boyue-tfa-phone/src/main/java/com/boyue/tfa/phone/service/DySmsService.java @@ -0,0 +1,14 @@ +package com.boyue.tfa.phone.service; + +import com.boyue.auth.common.service.OauthVerificationCodeService; +import com.boyue.auth.common.service.TfaService; + +/** + * 手机号认证Servcie + * + * @author zlh + * @date 2024-04-16 + */ +public interface DySmsService extends OauthVerificationCodeService, TfaService { + +} diff --git a/boyue-auth/boyue-tfa-phone/src/main/java/com/boyue/tfa/phone/service/Impl/DySmsServiceImpl.java b/boyue-auth/boyue-tfa-phone/src/main/java/com/boyue/tfa/phone/service/Impl/DySmsServiceImpl.java new file mode 100644 index 0000000..5a514fe --- /dev/null +++ b/boyue-auth/boyue-tfa-phone/src/main/java/com/boyue/tfa/phone/service/Impl/DySmsServiceImpl.java @@ -0,0 +1,185 @@ +package com.boyue.tfa.phone.service.Impl; + +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson2.JSONObject; +import com.boyue.auth.common.enums.OauthVerificationUse; +import com.boyue.auth.common.utils.RandomCodeUtil; +import com.boyue.common.constant.CacheConstants; +import com.boyue.common.constant.Constants; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.domain.model.LoginBody; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.core.domain.model.RegisterBody; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.CacheUtils; +import com.boyue.common.utils.MessageUtils; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.framework.manager.AsyncManager; +import com.boyue.framework.manager.factory.AsyncFactory; +import com.boyue.framework.web.service.SysLoginService; +import com.boyue.framework.web.service.TokenService; +import com.boyue.framework.web.service.UserDetailsServiceImpl; +import com.boyue.system.service.ISysUserService; +import com.boyue.tfa.phone.config.DySmsConfig; +import com.boyue.tfa.phone.service.DySmsService; +import com.boyue.tfa.phone.utils.DySmsUtil; + +/** + * 手机号认证Servcie + * + * @author zlh + * @date 2024-04-16 + */ +@Service("auth:service:dySms") +public class DySmsServiceImpl implements DySmsService { + + @Autowired + private ISysUserService userService; + @Autowired + private UserDetailsServiceImpl userDetailsServiceImpl; + @Autowired + private TokenService tokenService; + @Autowired + private SysLoginService sysLoginService; + @Autowired + private DySmsConfig dySmsConfig; + + private static final Logger log = LoggerFactory.getLogger(DySmsServiceImpl.class); + + @Override + public boolean sendCode(String phone, String code, OauthVerificationUse use) { + if (CacheUtils.hasKey(CacheConstants.PHONE_CODES, use.getValue() + phone)) { + throw new ServiceException("当前验证码未失效,请在1分钟后再发送"); + } + + try { + JSONObject templateParams = new JSONObject(); + templateParams.put("code", code); + DySmsUtil.sendSms(phone, dySmsConfig.getTemplate().get("VerificationCode"), templateParams); + CacheUtils.put(CacheConstants.PHONE_CODES, use.getValue() + phone, code, 1, TimeUnit.MINUTES); + log.info("发送手机验证码成功:{ phone: " + phone + " code:" + code + "}"); + return true; + } catch (Exception e) { + throw new ServiceException("发送手机验证码异常:" + phone); + } + } + + @Override + public boolean checkCode(String phone, String code, OauthVerificationUse use) { + if (StringUtils.isEmpty(code)) { + return false; + } + String cachedCode = CacheUtils.get(CacheConstants.PHONE_CODES, use.getValue() + phone, String.class); // 从缓存中获取验证码 + boolean isValid = code.equals(cachedCode); + if (isValid) { + CacheUtils.remove(CacheConstants.PHONE_CODES, use.getValue() + phone); + } + return isValid; + } + + @Override + public void doLogin(LoginBody loginBody) { + SysUser sysUser = userService.selectUserByPhone(loginBody.getPhonenumber()); + if (sysUser == null) { + throw new ServiceException("该手机号未绑定用户"); + } else { + sendCode(loginBody.getPhonenumber(), RandomCodeUtil.numberCode(6), OauthVerificationUse.LOGIN); + } + } + + @Override + public String doLoginVerify(LoginBody loginBody) { + if (checkCode(loginBody.getPhonenumber(), loginBody.getCode(), OauthVerificationUse.LOGIN)) { + SysUser sysUser = userService.selectUserByPhone(loginBody.getPhonenumber()); + if (sysUser == null) { + throw new ServiceException("该手机号未绑定用户"); + } + AsyncManager.me().execute(AsyncFactory.recordLogininfor(sysUser.getUserName(), Constants.LOGIN_SUCCESS, + MessageUtils.message("user.login.success"))); + LoginUser loginUser = (LoginUser) userDetailsServiceImpl.createLoginUser(sysUser); + sysLoginService.recordLoginInfo(loginUser.getUserId()); + return tokenService.createToken(loginUser); + } else { + throw new ServiceException("验证码错误"); + } + } + + @Override + public void doRegister(RegisterBody registerBody) { + SysUser sysUser = userService.selectUserByPhone(registerBody.getPhonenumber()); + if (sysUser != null) { + throw new ServiceException("该手机号已绑定用户"); + } else { + sendCode(registerBody.getPhonenumber(), RandomCodeUtil.numberCode(6), OauthVerificationUse.REGISTER); + } + } + + @Override + public void doRegisterVerify(RegisterBody registerBody) { + if (checkCode(registerBody.getPhonenumber(), registerBody.getCode(), OauthVerificationUse.REGISTER)) { + SysUser sysUser = new SysUser(); + sysUser.setUserName(registerBody.getPhonenumber()); + sysUser.setNickName(registerBody.getUsername()); + sysUser.setPassword(SecurityUtils.encryptPassword(registerBody.getPassword())); + sysUser.setPhonenumber(registerBody.getPhonenumber()); + userService.registerUser(sysUser); + AsyncManager.me().execute(AsyncFactory.recordLogininfor(sysUser.getUserName(), Constants.REGISTER, + MessageUtils.message("user.register.success"))); + } else { + throw new ServiceException("验证码错误"); + } + } + + public void doReset(RegisterBody registerBody) { + SysUser sysUser = userService.selectUserByPhone(registerBody.getPhonenumber()); + if (sysUser == null) { + throw new ServiceException("该手机号未绑定用户"); + } else { + sendCode(registerBody.getPhonenumber(), RandomCodeUtil.numberCode(6), OauthVerificationUse.RESET); + } + } + + public void doResetVerify(RegisterBody registerBody) { + if (checkCode(registerBody.getPhonenumber(), registerBody.getCode(), OauthVerificationUse.RESET)) { + SysUser sysUser = userService.selectUserById(SecurityUtils.getUserId()); + sysUser.setPhonenumber(registerBody.getPhonenumber()); + userService.updateUser(sysUser); + } else { + throw new ServiceException("验证码错误"); + } + } + + @Override + public void doBind(LoginBody loginBody) { + SysUser sysUser = userService.selectUserByPhone(loginBody.getPhonenumber()); + if (sysUser != null) { + throw new ServiceException("该手机号已绑定用户"); + } + sysUser = userService.selectUserById(SecurityUtils.getUserId()); + if (!SecurityUtils.matchesPassword(loginBody.getPassword(), sysUser.getPassword())) { + throw new ServiceException("密码错误"); + } + sendCode(loginBody.getPhonenumber(), RandomCodeUtil.numberCode(6), OauthVerificationUse.BIND); + } + + @Override + public void doBindVerify(LoginBody loginBody) { + if (checkCode(loginBody.getPhonenumber(), loginBody.getCode(), OauthVerificationUse.BIND)) { + SysUser sysUser = userService.selectUserById(SecurityUtils.getUserId()); + if (!SecurityUtils.matchesPassword(loginBody.getPassword(), sysUser.getPassword())) { + throw new ServiceException("密码错误"); + } + sysUser.setPhonenumber(loginBody.getPhonenumber()); + userService.updateUser(sysUser); + } else { + throw new ServiceException("验证码错误"); + } + } +} diff --git a/boyue-auth/boyue-tfa-phone/src/main/java/com/boyue/tfa/phone/utils/DySmsUtil.java b/boyue-auth/boyue-tfa-phone/src/main/java/com/boyue/tfa/phone/utils/DySmsUtil.java new file mode 100644 index 0000000..b3a2455 --- /dev/null +++ b/boyue-auth/boyue-tfa-phone/src/main/java/com/boyue/tfa/phone/utils/DySmsUtil.java @@ -0,0 +1,88 @@ +package com.boyue.tfa.phone.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.fastjson2.JSONObject; +import com.aliyun.dysmsapi20170525.Client; +import com.aliyun.dysmsapi20170525.models.SendSmsRequest; +import com.aliyun.dysmsapi20170525.models.SendSmsResponse; +import com.aliyun.tea.TeaException; +import com.aliyun.teaopenapi.models.Config; +import com.aliyun.teautil.Common; +import com.aliyun.teautil.models.RuntimeOptions; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.spring.SpringUtils; +import com.boyue.tfa.phone.config.DySmsConfig; +import com.boyue.tfa.phone.domain.DySmsTemplate; + +public class DySmsUtil { + protected final static Logger logger = LoggerFactory.getLogger(DySmsUtil.class); + + /** + * 使用AK&SK初始化账号Client + * + * @param accessKeyId + * @param accessKeySecret + * @return Client + * @throws Exception + */ + private static Client createClient() throws Exception { + DySmsConfig dySmsConfig = SpringUtils.getBean(DySmsConfig.class); + Config config = new Config() + // 必填,您的 AccessKey ID + .setAccessKeyId(dySmsConfig.getAccessKeyId()) + // 必填,您的 AccessKey Secret + .setAccessKeySecret(dySmsConfig.getAccessKeySecret()); + config.endpoint = "dysmsapi.aliyuncs.com"; + return new Client(config); + } + + /** + * 验证参数 + * + * @param templateParamJson + * @param dySmsTemplate + * @throws Exception + */ + private static void validateParam(JSONObject templateParamJson, DySmsTemplate dySmsTemplate) { + String keys = dySmsTemplate.getKeys(); + String[] keyArr = keys.split(","); + for (String item : keyArr) { + if (!templateParamJson.containsKey(item)) { + throw new RuntimeException("模板缺少参数:" + item); + } + } + } + + public static void sendSms(String phone, DySmsTemplate dySmsTemplate, JSONObject templateParamJson) + throws Exception { + if (StringUtils.isEmpty(phone)) { + throw new ServiceException("手机号不能为空"); + } + validateParam(templateParamJson, dySmsTemplate); + Client client = createClient(); + SendSmsRequest sendSmsRequest = new SendSmsRequest() + .setPhoneNumbers(phone) + .setSignName(dySmsTemplate.getSignName()) + .setTemplateCode(dySmsTemplate.getTemplateCode()) + .setTemplateParam(templateParamJson.toJSONString()); + try { + // 复制代码运行请自行打印 API 的返回值 + SendSmsResponse sendSmsResponse = client.sendSmsWithOptions(sendSmsRequest, new RuntimeOptions()); + if ("OK".equals(sendSmsResponse.getBody().getCode())) { + logger.info("短信接口返回的数据--- {}", sendSmsResponse.getBody().getMessage()); + } else { + logger.error("短信接口返回的数据--- {}", sendSmsResponse.getBody().getMessage()); + throw new ServiceException(sendSmsResponse.getBody().getMessage()); + } + } catch (TeaException error) { + // 错误 message + System.out.println(error.getMessage()); + // 诊断地址 + System.out.println(error.getData().get("Recommend")); + Common.assertAsString(error.message); + } + } +} \ No newline at end of file diff --git a/boyue-auth/boyue-tfa-phone/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/boyue-auth/boyue-tfa-phone/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000..349dd9c --- /dev/null +++ b/boyue-auth/boyue-tfa-phone/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,19 @@ +{ + "properties": [ + { + "name": "tfa.phone.dysms.access-key-id", + "type": "java.lang.String", + "description": "阿里云短信 AccessKey ID" + }, + { + "name": "tfa.phone.dysms.access-key-secret", + "type": "java.lang.String", + "description": "阿里云短信 AccessKey Secret" + }, + { + "name": "tfa.phone.dysms.template", + "type": "java.util.Map", + "description": "短信模板" + } + ] +} \ No newline at end of file diff --git a/boyue-auth/pom.xml b/boyue-auth/pom.xml new file mode 100644 index 0000000..c19aefc --- /dev/null +++ b/boyue-auth/pom.xml @@ -0,0 +1,118 @@ + + + + boyuehasfj-java + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-auth + + + 1.16.7 + 3.7.4.ALL + 3.1.1 + 2.0.1 + + + + 第三方认证模块 + + + + + + com.boyue + boyue-auth-common + ${boyue.version} + + + + jakarta.mail + jakarta.mail-api + ${mail.version} + + + + com.sun.mail + jakarta.mail + ${mail.version} + + + + + me.zhyd.oauth + JustAuth + ${justauth.version} + + + + + com.alipay.sdk + alipay-sdk-java + ${alipay.version} + + + commons-logging + commons-logging + + + + + + + com.aliyun + dysmsapi20170525 + ${dysmsapi.version} + + + + + com.boyue + boyue-oauth-justauth + ${boyue.version} + + + + + com.boyue + boyue-oauth-wx + ${boyue.version} + + + + + com.boyue + boyue-tfa-phone + ${boyue.version} + + + + + com.boyue + boyue-tfa-email + ${boyue.version} + + + + + com.boyue + boyue-auth-starter + ${boyue.version} + + + + + + + boyue-auth-common + boyue-oauth-justauth + boyue-oauth-wx + boyue-tfa-phone + boyue-tfa-email + boyue-auth-starter + + pom + \ No newline at end of file diff --git a/boyue-common/pom.xml b/boyue-common/pom.xml new file mode 100644 index 0000000..d1c753f --- /dev/null +++ b/boyue-common/pom.xml @@ -0,0 +1,146 @@ + + + + boyuehasfj-java + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-common + + + common通用工具 + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-security + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + + + + + org.springframework.boot + spring-boot-starter-validation + + + + + org.apache.commons + commons-lang3 + + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + + com.alibaba.fastjson2 + fastjson2 + + + + + commons-io + commons-io + + + + + org.apache.poi + poi-ooxml + + + + + io.jsonwebtoken + jjwt-api + + + + io.jsonwebtoken + jjwt-impl + + + + io.jsonwebtoken + jjwt-jackson + + + + + jakarta.xml.bind + jakarta.xml.bind-api + + + com.sun.xml.bind + jaxb-core + + + + + org.apache.commons + commons-pool2 + + + + + org.apache.httpcomponents + httpclient + + + + + eu.bitwalker + UserAgentUtils + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + + + + + org.projectlombok + lombok + + + + + org.springframework.boot + spring-boot-starter-cache + + + + javax.cache + cache-api + + + + diff --git a/boyue-common/src/main/java/com/boyue/common/annotation/Anonymous.java b/boyue-common/src/main/java/com/boyue/common/annotation/Anonymous.java new file mode 100644 index 0000000..ccadce6 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/annotation/Anonymous.java @@ -0,0 +1,19 @@ +package com.boyue.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 匿名访问不鉴权注解 + * + * @author boyue + */ +@Target({ ElementType.METHOD, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Anonymous +{ +} diff --git a/boyue-common/src/main/java/com/boyue/common/annotation/DataScope.java b/boyue-common/src/main/java/com/boyue/common/annotation/DataScope.java new file mode 100644 index 0000000..5307a25 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/annotation/DataScope.java @@ -0,0 +1,33 @@ +package com.boyue.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 数据权限过滤注解 + * + * @author boyue + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataScope +{ + /** + * 部门表的别名 + */ + public String deptAlias() default ""; + + /** + * 用户表的别名 + */ + public String userAlias() default ""; + + /** + * 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来 + */ + public String permission() default ""; +} diff --git a/boyue-common/src/main/java/com/boyue/common/annotation/DataSource.java b/boyue-common/src/main/java/com/boyue/common/annotation/DataSource.java new file mode 100644 index 0000000..fc9e348 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/annotation/DataSource.java @@ -0,0 +1,34 @@ +package com.boyue.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.boyue.common.enums.DataSourceType; + +/** + * 自定义多数据源切换注解 + * + * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准 + * + * @author boyue + */ +@Target({ ElementType.METHOD, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface DataSource { + + /** + * 切换数据源名称 - 枚举方式 + */ + public DataSourceType value() default DataSourceType.MASTER; + + /** + * 切换数据源名称 - 字符串方式 + */ + public String name() default ""; +} diff --git a/boyue-common/src/main/java/com/boyue/common/annotation/Excel.java b/boyue-common/src/main/java/com/boyue/common/annotation/Excel.java new file mode 100644 index 0000000..57652e4 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/annotation/Excel.java @@ -0,0 +1,206 @@ +package com.boyue.common.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.math.RoundingMode; + +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IndexedColors; + +import com.boyue.common.utils.poi.ExcelHandlerAdapter; + +/** + * 自定义导出Excel数据注解 + * + * @author boyue + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Excel { + /** + * 导出时在excel中排序 + */ + public int sort() default Integer.MAX_VALUE; + + /** + * 导出到Excel中的名字. + */ + public String name() default ""; + + /** + * 日期格式, 如: yyyy-MM-dd + */ + public String dateFormat() default ""; + + /** + * 如果是字典类型,请设置字典的type值 (如: sys_user_sex) + */ + public String dictType() default ""; + + /** + * 读取内容转表达式 (如: 0=男,1=女,2=未知) + */ + public String readConverterExp() default ""; + + /** + * 分隔符,读取字符串组内容 + */ + public String separator() default ","; + + /** + * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化) + */ + public int scale() default -1; + + /** + * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN + */ + public RoundingMode roundingMode() default RoundingMode.HALF_EVEN; + + /** + * 导出时在excel中每个列的高度 + */ + public double height() default 14; + + /** + * 导出时在excel中每个列的宽度 + */ + public double width() default 16; + + /** + * 文字后缀,如% 90 变成90% + */ + public String suffix() default ""; + + /** + * 当值为空时,字段的默认值 + */ + public String defaultValue() default ""; + + /** + * 提示信息 + */ + public String prompt() default ""; + + /** + * 是否允许内容换行 + */ + public boolean wrapText() default false; + + /** + * 设置只能选择不能输入的列内容. + */ + public String[] combo() default {}; + + /** + * 是否从字典读数据到combo,默认不读取,如读取需要设置dictType注解. + */ + public boolean comboReadDict() default false; + + /** + * 是否需要纵向合并单元格,应对需求:含有list集合单元格) + */ + public boolean needMerge() default false; + + /** + * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写. + */ + public boolean isExport() default true; + + /** + * 另一个类中的属性名称,支持多级获取,以小数点隔开 + */ + public String targetAttr() default ""; + + /** + * 是否自动统计数据,在最后追加一行统计数据总和 + */ + public boolean isStatistics() default false; + + /** + * 导出类型(0数字 1字符串 2图片) + */ + public ColumnType cellType() default ColumnType.STRING; + + /** + * 导出列头背景颜色 + */ + public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT; + + /** + * 导出列头字体颜色 + */ + public IndexedColors headerColor() default IndexedColors.WHITE; + + /** + * 导出单元格背景颜色 + */ + public IndexedColors backgroundColor() default IndexedColors.WHITE; + + /** + * 导出单元格字体颜色 + */ + public IndexedColors color() default IndexedColors.BLACK; + + /** + * 导出字段对齐方式 + */ + public HorizontalAlignment align() default HorizontalAlignment.CENTER; + + /** + * 自定义数据处理器 + */ + public Class handler() default ExcelHandlerAdapter.class; + + /** + * 自定义数据处理器参数 + */ + public String[] args() default {}; + + /** + * 字段类型(0:导出导入;1:仅导出;2:仅导入) + */ + Type type() default Type.ALL; + + public enum Type { + /** 导出或导入 */ + ALL(0), + /** 仅导出 */ + EXPORT(1), + /** 仅导入 */ + IMPORT(2); + + private final int value; + + Type(int value) { + this.value = value; + } + + public int value() { + return this.value; + } + } + + public enum ColumnType { + /** 数字 */ + NUMERIC(0), + /** 字符串 */ + STRING(1), + /** 图片 */ + IMAGE(2), + /** 文本 */ + TEXT(3); + + private final int value; + + ColumnType(int value) { + this.value = value; + } + + public int value() { + return this.value; + } + } +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/annotation/Excels.java b/boyue-common/src/main/java/com/boyue/common/annotation/Excels.java new file mode 100644 index 0000000..c21585a --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/annotation/Excels.java @@ -0,0 +1,18 @@ +package com.boyue.common.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Excel注解集 + * + * @author boyue + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Excels +{ + public Excel[] value(); +} diff --git a/boyue-common/src/main/java/com/boyue/common/annotation/Log.java b/boyue-common/src/main/java/com/boyue/common/annotation/Log.java new file mode 100644 index 0000000..f603617 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/annotation/Log.java @@ -0,0 +1,51 @@ +package com.boyue.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.enums.OperatorType; + +/** + * 自定义操作日志记录注解 + * + * @author boyue + * + */ +@Target({ ElementType.PARAMETER, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Log +{ + /** + * 模块 + */ + public String title() default ""; + + /** + * 功能 + */ + public BusinessType businessType() default BusinessType.OTHER; + + /** + * 操作人类别 + */ + public OperatorType operatorType() default OperatorType.MANAGE; + + /** + * 是否保存请求的参数 + */ + public boolean isSaveRequestData() default true; + + /** + * 是否保存响应的参数 + */ + public boolean isSaveResponseData() default true; + + /** + * 排除指定的请求参数 + */ + public String[] excludeParamNames() default {}; +} diff --git a/boyue-common/src/main/java/com/boyue/common/annotation/RateLimiter.java b/boyue-common/src/main/java/com/boyue/common/annotation/RateLimiter.java new file mode 100644 index 0000000..e1457d7 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/annotation/RateLimiter.java @@ -0,0 +1,41 @@ +package com.boyue.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.boyue.common.constant.CacheConstants; +import com.boyue.common.enums.LimitType; + +/** + * 限流注解 + * + * @author boyue + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RateLimiter +{ + /** + * 限流key + */ + public String key() default CacheConstants.RATE_LIMIT_KEY; + + /** + * 限流时间,单位秒 + */ + public int time() default 60; + + /** + * 限流次数 + */ + public int count() default 100; + + /** + * 限流类型 + */ + public LimitType limitType() default LimitType.DEFAULT; +} diff --git a/boyue-common/src/main/java/com/boyue/common/annotation/RepeatSubmit.java b/boyue-common/src/main/java/com/boyue/common/annotation/RepeatSubmit.java new file mode 100644 index 0000000..90edfa3 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/annotation/RepeatSubmit.java @@ -0,0 +1,31 @@ +package com.boyue.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义注解防止表单重复提交 + * + * @author boyue + * + */ +@Inherited +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RepeatSubmit +{ + /** + * 间隔时间(ms),小于此时间视为重复提交 + */ + public int interval() default 5000; + + /** + * 提示消息 + */ + public String message() default "不允许重复提交,请稍候再试"; +} diff --git a/boyue-common/src/main/java/com/boyue/common/annotation/Sensitive.java b/boyue-common/src/main/java/com/boyue/common/annotation/Sensitive.java new file mode 100644 index 0000000..e166ce6 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/annotation/Sensitive.java @@ -0,0 +1,25 @@ +package com.boyue.common.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.boyue.common.config.serializer.SensitiveJsonSerializer; +import com.boyue.common.enums.DesensitizedType; + +/** + * 数据脱敏注解 + * + * @author boyue + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@JacksonAnnotationsInside +@JsonSerialize(using = SensitiveJsonSerializer.class) +public @interface Sensitive +{ + DesensitizedType desensitizedType(); +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/config/BoYueConfig.java b/boyue-common/src/main/java/com/boyue/common/config/BoYueConfig.java new file mode 100644 index 0000000..5a55d34 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/config/BoYueConfig.java @@ -0,0 +1,135 @@ +package com.boyue.common.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 读取项目相关配置 + * + * @author boyue + */ +@Component +@ConfigurationProperties(prefix = "boyue") +public class BoYueConfig +{ + /** 项目名称 */ + private String name; + + /** 版本 */ + private String version; + + /** 版权年份 */ + private String copyrightYear; + + /** 上传路径 */ + private static String profile; + + + + private static String fileServer; + + /** 获取地址开关 */ + private static boolean addressEnabled; + + /** 验证码类型 */ + private static String captchaType; + + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public String getVersion() + { + return version; + } + + public void setVersion(String version) + { + this.version = version; + } + + public String getCopyrightYear() + { + return copyrightYear; + } + + public void setCopyrightYear(String copyrightYear) + { + this.copyrightYear = copyrightYear; + } + + public static String getProfile() + { + return profile; + } + + public void setProfile(String profile) + { + BoYueConfig.profile = profile; + } + + public static boolean isAddressEnabled() + { + return addressEnabled; + } + + public void setAddressEnabled(boolean addressEnabled) + { + BoYueConfig.addressEnabled = addressEnabled; + } + + public static String getCaptchaType() { + return captchaType; + } + + public void setCaptchaType(String captchaType) { + BoYueConfig.captchaType = captchaType; + } + + public static String getFileServer() { + return fileServer; + } + + public void setFileServer(String fileServer) { + BoYueConfig.fileServer = fileServer; + } + + /** + * 获取导入上传路径 + */ + public static String getImportPath() + { + return getProfile() + "/import"; + } + + /** + * 获取头像上传路径 + */ + public static String getAvatarPath() + { + return getProfile() + "/avatar"; + } + + /** + * 获取下载路径 + */ + public static String getDownloadPath() + { + return getProfile() + "/download/"; + } + + /** + * 获取上传路径 + */ + public static String getUploadPath() + { + return getProfile() + "/upload"; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/config/serializer/SensitiveJsonSerializer.java b/boyue-common/src/main/java/com/boyue/common/config/serializer/SensitiveJsonSerializer.java new file mode 100644 index 0000000..43f0ad2 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/config/serializer/SensitiveJsonSerializer.java @@ -0,0 +1,68 @@ +package com.boyue.common.config.serializer; + +import java.io.IOException; +import java.util.Objects; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import com.boyue.common.annotation.Sensitive; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.enums.DesensitizedType; +import com.boyue.common.utils.SecurityUtils; + +/** + * 数据脱敏序列化过滤 + * + * @author boyue + */ +public class SensitiveJsonSerializer extends JsonSerializer implements ContextualSerializer +{ + private DesensitizedType desensitizedType; + + @Override + public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException + { + if (desensitization()) + { + gen.writeString(desensitizedType.desensitizer().apply(value)); + } + else + { + gen.writeString(value); + } + } + + @Override + public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) + throws JsonMappingException + { + Sensitive annotation = property.getAnnotation(Sensitive.class); + if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) + { + this.desensitizedType = annotation.desensitizedType(); + return this; + } + return prov.findValueSerializer(property.getType(), property); + } + + /** + * 是否需要脱敏处理 + */ + private boolean desensitization() + { + try + { + LoginUser securityUser = SecurityUtils.getLoginUser(); + // 管理员不脱敏 + return !securityUser.getUser().isAdmin(); + } + catch (Exception e) + { + return true; + } + } +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/constant/CacheConstants.java b/boyue-common/src/main/java/com/boyue/common/constant/CacheConstants.java new file mode 100644 index 0000000..9e2cbfd --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/constant/CacheConstants.java @@ -0,0 +1,68 @@ +package com.boyue.common.constant; + +/** + * 缓存的key 常量 + * + * @author boyue + */ +public class CacheConstants { + /** + * 登录用户 redis key + */ + public static final String LOGIN_TOKEN_KEY = "login_tokens"; + + /** + * 验证码 redis key + */ + public static final String CAPTCHA_CODE_KEY = "captcha_codes"; + + /** + * 参数管理 cache key + */ + public static final String SYS_CONFIG_KEY = "sys_config"; + + /** + * 字典管理 cache key + */ + public static final String SYS_DICT_KEY = "sys_dict"; + + /** + * 防重提交 redis key + */ + public static final String REPEAT_SUBMIT_KEY = "repeat_submit"; + + /** + * 限流 redis key + */ + public static final String RATE_LIMIT_KEY = "rate_limit"; + + /** + * 登录账户密码错误次数 redis key + */ + public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt"; + + /** + * 登录ip错误次数 redis key + */ + public static final String IP_ERR_CNT_KEY = "ip_err_cnt_key"; + + /** + * 手机号验证码 phone codes + */ + public static final String PHONE_CODES = "phone_codes"; + + /** + * 邮箱验证码 + */ + public static final String EMAIL_CODES = "email_codes"; + + /** + * 文件的md5 redis key + */ + public static final String FILE_MD5_PATH_KEY = "file_md5_path"; + + /** + * 文件路径 redis key + */ + public static final String FILE_PATH_MD5_KEY = "file_path_md5"; +} diff --git a/boyue-common/src/main/java/com/boyue/common/constant/Constants.java b/boyue-common/src/main/java/com/boyue/common/constant/Constants.java new file mode 100644 index 0000000..f606c92 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/constant/Constants.java @@ -0,0 +1,175 @@ +package com.boyue.common.constant; + +import java.util.Locale; + +import io.jsonwebtoken.Claims; + +/** + * 通用常量信息 + * + * @author boyue + */ +public class Constants { + /** + * UTF-8 字符集 + */ + public static final String UTF8 = "UTF-8"; + + /** + * GBK 字符集 + */ + public static final String GBK = "GBK"; + + /** + * 系统语言 + */ + public static final Locale DEFAULT_LOCALE = Locale.SIMPLIFIED_CHINESE; + + /** + * www主域 + */ + public static final String WWW = "www."; + + /** + * http请求 + */ + public static final String HTTP = "http://"; + + /** + * https请求 + */ + public static final String HTTPS = "https://"; + + /** + * 通用成功标识 + */ + public static final String SUCCESS = "0"; + + /** + * 通用失败标识 + */ + public static final String FAIL = "1"; + + /** + * 登录成功 + */ + public static final String LOGIN_SUCCESS = "Success"; + + /** + * 注销 + */ + public static final String LOGOUT = "Logout"; + + /** + * 注册 + */ + public static final String REGISTER = "Register"; + + /** + * 登录失败 + */ + public static final String LOGIN_FAIL = "Error"; + + /** + * 所有权限标识 + */ + public static final String ALL_PERMISSION = "*:*:*"; + + /** + * 管理员角色权限标识 + */ + public static final String SUPER_ADMIN = "admin"; + + /** + * 角色权限分隔符 + */ + public static final String ROLE_DELIMETER = ","; + + /** + * 权限标识分隔符 + */ + public static final String PERMISSION_DELIMETER = ","; + + /** + * 验证码有效期(分钟) + */ + public static final Integer CAPTCHA_EXPIRATION = 2; + + /** + * 令牌 + */ + public static final String TOKEN = "token"; + + /** + * 令牌前缀 + */ + public static final String TOKEN_PREFIX = "Bearer "; + + /** + * 令牌前缀 + */ + public static final String LOGIN_USER_KEY = "login_user_key"; + + /** + * 用户ID + */ + public static final String JWT_USERID = "userid"; + + /** + * 用户名称 + */ + public static final String JWT_USERNAME = Claims.SUBJECT; + + /** + * 用户头像 + */ + public static final String JWT_AVATAR = "avatar"; + + /** + * 创建时间 + */ + public static final String JWT_CREATED = "created"; + + /** + * 用户权限 + */ + public static final String JWT_AUTHORITIES = "authorities"; + + /** + * 资源映射路径 前缀 + */ + public static final String RESOURCE_PREFIX = "/profile"; + + /** + * RMI 远程方法调用 + */ + public static final String LOOKUP_RMI = "rmi:"; + + /** + * LDAP 远程方法调用 + */ + public static final String LOOKUP_LDAP = "ldap:"; + + /** + * LDAPS 远程方法调用 + */ + public static final String LOOKUP_LDAPS = "ldaps:"; + + /** + * 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全) + */ + public static final String[] JSON_WHITELIST_STR = { "org.springframework", "com.boyue" }; + + /** + * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加) + */ + public static final String[] JOB_WHITELIST_STR = { "com.boyue.quartz.task" }; + + /** + * 定时任务违规的字符 + */ + public static final String[] JOB_ERROR_STR = { + "java.net.URL", "javax.naming.InitialContext", + "org.yaml.snakeyaml", "org.springframework", "org.apache", + "com.boyue.common.utils.file", "com.boyue.common.config", "com.boyue.generator" }; +} diff --git a/boyue-common/src/main/java/com/boyue/common/constant/HttpStatus.java b/boyue-common/src/main/java/com/boyue/common/constant/HttpStatus.java new file mode 100644 index 0000000..6170da0 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/constant/HttpStatus.java @@ -0,0 +1,94 @@ +package com.boyue.common.constant; + +/** + * 返回状态码 + * + * @author boyue + */ +public class HttpStatus +{ + /** + * 操作成功 + */ + public static final int SUCCESS = 200; + + /** + * 对象创建成功 + */ + public static final int CREATED = 201; + + /** + * 请求已经被接受 + */ + public static final int ACCEPTED = 202; + + /** + * 操作已经执行成功,但是没有返回数据 + */ + public static final int NO_CONTENT = 204; + + /** + * 资源已被移除 + */ + public static final int MOVED_PERM = 301; + + /** + * 重定向 + */ + public static final int SEE_OTHER = 303; + + /** + * 资源没有被修改 + */ + public static final int NOT_MODIFIED = 304; + + /** + * 参数列表错误(缺少,格式不匹配) + */ + public static final int BAD_REQUEST = 400; + + /** + * 未授权 + */ + public static final int UNAUTHORIZED = 401; + + /** + * 访问受限,授权过期 + */ + public static final int FORBIDDEN = 403; + + /** + * 资源,服务未找到 + */ + public static final int NOT_FOUND = 404; + + /** + * 不允许的http方法 + */ + public static final int BAD_METHOD = 405; + + /** + * 资源冲突,或者资源被锁 + */ + public static final int CONFLICT = 409; + + /** + * 不支持的数据,媒体类型 + */ + public static final int UNSUPPORTED_TYPE = 415; + + /** + * 系统内部错误 + */ + public static final int ERROR = 500; + + /** + * 接口未实现 + */ + public static final int NOT_IMPLEMENTED = 501; + + /** + * 系统警告消息 + */ + public static final int WARN = 601; +} diff --git a/boyue-common/src/main/java/com/boyue/common/constant/ScheduleConstants.java b/boyue-common/src/main/java/com/boyue/common/constant/ScheduleConstants.java new file mode 100644 index 0000000..ff4f7b6 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/constant/ScheduleConstants.java @@ -0,0 +1,50 @@ +package com.boyue.common.constant; + +/** + * 任务调度通用常量 + * + * @author boyue + */ +public class ScheduleConstants +{ + public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME"; + + /** 执行目标key */ + public static final String TASK_PROPERTIES = "TASK_PROPERTIES"; + + /** 默认 */ + public static final String MISFIRE_DEFAULT = "0"; + + /** 立即触发执行 */ + public static final String MISFIRE_IGNORE_MISFIRES = "1"; + + /** 触发一次执行 */ + public static final String MISFIRE_FIRE_AND_PROCEED = "2"; + + /** 不触发立即执行 */ + public static final String MISFIRE_DO_NOTHING = "3"; + + public enum Status + { + /** + * 正常 + */ + NORMAL("0"), + /** + * 暂停 + */ + PAUSE("1"); + + private String value; + + private Status(String value) + { + this.value = value; + } + + public String getValue() + { + return value; + } + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/constant/UserConstants.java b/boyue-common/src/main/java/com/boyue/common/constant/UserConstants.java new file mode 100644 index 0000000..f23c38a --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/constant/UserConstants.java @@ -0,0 +1,80 @@ +package com.boyue.common.constant; + +/** + * 用户常量信息 + * + * @author boyue + */ +public class UserConstants { + /** + * 平台内系统用户的唯一标志 + */ + public static final String SYS_USER = "SYS_USER"; + + /** 正常状态 */ + public static final String NORMAL = "0"; + + /** 异常状态 */ + public static final String EXCEPTION = "1"; + + /** 用户封禁状态 */ + public static final String USER_DISABLE = "1"; + + /** 角色正常状态 */ + public static final String ROLE_NORMAL = "0"; + + /** 角色封禁状态 */ + public static final String ROLE_DISABLE = "1"; + + /** 部门正常状态 */ + public static final String DEPT_NORMAL = "0"; + + /** 部门停用状态 */ + public static final String DEPT_DISABLE = "1"; + + /** 字典正常状态 */ + public static final String DICT_NORMAL = "0"; + + /** 是否为系统默认(是) */ + public static final String YES = "Y"; + + /** 是否菜单外链(是) */ + public static final String YES_FRAME = "0"; + + /** 是否菜单外链(否) */ + public static final String NO_FRAME = "1"; + + /** 菜单类型(目录) */ + public static final String TYPE_DIR = "M"; + + /** 菜单类型(菜单) */ + public static final String TYPE_MENU = "C"; + + /** 菜单类型(按钮) */ + public static final String TYPE_BUTTON = "F"; + + /** Layout组件标识 */ + public final static String LAYOUT = "Layout"; + + /** ParentView组件标识 */ + public final static String PARENT_VIEW = "ParentView"; + + /** InnerLink组件标识 */ + public final static String INNER_LINK = "InnerLink"; + + /** 校验是否唯一的返回标识 */ + public final static boolean UNIQUE = true; + public final static boolean NOT_UNIQUE = false; + + /** + * 用户名长度限制 + */ + public static final int USERNAME_MIN_LENGTH = 2; + public static final int USERNAME_MAX_LENGTH = 20; + + /** + * 密码长度限制 + */ + public static final int PASSWORD_MIN_LENGTH = 5; + public static final int PASSWORD_MAX_LENGTH = 20; +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/controller/BaseController.java b/boyue-common/src/main/java/com/boyue/common/core/controller/BaseController.java new file mode 100644 index 0000000..a7cdec0 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/controller/BaseController.java @@ -0,0 +1,202 @@ +package com.boyue.common.core.controller; + +import java.beans.PropertyEditorSupport; +import java.util.Date; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.InitBinder; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.boyue.common.constant.HttpStatus; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.core.page.PageDomain; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.core.page.TableSupport; +import com.boyue.common.utils.DateUtils; +import com.boyue.common.utils.PageUtils; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.sql.SqlUtil; + +/** + * web层通用数据处理 + * + * @author boyue + */ +public class BaseController +{ + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + + /** + * 将前台传递过来的日期格式的字符串,自动转化为Date类型 + */ + @InitBinder + public void initBinder(WebDataBinder binder) + { + // Date 类型转换 + binder.registerCustomEditor(Date.class, new PropertyEditorSupport() + { + @Override + public void setAsText(String text) + { + setValue(DateUtils.parseDate(text)); + } + }); + } + + /** + * 设置请求分页数据 + */ + protected void startPage() + { + PageUtils.startPage(); + } + + /** + * 设置请求排序数据 + */ + protected void startOrderBy() + { + PageDomain pageDomain = TableSupport.buildPageRequest(); + if (StringUtils.isNotEmpty(pageDomain.getOrderBy())) + { + String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy()); + PageHelper.orderBy(orderBy); + } + } + + /** + * 清理分页的线程变量 + */ + protected void clearPage() + { + PageUtils.clearPage(); + } + + /** + * 响应请求分页数据 + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected TableDataInfo getDataTable(List list) + { + TableDataInfo rspData = new TableDataInfo(); + rspData.setCode(HttpStatus.SUCCESS); + rspData.setMsg("查询成功"); + rspData.setRows(list); + rspData.setTotal(new PageInfo(list).getTotal()); + return rspData; + } + + /** + * 返回成功 + */ + public AjaxResult success() + { + return AjaxResult.success(); + } + + /** + * 返回失败消息 + */ + public AjaxResult error() + { + return AjaxResult.error(); + } + + /** + * 返回成功消息 + */ + public AjaxResult success(String message) + { + return AjaxResult.success(message); + } + + /** + * 返回成功消息 + */ + public AjaxResult success(Object data) + { + return AjaxResult.success(data); + } + + /** + * 返回失败消息 + */ + public AjaxResult error(String message) + { + return AjaxResult.error(message); + } + + /** + * 返回警告消息 + */ + public AjaxResult warn(String message) + { + return AjaxResult.warn(message); + } + + /** + * 响应返回结果 + * + * @param rows 影响行数 + * @return 操作结果 + */ + protected AjaxResult toAjax(int rows) + { + return rows > 0 ? AjaxResult.success() : AjaxResult.error(); + } + + /** + * 响应返回结果 + * + * @param result 结果 + * @return 操作结果 + */ + protected AjaxResult toAjax(boolean result) + { + return result ? success() : error(); + } + + /** + * 页面跳转 + */ + public String redirect(String url) + { + return StringUtils.format("redirect:{}", url); + } + + /** + * 获取用户缓存信息 + */ + public LoginUser getLoginUser() + { + return SecurityUtils.getLoginUser(); + } + + /** + * 获取登录用户id + */ + public Long getUserId() + { + return getLoginUser().getUserId(); + } + + /** + * 获取登录部门id + */ + public Long getDeptId() + { + return getLoginUser().getDeptId(); + } + + /** + * 获取登录用户名 + */ + public String getUsername() + { + return getLoginUser().getUsername(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/domain/AjaxResult.java b/boyue-common/src/main/java/com/boyue/common/core/domain/AjaxResult.java new file mode 100644 index 0000000..ebba77d --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/domain/AjaxResult.java @@ -0,0 +1,185 @@ +package com.boyue.common.core.domain; + +import java.util.HashMap; +import com.boyue.common.constant.HttpStatus; +import com.boyue.common.utils.StringUtils; + +/** + * 操作消息提醒 + * + * @author boyue + */ +public class AjaxResult extends HashMap +{ + private static final long serialVersionUID = 1L; + + /** 状态码 */ + public static final String CODE_TAG = "code"; + + /** 返回内容 */ + public static final String MSG_TAG = "msg"; + + /** 数据对象 */ + public static final String DATA_TAG = "data"; + + /** + * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。 + */ + public AjaxResult() + { + } + + /** + * 初始化一个新创建的 AjaxResult 对象 + * + * @param code 状态码 + * @param msg 返回内容 + */ + public AjaxResult(int code, String msg) + { + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + } + + /** + * 初始化一个新创建的 AjaxResult 对象 + * + * @param code 状态码 + * @param msg 返回内容 + * @param data 数据对象 + */ + public AjaxResult(int code, String msg, Object data) + { + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + if (StringUtils.isNotNull(data)) + { + super.put(DATA_TAG, data); + } + } + + /** + * 返回成功消息 + * + * @return 成功消息 + */ + public static AjaxResult success() + { + return AjaxResult.success("操作成功"); + } + + /** + * 返回成功数据 + * + * @return 成功消息 + */ + public static AjaxResult success(Object data) + { + return AjaxResult.success("操作成功", data); + } + + /** + * 返回成功消息 + * + * @param msg 返回内容 + * @return 成功消息 + */ + public static AjaxResult success(String msg) + { + return AjaxResult.success(msg, null); + } + + /** + * 返回成功消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 成功消息 + */ + public static AjaxResult success(String msg, Object data) + { + return new AjaxResult(HttpStatus.SUCCESS, msg, data); + } + + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @return 警告消息 + */ + public static AjaxResult warn(String msg) + { + return AjaxResult.warn(msg, null); + } + + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 警告消息 + */ + public static AjaxResult warn(String msg, Object data) + { + return new AjaxResult(HttpStatus.WARN, msg, data); + } + + /** + * 返回错误消息 + * + * @return 错误消息 + */ + public static AjaxResult error() + { + return AjaxResult.error("操作失败"); + } + + /** + * 返回错误消息 + * + * @param msg 返回内容 + * @return 错误消息 + */ + public static AjaxResult error(String msg) + { + return AjaxResult.error(msg, null); + } + + /** + * 返回错误消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 错误消息 + */ + public static AjaxResult error(String msg, Object data) + { + return new AjaxResult(HttpStatus.ERROR, msg, data); + } + + /** + * 返回错误消息 + * + * @param code 状态码 + * @param msg 返回内容 + * @return 错误消息 + */ + public static AjaxResult error(int code, String msg) + { + return new AjaxResult(code, msg, null); + } + + /** + * 方便链式调用 + * + * @param key 键 + * @param value 值 + * @return 数据对象 + */ + @Override + public AjaxResult put(String key, Object value) + { + super.put(key, value); + return this; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/domain/BaseEntity.java b/boyue-common/src/main/java/com/boyue/common/core/domain/BaseEntity.java new file mode 100644 index 0000000..9d84ed5 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/domain/BaseEntity.java @@ -0,0 +1,129 @@ +package com.boyue.common.core.domain; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * Entity基类 + * + * @author boyue + */ +@Schema(title = "基类") +public class BaseEntity implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 搜索值 */ + @Schema(title = "搜索值") + @JsonIgnore + private String searchValue; + + /** 创建者 */ + @Schema(title = "创建者") + private String createBy; + + /** 创建时间 */ + @Schema(title = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + /** 更新者 */ + @Schema(title = "更新者") + private String updateBy; + + /** 更新时间 */ + @Schema(title = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + /** 备注 */ + @Schema(title = "备注") + private String remark; + + /** 请求参数 */ + @Schema(title = "请求参数") + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private Map params; + + public String getSearchValue() + { + return searchValue; + } + + public void setSearchValue(String searchValue) + { + this.searchValue = searchValue; + } + + public String getCreateBy() + { + return createBy; + } + + public void setCreateBy(String createBy) + { + this.createBy = createBy; + } + + public Date getCreateTime() + { + return createTime; + } + + public void setCreateTime(Date createTime) + { + this.createTime = createTime; + } + + public String getUpdateBy() + { + return updateBy; + } + + public void setUpdateBy(String updateBy) + { + this.updateBy = updateBy; + } + + public Date getUpdateTime() + { + return updateTime; + } + + public void setUpdateTime(Date updateTime) + { + this.updateTime = updateTime; + } + + public String getRemark() + { + return remark; + } + + public void setRemark(String remark) + { + this.remark = remark; + } + + public Map getParams() + { + if (params == null) + { + params = new HashMap<>(); + } + return params; + } + + public void setParams(Map params) + { + this.params = params; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/domain/Message.java b/boyue-common/src/main/java/com/boyue/common/core/domain/Message.java new file mode 100644 index 0000000..27dafc7 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/domain/Message.java @@ -0,0 +1,172 @@ +package com.boyue.common.core.domain; + +import java.time.Instant; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +public class Message { + + /** 消息唯一标识符 */ + private String messageId; + /** 发送者标识 */ + private String sender; + /** 接收者标识 */ + private String receiver; + /** 消息时间戳 */ + private Instant timestamp; + /** 消息类型(如命令、聊天、日志、事件等) */ + private String type; + /** 消息主题或事件名称 */ + private String subject; + /** 消息数据负载 */ + private Map payload; + /** 元数据,用于存储额外的信息 */ + private Map metadata; + /** 消息状态(如成功、失败、重试等) */ + private String status; + /** 重试次数 */ + private int retryCount; + /** 最大重试次数 */ + private int maxRetries; + /** 重试间隔 */ + private String retryInterval; + + // 构造函数 + public Message() { + this.messageId = UUID.randomUUID().toString(); + this.timestamp = Instant.now(); + } + + public static Message create() { + return new Message(); + } + + public String getMessageId() { + return messageId; + } + + public Message setMessageId(String messageId) { + this.messageId = messageId; + return this; + } + + public String getSender() { + return sender; + } + + public Message setSender(String sender) { + this.sender = sender; + return this; + } + + public String getReceiver() { + return receiver; + } + + public Message setReceiver(String receiver) { + this.receiver = receiver; + return this; + } + + public Instant getTimestamp() { + return timestamp; + } + + public Message setTimestamp(Instant timestamp) { + this.timestamp = timestamp; + return this; + } + + public String getType() { + return type; + } + + public Message setType(String type) { + this.type = type; + return this; + } + + public String getSubject() { + return subject; + } + + public Message setSubject(String subject) { + this.subject = subject; + return this; + } + + public Map getPayload() { + return payload; + } + + public Message setPayload(Map payload) { + this.payload = payload; + return this; + } + + public Map getMetadata() { + return metadata; + } + + public Message setMetadata(Map metadata) { + this.metadata = metadata; + return this; + } + + public String getStatus() { + return status; + } + + public Message setStatus(String status) { + this.status = status; + return this; + } + + public int getRetryCount() { + return retryCount; + } + + public Message setRetryCount(int retryCount) { + this.retryCount = retryCount; + return this; + } + + public int getMaxRetries() { + return maxRetries; + } + + public Message setMaxRetries(int maxRetries) { + this.maxRetries = maxRetries; + return this; + } + + public String getRetryInterval() { + return retryInterval; + } + + public Message setRetryInterval(String retryInterval) { + this.retryInterval = retryInterval; + return this; + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("messageId", getMessageId()) + .append("sender", getSender()) + .append("receiver", getReceiver()) + .append("timestamp", getTimestamp()) + .append("type", getType()) + .append("subject", getSubject()) + .append("payload", getPayload()) + .append("metadata", getMetadata()) + .append("status", getStatus()) + .append("retryCount", getRetryCount()) + .append("maxRetries", getMaxRetries()) + .append("retryInterval", getRetryInterval()) + .toString(); + } +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/core/domain/R.java b/boyue-common/src/main/java/com/boyue/common/core/domain/R.java new file mode 100644 index 0000000..50abf0d --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/domain/R.java @@ -0,0 +1,122 @@ +package com.boyue.common.core.domain; + +import java.io.Serializable; + +import com.boyue.common.constant.HttpStatus; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 响应信息主体 + * + * @author boyue + */ +@Schema(title = "响应信息主体") +public class R implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 成功 */ + public static final int SUCCESS = HttpStatus.SUCCESS; + + /** 失败 */ + public static final int FAIL = HttpStatus.ERROR; + + @Schema(title = "响应码") + private int code; + + @Schema(title = "响应信息") + private String msg; + + @Schema(title = "响应数据") + private T data; + + public static R ok() + { + return restResult(null, SUCCESS, "操作成功"); + } + + public static R ok(T data) + { + return restResult(data, SUCCESS, "操作成功"); + } + + public static R ok(T data, String msg) + { + return restResult(data, SUCCESS, msg); + } + + public static R fail() + { + return restResult(null, FAIL, "操作失败"); + } + + public static R fail(String msg) + { + return restResult(null, FAIL, msg); + } + + public static R fail(T data) + { + return restResult(data, FAIL, "操作失败"); + } + + public static R fail(T data, String msg) + { + return restResult(data, FAIL, msg); + } + + public static R fail(int code, String msg) + { + return restResult(null, code, msg); + } + + private static R restResult(T data, int code, String msg) + { + R apiResult = new R<>(); + apiResult.setCode(code); + apiResult.setData(data); + apiResult.setMsg(msg); + return apiResult; + } + + public int getCode() + { + return code; + } + + public void setCode(int code) + { + this.code = code; + } + + public String getMsg() + { + return msg; + } + + public void setMsg(String msg) + { + this.msg = msg; + } + + public T getData() + { + return data; + } + + public void setData(T data) + { + this.data = data; + } + + public static Boolean isError(R ret) + { + return !isSuccess(ret); + } + + public static Boolean isSuccess(R ret) + { + return R.SUCCESS == ret.getCode(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/domain/TreeEntity.java b/boyue-common/src/main/java/com/boyue/common/core/domain/TreeEntity.java new file mode 100644 index 0000000..102e8e6 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/domain/TreeEntity.java @@ -0,0 +1,79 @@ +package com.boyue.common.core.domain; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tree基类 + * + * @author boyue + */ +public class TreeEntity extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 父菜单名称 */ + private String parentName; + + /** 父菜单ID */ + private Long parentId; + + /** 显示顺序 */ + private Integer orderNum; + + /** 祖级列表 */ + private String ancestors; + + /** 子部门 */ + private List children = new ArrayList<>(); + + public String getParentName() + { + return parentName; + } + + public void setParentName(String parentName) + { + this.parentName = parentName; + } + + public Long getParentId() + { + return parentId; + } + + public void setParentId(Long parentId) + { + this.parentId = parentId; + } + + public Integer getOrderNum() + { + return orderNum; + } + + public void setOrderNum(Integer orderNum) + { + this.orderNum = orderNum; + } + + public String getAncestors() + { + return ancestors; + } + + public void setAncestors(String ancestors) + { + this.ancestors = ancestors; + } + + public List getChildren() + { + return children; + } + + public void setChildren(List children) + { + this.children = children; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/domain/TreeSelect.java b/boyue-common/src/main/java/com/boyue/common/core/domain/TreeSelect.java new file mode 100644 index 0000000..d5b3052 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/domain/TreeSelect.java @@ -0,0 +1,77 @@ +package com.boyue.common.core.domain; + +import java.io.Serializable; +import java.util.List; +import java.util.stream.Collectors; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.boyue.common.core.domain.entity.SysDept; +import com.boyue.common.core.domain.entity.SysMenu; + +/** + * Treeselect树结构实体类 + * + * @author boyue + */ +public class TreeSelect implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 节点ID */ + private Long id; + + /** 节点名称 */ + private String label; + + /** 子节点 */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private List children; + + public TreeSelect() + { + + } + + public TreeSelect(SysDept dept) + { + this.id = dept.getDeptId(); + this.label = dept.getDeptName(); + this.children = dept.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList()); + } + + public TreeSelect(SysMenu menu) + { + this.id = menu.getMenuId(); + this.label = menu.getMenuName(); + this.children = menu.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList()); + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public String getLabel() + { + return label; + } + + public void setLabel(String label) + { + this.label = label; + } + + public List getChildren() + { + return children; + } + + public void setChildren(List children) + { + this.children = children; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysDept.java b/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysDept.java new file mode 100644 index 0000000..c2d63ef --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysDept.java @@ -0,0 +1,220 @@ +package com.boyue.common.core.domain.entity; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +/** + * 部门表 sys_dept + * + * @author boyue + */ +@Schema(title = "部门") +public class SysDept extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 部门ID */ + @Schema(title = "部门ID") + private Long deptId; + + /** 父部门ID */ + @Schema(title = "父部门ID") + private Long parentId; + + /** 祖级列表 */ + @Schema(title = "祖级列表") + private String ancestors; + + /** 部门名称 */ + @Schema(title = "部门名称") + private String deptName; + + /** 显示顺序 */ + @Schema(title = "显示顺序") + private Integer orderNum; + + /** 负责人 */ + @Schema(title = "负责人") + private String leader; + + /** 联系电话 */ + @Schema(title = "联系电话") + private String phone; + + /** 邮箱 */ + @Schema(title = "邮箱") + private String email; + + /** 部门状态:0正常,1停用 */ + @Schema(title = "部门表",description = "0正常,1停用") + private String status; + + /** 删除标志(0代表存在 2代表删除) */ + @Schema(title = "删除标志",description = "0代表存在 2代表删除") + private String delFlag; + + /** 父部门名称 */ + @Schema(title = "父部门名称") + private String parentName; + + /** 子部门 */ + @Schema(title = "子部门") + private List children = new ArrayList(); + + public Long getDeptId() + { + return deptId; + } + + public void setDeptId(Long deptId) + { + this.deptId = deptId; + } + + public Long getParentId() + { + return parentId; + } + + public void setParentId(Long parentId) + { + this.parentId = parentId; + } + + public String getAncestors() + { + return ancestors; + } + + public void setAncestors(String ancestors) + { + this.ancestors = ancestors; + } + + @NotBlank(message = "部门名称不能为空") + @Size(min = 0, max = 30, message = "部门名称长度不能超过30个字符") + public String getDeptName() + { + return deptName; + } + + public void setDeptName(String deptName) + { + this.deptName = deptName; + } + + @NotNull(message = "显示顺序不能为空") + public Integer getOrderNum() + { + return orderNum; + } + + public void setOrderNum(Integer orderNum) + { + this.orderNum = orderNum; + } + + public String getLeader() + { + return leader; + } + + public void setLeader(String leader) + { + this.leader = leader; + } + + @Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符") + public String getPhone() + { + return phone; + } + + public void setPhone(String phone) + { + this.phone = phone; + } + + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") + public String getEmail() + { + return email; + } + + public void setEmail(String email) + { + this.email = email; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getDelFlag() + { + return delFlag; + } + + public void setDelFlag(String delFlag) + { + this.delFlag = delFlag; + } + + public String getParentName() + { + return parentName; + } + + public void setParentName(String parentName) + { + this.parentName = parentName; + } + + public List getChildren() + { + return children; + } + + public void setChildren(List children) + { + this.children = children; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("deptId", getDeptId()) + .append("parentId", getParentId()) + .append("ancestors", getAncestors()) + .append("deptName", getDeptName()) + .append("orderNum", getOrderNum()) + .append("leader", getLeader()) + .append("phone", getPhone()) + .append("email", getEmail()) + .append("status", getStatus()) + .append("delFlag", getDelFlag()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .toString(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysDictData.java b/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysDictData.java new file mode 100644 index 0000000..18e1d77 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysDictData.java @@ -0,0 +1,189 @@ +package com.boyue.common.core.domain.entity; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.annotation.Excel.ColumnType; +import com.boyue.common.constant.UserConstants; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +/** + * 字典数据表 sys_dict_data + * + * @author boyue + */ +@Schema(title = "字典数据") +public class SysDictData extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 字典编码 */ + @Schema(title = "字典编码") + @Excel(name = "字典编码", cellType = ColumnType.NUMERIC) + private Long dictCode; + + /** 字典排序 */ + @Schema(title = "字典排序") + @Excel(name = "字典排序", cellType = ColumnType.NUMERIC) + private Long dictSort; + + /** 字典标签 */ + @Schema(title = "字典标签") + @Excel(name = "字典标签") + private String dictLabel; + + /** 字典键值 */ + @Schema(title = "字典键值") + @Excel(name = "字典键值") + private String dictValue; + + /** 字典类型 */ + @Schema(title = "字典类型") + @Excel(name = "字典类型") + private String dictType; + + /** 样式属性(其他样式扩展) */ + @Schema(title = "样式属性", description = "其他样式扩展") + private String cssClass; + + /** 表格字典样式 */ + @Schema(title = "表格字典样式") + private String listClass; + + /** 是否默认(Y是 N否) */ + @Schema(title = "是否默认", description = "Y=是,N=否") + @Excel(name = "是否默认", readConverterExp = "Y=是,N=否") + private String isDefault; + + /** 状态(0正常 1停用) */ + @Schema(title = "状态", description = "0=正常,1=停用") + @Excel(name = "状态", readConverterExp = "0=正常,1=停用") + private String status; + + public Long getDictCode() + { + return dictCode; + } + + public void setDictCode(Long dictCode) + { + this.dictCode = dictCode; + } + + public Long getDictSort() + { + return dictSort; + } + + public void setDictSort(Long dictSort) + { + this.dictSort = dictSort; + } + + @NotBlank(message = "字典标签不能为空") + @Size(min = 0, max = 100, message = "字典标签长度不能超过100个字符") + public String getDictLabel() + { + return dictLabel; + } + + public void setDictLabel(String dictLabel) + { + this.dictLabel = dictLabel; + } + + @NotBlank(message = "字典键值不能为空") + @Size(min = 0, max = 100, message = "字典键值长度不能超过100个字符") + public String getDictValue() + { + return dictValue; + } + + public void setDictValue(String dictValue) + { + this.dictValue = dictValue; + } + + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型长度不能超过100个字符") + public String getDictType() + { + return dictType; + } + + public void setDictType(String dictType) + { + this.dictType = dictType; + } + + @Size(min = 0, max = 100, message = "样式属性长度不能超过100个字符") + public String getCssClass() + { + return cssClass; + } + + public void setCssClass(String cssClass) + { + this.cssClass = cssClass; + } + + public String getListClass() + { + return listClass; + } + + public void setListClass(String listClass) + { + this.listClass = listClass; + } + + public boolean getDefault() + { + return UserConstants.YES.equals(this.isDefault); + } + + public String getIsDefault() + { + return isDefault; + } + + public void setIsDefault(String isDefault) + { + this.isDefault = isDefault; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("dictCode", getDictCode()) + .append("dictSort", getDictSort()) + .append("dictLabel", getDictLabel()) + .append("dictValue", getDictValue()) + .append("dictType", getDictType()) + .append("cssClass", getCssClass()) + .append("listClass", getListClass()) + .append("isDefault", getIsDefault()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysDictType.java b/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysDictType.java new file mode 100644 index 0000000..0847495 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysDictType.java @@ -0,0 +1,104 @@ +package com.boyue.common.core.domain.entity; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.annotation.Excel.ColumnType; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; + +/** + * 字典类型表 sys_dict_type + * + * @author boyue + */ +@Schema(title = "字典类型") +public class SysDictType extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 字典主键 */ + @Schema(title = "字典主键") + @Excel(name = "字典主键", cellType = ColumnType.NUMERIC) + private Long dictId; + + /** 字典名称 */ + @Schema(title = "字典名称") + @Excel(name = "字典名称") + private String dictName; + + /** 字典类型 */ + @Schema(title = "字典类型") + @Excel(name = "字典类型") + private String dictType; + + /** 状态(0正常 1停用) */ + @Schema(title = "状态", description = "0正常 1停用") + @Excel(name = "状态", readConverterExp = "0=正常,1=停用") + private String status; + + public Long getDictId() + { + return dictId; + } + + public void setDictId(Long dictId) + { + this.dictId = dictId; + } + + @NotBlank(message = "字典名称不能为空") + @Size(min = 0, max = 100, message = "字典类型名称长度不能超过100个字符") + public String getDictName() + { + return dictName; + } + + public void setDictName(String dictName) + { + this.dictName = dictName; + } + + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符") + @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)") + public String getDictType() + { + return dictType; + } + + public void setDictType(String dictType) + { + this.dictType = dictType; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("dictId", getDictId()) + .append("dictName", getDictName()) + .append("dictType", getDictType()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysMenu.java b/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysMenu.java new file mode 100644 index 0000000..9d909bf --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysMenu.java @@ -0,0 +1,260 @@ +package com.boyue.common.core.domain.entity; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +/** + * 菜单权限表 sys_menu + * + * @author boyue + */ +@Schema(title = "菜单权限") +public class SysMenu extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** 菜单ID */ + @Schema(title = "菜单ID") + private Long menuId; + + /** 菜单名称 */ + @Schema(title = "菜单名称") + private String menuName; + + /** 父菜单名称 */ + @Schema(title = "父菜单名称") + private String parentName; + + /** 父菜单ID */ + @Schema(title = "父菜单ID") + private Long parentId; + + /** 显示顺序 */ + @Schema(title = "显示顺序") + private Integer orderNum; + + /** 路由地址 */ + @Schema(title = "路由地址") + private String path; + + /** 组件路径 */ + @Schema(title = "组件路径") + private String component; + + /** 路由参数 */ + @Schema(title = "路由参数") + private String query; + + /** 路由名称,默认和路由地址相同的驼峰格式(注意:因为vue3版本的router会删除名称相同路由,为避免名字的冲突,特殊情况可以自定义) */ + private String routeName; + + /** 是否为外链(0是 1否) */ + @Schema(title = "是否为外链", description = "0是 1否") + private String isFrame; + + /** 是否缓存(0缓存 1不缓存) */ + @Schema(title = "是否缓存", description = "0缓存 1不缓存") + private String isCache; + + /** 类型(M目录 C菜单 F按钮) */ + @Schema(title = "类型", description = "M目录 C菜单 F按钮") + private String menuType; + + /** 显示状态(0显示 1隐藏) */ + @Schema(title = "显示状态", description = "0显示 1隐藏") + private String visible; + + /** 菜单状态(0正常 1停用) */ + @Schema(title = "菜单状态", description = "0正常 1停用") + private String status; + + /** 权限字符串 */ + @Schema(title = "权限字符串") + private String perms; + + /** 菜单图标 */ + @Schema(title = "菜单图标") + private String icon; + + /** 子菜单 */ + @Schema(title = "子菜单") + private List children = new ArrayList(); + + public Long getMenuId() { + return menuId; + } + + public void setMenuId(Long menuId) { + this.menuId = menuId; + } + + @NotBlank(message = "菜单名称不能为空") + @Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符") + public String getMenuName() { + return menuName; + } + + public void setMenuName(String menuName) { + this.menuName = menuName; + } + + public String getParentName() { + return parentName; + } + + public void setParentName(String parentName) { + this.parentName = parentName; + } + + public Long getParentId() { + return parentId; + } + + public void setParentId(Long parentId) { + this.parentId = parentId; + } + + @NotNull(message = "显示顺序不能为空") + public Integer getOrderNum() { + return orderNum; + } + + public void setOrderNum(Integer orderNum) { + this.orderNum = orderNum; + } + + @Size(min = 0, max = 200, message = "路由地址不能超过200个字符") + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + @Size(min = 0, max = 200, message = "组件路径不能超过255个字符") + public String getComponent() { + return component; + } + + public void setComponent(String component) { + this.component = component; + } + + public String getQuery() { + return query; + } + + public void setQuery(String query) { + this.query = query; + } + + public String getRouteName() { + return routeName; + } + + public void setRouteName(String routeName) { + this.routeName = routeName; + } + + public String getIsFrame() { + return isFrame; + } + + public void setIsFrame(String isFrame) { + this.isFrame = isFrame; + } + + public String getIsCache() { + return isCache; + } + + public void setIsCache(String isCache) { + this.isCache = isCache; + } + + @NotBlank(message = "菜单类型不能为空") + public String getMenuType() { + return menuType; + } + + public void setMenuType(String menuType) { + this.menuType = menuType; + } + + public String getVisible() { + return visible; + } + + public void setVisible(String visible) { + this.visible = visible; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符") + public String getPerms() { + return perms; + } + + public void setPerms(String perms) { + this.perms = perms; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("menuId", getMenuId()) + .append("menuName", getMenuName()) + .append("parentId", getParentId()) + .append("orderNum", getOrderNum()) + .append("path", getPath()) + .append("component", getComponent()) + .append("query", getQuery()) + .append("routeName", getRouteName()) + .append("isFrame", getIsFrame()) + .append("IsCache", getIsCache()) + .append("menuType", getMenuType()) + .append("visible", getVisible()) + .append("status ", getStatus()) + .append("perms", getPerms()) + .append("icon", getIcon()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysRole.java b/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysRole.java new file mode 100644 index 0000000..66fc321 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysRole.java @@ -0,0 +1,259 @@ +package com.boyue.common.core.domain.entity; + +import java.util.Set; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.annotation.Excel.ColumnType; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +/** + * 角色表 sys_role + * + * @author boyue + */ +@Schema(title = "角色表") +public class SysRole extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 角色ID */ + @Schema(title = "角色ID") + @Excel(name = "角色序号", cellType = ColumnType.NUMERIC) + private Long roleId; + + /** 角色名称 */ + @Schema(title = "角色名称") + @Excel(name = "角色名称") + private String roleName; + + /** 角色权限 */ + @Schema(title = "角色权限") + @Excel(name = "角色权限") + private String roleKey; + + /** 角色排序 */ + @Schema(title = "角色排序") + @Excel(name = "角色排序") + private Integer roleSort; + + /** 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) */ + @Schema(title = "数据范围", description = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限") + @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限") + private String dataScope; + + /** 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) */ + @Schema(title = "菜单树选择项是否关联显示", description = "0:父子不互相关联显示 1:父子互相关联显示") + private boolean menuCheckStrictly; + + /** 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 ) */ + @Schema(title = "部门树选择项是否关联显示", description = "0:父子不互相关联显示 1:父子互相关联显示 ") + private boolean deptCheckStrictly; + + /** 角色状态(0正常 1停用) */ + @Schema(title = "角色状态", description = "0正常 1停用") + @Excel(name = "角色状态", readConverterExp = "0=正常,1=停用") + private String status; + + /** 删除标志(0代表存在 2代表删除) */ + @Schema(title = "删除标志", description = "0代表存在 2代表删除") + private String delFlag; + + /** 用户是否存在此角色标识 默认不存在 */ + @Schema(title = "用户是否存在此角色标识", description = "默认不存在") + private boolean flag = false; + + /** 菜单组 */ + @Schema(title = "菜单组") + private Long[] menuIds; + + /** 部门组(数据权限) */ + @Schema(title = "部门组", description = "数据权限") + private Long[] deptIds; + + /** 角色菜单权限 */ + @Schema(title = "角色菜单权限") + private Set permissions; + + public SysRole() + { + + } + + public SysRole(Long roleId) + { + this.roleId = roleId; + } + + public Long getRoleId() + { + return roleId; + } + + public void setRoleId(Long roleId) + { + this.roleId = roleId; + } + + public boolean isAdmin() + { + return isAdmin(this.roleId); + } + + public static boolean isAdmin(Long roleId) + { + return roleId != null && 1L == roleId; + } + + @NotBlank(message = "角色名称不能为空") + @Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符") + public String getRoleName() + { + return roleName; + } + + public void setRoleName(String roleName) + { + this.roleName = roleName; + } + + @NotBlank(message = "权限字符不能为空") + @Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符") + public String getRoleKey() + { + return roleKey; + } + + public void setRoleKey(String roleKey) + { + this.roleKey = roleKey; + } + + @NotNull(message = "显示顺序不能为空") + public Integer getRoleSort() + { + return roleSort; + } + + public void setRoleSort(Integer roleSort) + { + this.roleSort = roleSort; + } + + public String getDataScope() + { + return dataScope; + } + + public void setDataScope(String dataScope) + { + this.dataScope = dataScope; + } + + public boolean isMenuCheckStrictly() + { + return menuCheckStrictly; + } + + public void setMenuCheckStrictly(boolean menuCheckStrictly) + { + this.menuCheckStrictly = menuCheckStrictly; + } + + public boolean isDeptCheckStrictly() + { + return deptCheckStrictly; + } + + public void setDeptCheckStrictly(boolean deptCheckStrictly) + { + this.deptCheckStrictly = deptCheckStrictly; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getDelFlag() + { + return delFlag; + } + + public void setDelFlag(String delFlag) + { + this.delFlag = delFlag; + } + + public boolean isFlag() + { + return flag; + } + + public void setFlag(boolean flag) + { + this.flag = flag; + } + + public Long[] getMenuIds() + { + return menuIds; + } + + public void setMenuIds(Long[] menuIds) + { + this.menuIds = menuIds; + } + + public Long[] getDeptIds() + { + return deptIds; + } + + public void setDeptIds(Long[] deptIds) + { + this.deptIds = deptIds; + } + + public Set getPermissions() + { + return permissions; + } + + public void setPermissions(Set permissions) + { + this.permissions = permissions; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("roleId", getRoleId()) + .append("roleName", getRoleName()) + .append("roleKey", getRoleKey()) + .append("roleSort", getRoleSort()) + .append("dataScope", getDataScope()) + .append("menuCheckStrictly", isMenuCheckStrictly()) + .append("deptCheckStrictly", isDeptCheckStrictly()) + .append("status", getStatus()) + .append("delFlag", getDelFlag()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysUser.java b/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysUser.java new file mode 100644 index 0000000..9fe1a12 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/domain/entity/SysUser.java @@ -0,0 +1,349 @@ +package com.boyue.common.core.domain.entity; + +import java.util.Date; +import java.util.List; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.annotation.Excel.ColumnType; +import com.boyue.common.annotation.Excel.Type; +import com.boyue.common.annotation.Excels; +import com.boyue.common.core.domain.BaseEntity; +import com.boyue.common.xss.Xss; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +/** + * 用户对象 sys_user + * + * @author boyue + */ +@Schema(title = "用户") +public class SysUser extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 用户ID */ + @Schema(title = "用户序号") + @Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号") + private Long userId; + + /** 部门ID */ + @Schema(title = "部门编号") + @Excel(name = "部门编号", type = Type.IMPORT) + private Long deptId; + + /** 用户账号 */ + @Schema(title = "登录名称") + @Excel(name = "登录名称") + private String userName; + + /** 用户昵称 */ + @Schema(title = "用户名称") + @Excel(name = "用户名称") + private String nickName; + + /** 用户邮箱 */ + @Schema(title = "用户邮箱") + @Excel(name = "用户邮箱") + private String email; + + /** 手机号码 */ + @Schema(title = "手机号码") + @Excel(name = "手机号码") + private String phonenumber; + + /** 用户性别 */ + @Schema(title = "用户性别", description = "0=男,1=女,2=未知") + @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知") + private String sex; + + /** 用户头像 */ + @Schema(title = "用户头像") + private String avatar; + + /** 密码 */ + @Schema(title = "密码") + private String password; + + /** 帐号状态(0正常 1停用) */ + @Schema(title = "帐号状态", description = "0正常 1停用") + @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用") + private String status; + + /** 删除标志(0代表存在 2代表删除) */ + @Schema(title = "删除标志", description = "0代表存在 2代表删除") + private String delFlag; + + /** 最后登录IP */ + @Schema(title = "最后登录IP") + @Excel(name = "最后登录IP", type = Type.EXPORT) + private String loginIp; + + /** 最后登录时间 */ + @Schema(title = "最后登录时间") + @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT) + private Date loginDate; + + /** 部门对象 */ + @Schema(title = "部门对象") + @Excels({ + @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT), + @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT) + }) + private SysDept dept; + + /** 角色对象 */ + @Schema(title = "角色对象") + private List roles; + + /** 角色组 */ + @Schema(title = "角色组") + private Long[] roleIds; + + /** 岗位组 */ + @Schema(title = "岗位组") + private Long[] postIds; + + /** 角色ID */ + @Schema(title = "角色ID") + private Long roleId; + + public SysUser() + { + + } + + public SysUser(Long userId) + { + this.userId = userId; + } + + public Long getUserId() + { + return userId; + } + + public void setUserId(Long userId) + { + this.userId = userId; + } + + public boolean isAdmin() + { + return isAdmin(this.userId); + } + + public static boolean isAdmin(Long userId) + { + return userId != null && 1L == userId; + } + + public Long getDeptId() + { + return deptId; + } + + public void setDeptId(Long deptId) + { + this.deptId = deptId; + } + + @Xss(message = "用户昵称不能包含脚本字符") + @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符") + public String getNickName() + { + return nickName; + } + + public void setNickName(String nickName) + { + this.nickName = nickName; + } + + @Xss(message = "用户账号不能包含脚本字符") + @NotBlank(message = "用户账号不能为空") + @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符") + public String getUserName() + { + return userName; + } + + public void setUserName(String userName) + { + this.userName = userName; + } + + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") + public String getEmail() + { + return email; + } + + public void setEmail(String email) + { + this.email = email; + } + + @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符") + public String getPhonenumber() + { + return phonenumber; + } + + public void setPhonenumber(String phonenumber) + { + this.phonenumber = phonenumber; + } + + public String getSex() + { + return sex; + } + + public void setSex(String sex) + { + this.sex = sex; + } + + public String getAvatar() + { + return avatar; + } + + public void setAvatar(String avatar) + { + this.avatar = avatar; + } + + public String getPassword() + { + return password; + } + + public void setPassword(String password) + { + this.password = password; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getDelFlag() + { + return delFlag; + } + + public void setDelFlag(String delFlag) + { + this.delFlag = delFlag; + } + + public String getLoginIp() + { + return loginIp; + } + + public void setLoginIp(String loginIp) + { + this.loginIp = loginIp; + } + + public Date getLoginDate() + { + return loginDate; + } + + public void setLoginDate(Date loginDate) + { + this.loginDate = loginDate; + } + + public SysDept getDept() + { + return dept; + } + + public void setDept(SysDept dept) + { + this.dept = dept; + } + + public List getRoles() + { + return roles; + } + + public void setRoles(List roles) + { + this.roles = roles; + } + + public Long[] getRoleIds() + { + return roleIds; + } + + public void setRoleIds(Long[] roleIds) + { + this.roleIds = roleIds; + } + + public Long[] getPostIds() + { + return postIds; + } + + public void setPostIds(Long[] postIds) + { + this.postIds = postIds; + } + + public Long getRoleId() + { + return roleId; + } + + public void setRoleId(Long roleId) + { + this.roleId = roleId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("userId", getUserId()) + .append("deptId", getDeptId()) + .append("userName", getUserName()) + .append("nickName", getNickName()) + .append("email", getEmail()) + .append("phonenumber", getPhonenumber()) + .append("sex", getSex()) + .append("avatar", getAvatar()) + .append("password", getPassword()) + .append("status", getStatus()) + .append("delFlag", getDelFlag()) + .append("loginIp", getLoginIp()) + .append("loginDate", getLoginDate()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .append("dept", getDept()) + .toString(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/domain/model/LoginBody.java b/boyue-common/src/main/java/com/boyue/common/core/domain/model/LoginBody.java new file mode 100644 index 0000000..4909be9 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/domain/model/LoginBody.java @@ -0,0 +1,97 @@ +package com.boyue.common.core.domain.model; + +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 用户登录对象 + * + * @author boyue + */ +@Schema(title = "用户登录对象") +public class LoginBody extends BaseEntity { + /** + * 用户名 + */ + @Schema(title = "用户名") + private String username; + + /** + * 用户密码 + */ + @Schema(title = "用户密码") + private String password; + + /** + * 手机号码 + */ + @Schema(title = "手机号码") + private String phonenumber; + + /** + * 邮箱 + */ + @Schema(title = "邮箱") + private String email; + + /** + * 验证码 + */ + @Schema(title = "验证码") + private String code; + + /** + * 唯一标识 + */ + @Schema(title = "唯一标识") + private String uuid; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getPhonenumber() { + return phonenumber; + } + + public void setPhonenumber(String phonenumber) { + this.phonenumber = phonenumber; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/domain/model/LoginUser.java b/boyue-common/src/main/java/com/boyue/common/core/domain/model/LoginUser.java new file mode 100644 index 0000000..c92b53b --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/domain/model/LoginUser.java @@ -0,0 +1,266 @@ +package com.boyue.common.core.domain.model; + +import java.util.Collection; +import java.util.Set; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import com.alibaba.fastjson2.annotation.JSONField; +import com.boyue.common.core.domain.entity.SysUser; + +/** + * 登录用户身份权限 + * + * @author boyue + */ +public class LoginUser implements UserDetails +{ + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 用户唯一标识 + */ + private String token; + + /** + * 登录时间 + */ + private Long loginTime; + + /** + * 过期时间 + */ + private Long expireTime; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地点 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 权限列表 + */ + private Set permissions; + + /** + * 用户信息 + */ + private SysUser user; + + public Long getUserId() + { + return userId; + } + + public void setUserId(Long userId) + { + this.userId = userId; + } + + public Long getDeptId() + { + return deptId; + } + + public void setDeptId(Long deptId) + { + this.deptId = deptId; + } + + public String getToken() + { + return token; + } + + public void setToken(String token) + { + this.token = token; + } + + public LoginUser() + { + } + + public LoginUser(SysUser user, Set permissions) + { + this.user = user; + this.permissions = permissions; + } + + public LoginUser(Long userId, Long deptId, SysUser user, Set permissions) + { + this.userId = userId; + this.deptId = deptId; + this.user = user; + this.permissions = permissions; + } + + @JSONField(serialize = false) + @Override + public String getPassword() + { + return user.getPassword(); + } + + @Override + public String getUsername() + { + return user.getUserName(); + } + + /** + * 账户是否未过期,过期无法验证 + */ + @JSONField(serialize = false) + @Override + public boolean isAccountNonExpired() + { + return true; + } + + /** + * 指定用户是否解锁,锁定的用户无法进行身份验证 + * + * @return + */ + @JSONField(serialize = false) + @Override + public boolean isAccountNonLocked() + { + return true; + } + + /** + * 指示是否已过期的用户的凭据(密码),过期的凭据防止认证 + * + * @return + */ + @JSONField(serialize = false) + @Override + public boolean isCredentialsNonExpired() + { + return true; + } + + /** + * 是否可用 ,禁用的用户不能身份验证 + * + * @return + */ + @JSONField(serialize = false) + @Override + public boolean isEnabled() + { + return true; + } + + public Long getLoginTime() + { + return loginTime; + } + + public void setLoginTime(Long loginTime) + { + this.loginTime = loginTime; + } + + public String getIpaddr() + { + return ipaddr; + } + + public void setIpaddr(String ipaddr) + { + this.ipaddr = ipaddr; + } + + public String getLoginLocation() + { + return loginLocation; + } + + public void setLoginLocation(String loginLocation) + { + this.loginLocation = loginLocation; + } + + public String getBrowser() + { + return browser; + } + + public void setBrowser(String browser) + { + this.browser = browser; + } + + public String getOs() + { + return os; + } + + public void setOs(String os) + { + this.os = os; + } + + public Long getExpireTime() + { + return expireTime; + } + + public void setExpireTime(Long expireTime) + { + this.expireTime = expireTime; + } + + public Set getPermissions() + { + return permissions; + } + + public void setPermissions(Set permissions) + { + this.permissions = permissions; + } + + public SysUser getUser() + { + return user; + } + + public void setUser(SysUser user) + { + this.user = user; + } + + @Override + public Collection getAuthorities() + { + return null; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/domain/model/RegisterBody.java b/boyue-common/src/main/java/com/boyue/common/core/domain/model/RegisterBody.java new file mode 100644 index 0000000..a04e437 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/domain/model/RegisterBody.java @@ -0,0 +1,14 @@ +package com.boyue.common.core.domain.model; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 用户注册对象 + * + * @author boyue + */ +@Schema(title = "用户注册对象") +public class RegisterBody extends LoginBody +{ + +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/page/PageDomain.java b/boyue-common/src/main/java/com/boyue/common/core/page/PageDomain.java new file mode 100644 index 0000000..c38b8b5 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/page/PageDomain.java @@ -0,0 +1,101 @@ +package com.boyue.common.core.page; + +import com.boyue.common.utils.StringUtils; + +/** + * 分页数据 + * + * @author boyue + */ +public class PageDomain +{ + /** 当前记录起始索引 */ + private Integer pageNum; + + /** 每页显示记录数 */ + private Integer pageSize; + + /** 排序列 */ + private String orderByColumn; + + /** 排序的方向desc或者asc */ + private String isAsc = "asc"; + + /** 分页参数合理化 */ + private Boolean reasonable = true; + + public String getOrderBy() + { + if (StringUtils.isEmpty(orderByColumn)) + { + return ""; + } + return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc; + } + + public Integer getPageNum() + { + return pageNum; + } + + public void setPageNum(Integer pageNum) + { + this.pageNum = pageNum; + } + + public Integer getPageSize() + { + return pageSize; + } + + public void setPageSize(Integer pageSize) + { + this.pageSize = pageSize; + } + + public String getOrderByColumn() + { + return orderByColumn; + } + + public void setOrderByColumn(String orderByColumn) + { + this.orderByColumn = orderByColumn; + } + + public String getIsAsc() + { + return isAsc; + } + + public void setIsAsc(String isAsc) + { + if (StringUtils.isNotEmpty(isAsc)) + { + // 兼容前端排序类型 + if ("ascending".equals(isAsc)) + { + isAsc = "asc"; + } + else if ("descending".equals(isAsc)) + { + isAsc = "desc"; + } + this.isAsc = isAsc; + } + } + + public Boolean getReasonable() + { + if (StringUtils.isNull(reasonable)) + { + return Boolean.TRUE; + } + return reasonable; + } + + public void setReasonable(Boolean reasonable) + { + this.reasonable = reasonable; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/page/TableDataInfo.java b/boyue-common/src/main/java/com/boyue/common/core/page/TableDataInfo.java new file mode 100644 index 0000000..203a992 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/page/TableDataInfo.java @@ -0,0 +1,92 @@ +package com.boyue.common.core.page; + +import java.io.Serializable; +import java.util.List; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 表格分页数据对象 + * + * @author boyue + */ +@Schema(title = "表格分页数据对象") +public class TableDataInfo implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 总记录数 */ + @Schema(title = "总记录数") + private long total; + + /** 列表数据 */ + @Schema(title = "列表数据") + private List rows; + + /** 消息状态码 */ + @Schema(title = "消息状态码") + private int code; + + /** 消息内容 */ + @Schema(title = "消息内容") + private String msg; + + /** + * 表格数据对象 + */ + public TableDataInfo() + { + } + + /** + * 分页 + * + * @param list 列表数据 + * @param total 总记录数 + */ + public TableDataInfo(List list, int total) + { + this.rows = list; + this.total = total; + } + + public long getTotal() + { + return total; + } + + public void setTotal(long total) + { + this.total = total; + } + + public List getRows() + { + return rows; + } + + public void setRows(List rows) + { + this.rows = rows; + } + + public int getCode() + { + return code; + } + + public void setCode(int code) + { + this.code = code; + } + + public String getMsg() + { + return msg; + } + + public void setMsg(String msg) + { + this.msg = msg; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/page/TableSupport.java b/boyue-common/src/main/java/com/boyue/common/core/page/TableSupport.java new file mode 100644 index 0000000..8ae24b8 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/page/TableSupport.java @@ -0,0 +1,56 @@ +package com.boyue.common.core.page; + +import com.boyue.common.core.text.Convert; +import com.boyue.common.utils.ServletUtils; + +/** + * 表格数据处理 + * + * @author boyue + */ +public class TableSupport +{ + /** + * 当前记录起始索引 + */ + public static final String PAGE_NUM = "pageNum"; + + /** + * 每页显示记录数 + */ + public static final String PAGE_SIZE = "pageSize"; + + /** + * 排序列 + */ + public static final String ORDER_BY_COLUMN = "orderByColumn"; + + /** + * 排序的方向 "desc" 或者 "asc". + */ + public static final String IS_ASC = "isAsc"; + + /** + * 分页参数合理化 + */ + public static final String REASONABLE = "reasonable"; + + /** + * 封装分页对象 + */ + public static PageDomain getPageDomain() + { + PageDomain pageDomain = new PageDomain(); + pageDomain.setPageNum(Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1)); + pageDomain.setPageSize(Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10)); + pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN)); + pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC)); + pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE)); + return pageDomain; + } + + public static PageDomain buildPageRequest() + { + return getPageDomain(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/security/service/IPermissionService.java b/boyue-common/src/main/java/com/boyue/common/core/security/service/IPermissionService.java new file mode 100644 index 0000000..dfe6151 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/security/service/IPermissionService.java @@ -0,0 +1,56 @@ +package com.boyue.common.core.security.service; + +public interface IPermissionService { + + /** + * 验证用户是否具备某权限 + * + * @param permission 权限字符串 + * @return 用户是否具备某权限 + */ + boolean hasPermi(String permission); + + /** + * 验证用户是否不具备某权限,与 hasPermi 逻辑相反 + * + * @param permission 权限字符串 + * @return 用户是否不具备某权限 + */ + default boolean lacksPermi(String permission) { + return !hasPermi(permission); + } + + /** + * 验证用户是否具有以下任意一个权限 + * + * @param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表 + * @return 用户是否具有以下任意一个权限 + */ + boolean hasAnyPermi(String permissions); + + /** + * 判断用户是否拥有某个角色 + * + * @param role 角色字符串 + * @return 用户是否具备某角色 + */ + boolean hasRole(String role); + + /** + * 验证用户是否不具备某角色,与 hasRole 逻辑相反。 + * + * @param role 角色名称 + * @return 用户是否不具备某角色 + */ + default boolean lacksRole(String role) { + return !hasRole(role); + } + + /** + * 验证用户是否具有以下任意一个角色 + * + * @param roles 以 ROLE_DELIMETER 为分隔符的角色列表 + * @return 用户是否具有以下任意一个角色 + */ + boolean hasAnyRoles(String roles); +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/core/text/CharsetKit.java b/boyue-common/src/main/java/com/boyue/common/core/text/CharsetKit.java new file mode 100644 index 0000000..dbf7a0a --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/text/CharsetKit.java @@ -0,0 +1,86 @@ +package com.boyue.common.core.text; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import com.boyue.common.utils.StringUtils; + +/** + * 字符集工具类 + * + * @author boyue + */ +public class CharsetKit +{ + /** ISO-8859-1 */ + public static final String ISO_8859_1 = "ISO-8859-1"; + /** UTF-8 */ + public static final String UTF_8 = "UTF-8"; + /** GBK */ + public static final String GBK = "GBK"; + + /** ISO-8859-1 */ + public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1); + /** UTF-8 */ + public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8); + /** GBK */ + public static final Charset CHARSET_GBK = Charset.forName(GBK); + + /** + * 转换为Charset对象 + * + * @param charset 字符集,为空则返回默认字符集 + * @return Charset + */ + public static Charset charset(String charset) + { + return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset); + } + + /** + * 转换字符串的字符集编码 + * + * @param source 字符串 + * @param srcCharset 源字符集,默认ISO-8859-1 + * @param destCharset 目标字符集,默认UTF-8 + * @return 转换后的字符集 + */ + public static String convert(String source, String srcCharset, String destCharset) + { + return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset)); + } + + /** + * 转换字符串的字符集编码 + * + * @param source 字符串 + * @param srcCharset 源字符集,默认ISO-8859-1 + * @param destCharset 目标字符集,默认UTF-8 + * @return 转换后的字符集 + */ + public static String convert(String source, Charset srcCharset, Charset destCharset) + { + if (null == srcCharset) + { + srcCharset = StandardCharsets.ISO_8859_1; + } + + if (null == destCharset) + { + destCharset = StandardCharsets.UTF_8; + } + + if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) + { + return source; + } + return new String(source.getBytes(srcCharset), destCharset); + } + + /** + * @return 系统字符集编码 + */ + public static String systemCharset() + { + return Charset.defaultCharset().name(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/text/Convert.java b/boyue-common/src/main/java/com/boyue/common/core/text/Convert.java new file mode 100644 index 0000000..96b468f --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/text/Convert.java @@ -0,0 +1,1006 @@ +package com.boyue.common.core.text; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.text.NumberFormat; +import java.util.Set; + +import org.apache.commons.lang3.ArrayUtils; + +import com.boyue.common.utils.StringUtils; + +/** + * 类型转换器 + * + * @author boyue + */ +public class Convert +{ + /** + * 转换为字符串
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static String toStr(Object value, String defaultValue) + { + if (null == value) + { + return defaultValue; + } + if (value instanceof String) + { + return (String) value; + } + return value.toString(); + } + + /** + * 转换为字符串
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static String toStr(Object value) + { + return toStr(value, null); + } + + /** + * 转换为字符
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Character toChar(Object value, Character defaultValue) + { + if (null == value) + { + return defaultValue; + } + if (value instanceof Character) + { + return (Character) value; + } + + final String valueStr = toStr(value, null); + return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0); + } + + /** + * 转换为字符
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Character toChar(Object value) + { + return toChar(value, null); + } + + /** + * 转换为byte
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Byte toByte(Object value, Byte defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Byte) + { + return (Byte) value; + } + if (value instanceof Number) + { + return ((Number) value).byteValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Byte.parseByte(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为byte
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Byte toByte(Object value) + { + return toByte(value, null); + } + + /** + * 转换为Short
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Short toShort(Object value, Short defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Short) + { + return (Short) value; + } + if (value instanceof Number) + { + return ((Number) value).shortValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Short.parseShort(valueStr.trim()); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Short
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Short toShort(Object value) + { + return toShort(value, null); + } + + /** + * 转换为Number
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Number toNumber(Object value, Number defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Number) + { + return (Number) value; + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return NumberFormat.getInstance().parse(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Number
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Number toNumber(Object value) + { + return toNumber(value, null); + } + + /** + * 转换为int
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Integer toInt(Object value, Integer defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Integer) + { + return (Integer) value; + } + if (value instanceof Number) + { + return ((Number) value).intValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Integer.parseInt(valueStr.trim()); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为int
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Integer toInt(Object value) + { + return toInt(value, null); + } + + /** + * 转换为Integer数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static Integer[] toIntArray(String str) + { + return toIntArray(",", str); + } + + /** + * 转换为Long数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static Long[] toLongArray(String str) + { + return toLongArray(",", str); + } + + /** + * 转换为Integer数组
+ * + * @param split 分隔符 + * @param split 被转换的值 + * @return 结果 + */ + public static Integer[] toIntArray(String split, String str) + { + if (StringUtils.isEmpty(str)) + { + return new Integer[] {}; + } + String[] arr = str.split(split); + final Integer[] ints = new Integer[arr.length]; + for (int i = 0; i < arr.length; i++) + { + final Integer v = toInt(arr[i], 0); + ints[i] = v; + } + return ints; + } + + /** + * 转换为Long数组
+ * + * @param split 分隔符 + * @param str 被转换的值 + * @return 结果 + */ + public static Long[] toLongArray(String split, String str) + { + if (StringUtils.isEmpty(str)) + { + return new Long[] {}; + } + String[] arr = str.split(split); + final Long[] longs = new Long[arr.length]; + for (int i = 0; i < arr.length; i++) + { + final Long v = toLong(arr[i], null); + longs[i] = v; + } + return longs; + } + + /** + * 转换为String数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static String[] toStrArray(String str) + { + if (StringUtils.isEmpty(str)) + { + return new String[] {}; + } + return toStrArray(",", str); + } + + /** + * 转换为String数组
+ * + * @param split 分隔符 + * @param split 被转换的值 + * @return 结果 + */ + public static String[] toStrArray(String split, String str) + { + return str.split(split); + } + + /** + * 转换为long
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Long toLong(Object value, Long defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Long) + { + return (Long) value; + } + if (value instanceof Number) + { + return ((Number) value).longValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).longValue(); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为long
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Long toLong(Object value) + { + return toLong(value, null); + } + + /** + * 转换为double
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Double toDouble(Object value, Double defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Double) + { + return (Double) value; + } + if (value instanceof Number) + { + return ((Number) value).doubleValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).doubleValue(); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为double
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Double toDouble(Object value) + { + return toDouble(value, null); + } + + /** + * 转换为Float
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Float toFloat(Object value, Float defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Float) + { + return (Float) value; + } + if (value instanceof Number) + { + return ((Number) value).floatValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Float.parseFloat(valueStr.trim()); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Float
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Float toFloat(Object value) + { + return toFloat(value, null); + } + + /** + * 转换为boolean
+ * String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Boolean toBool(Object value, Boolean defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Boolean) + { + return (Boolean) value; + } + String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + valueStr = valueStr.trim().toLowerCase(); + switch (valueStr) + { + case "true": + case "yes": + case "ok": + case "1": + return true; + case "false": + case "no": + case "0": + return false; + default: + return defaultValue; + } + } + + /** + * 转换为boolean
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Boolean toBool(Object value) + { + return toBool(value, null); + } + + /** + * 转换为Enum对象
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * + * @param clazz Enum的Class + * @param value 值 + * @param defaultValue 默认值 + * @return Enum + */ + public static > E toEnum(Class clazz, Object value, E defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (clazz.isAssignableFrom(value.getClass())) + { + @SuppressWarnings("unchecked") + E myE = (E) value; + return myE; + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Enum.valueOf(clazz, valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Enum对象
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * + * @param clazz Enum的Class + * @param value 值 + * @return Enum + */ + public static > E toEnum(Class clazz, Object value) + { + return toEnum(clazz, value, null); + } + + /** + * 转换为BigInteger
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static BigInteger toBigInteger(Object value, BigInteger defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof BigInteger) + { + return (BigInteger) value; + } + if (value instanceof Long) + { + return BigInteger.valueOf((Long) value); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return new BigInteger(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为BigInteger
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static BigInteger toBigInteger(Object value) + { + return toBigInteger(value, null); + } + + /** + * 转换为BigDecimal
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof BigDecimal) + { + return (BigDecimal) value; + } + if (value instanceof Long) + { + return new BigDecimal((Long) value); + } + if (value instanceof Double) + { + return BigDecimal.valueOf((Double) value); + } + if (value instanceof Integer) + { + return new BigDecimal((Integer) value); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return new BigDecimal(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为BigDecimal
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static BigDecimal toBigDecimal(Object value) + { + return toBigDecimal(value, null); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @return 字符串 + */ + public static String utf8Str(Object obj) + { + return str(obj, CharsetKit.CHARSET_UTF_8); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charsetName 字符集 + * @return 字符串 + */ + public static String str(Object obj, String charsetName) + { + return str(obj, Charset.forName(charsetName)); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charset 字符集 + * @return 字符串 + */ + public static String str(Object obj, Charset charset) + { + if (null == obj) + { + return null; + } + + if (obj instanceof String) + { + return (String) obj; + } + else if (obj instanceof byte[]) + { + return str((byte[]) obj, charset); + } + else if (obj instanceof Byte[]) + { + byte[] bytes = ArrayUtils.toPrimitive((Byte[]) obj); + return str(bytes, charset); + } + else if (obj instanceof ByteBuffer) + { + return str((ByteBuffer) obj, charset); + } + return obj.toString(); + } + + /** + * 将byte数组转为字符串 + * + * @param bytes byte数组 + * @param charset 字符集 + * @return 字符串 + */ + public static String str(byte[] bytes, String charset) + { + return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset)); + } + + /** + * 解码字节码 + * + * @param data 字符串 + * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 + * @return 解码后的字符串 + */ + public static String str(byte[] data, Charset charset) + { + if (data == null) + { + return null; + } + + if (null == charset) + { + return new String(data); + } + return new String(data, charset); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * @return 字符串 + */ + public static String str(ByteBuffer data, String charset) + { + if (data == null) + { + return null; + } + + return str(data, Charset.forName(charset)); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * @return 字符串 + */ + public static String str(ByteBuffer data, Charset charset) + { + if (null == charset) + { + charset = Charset.defaultCharset(); + } + return charset.decode(data).toString(); + } + + // ----------------------------------------------------------------------- 全角半角转换 + /** + * 半角转全角 + * + * @param input String. + * @return 全角字符串. + */ + public static String toSBC(String input) + { + return toSBC(input, null); + } + + /** + * 半角转全角 + * + * @param input String + * @param notConvertSet 不替换的字符集合 + * @return 全角字符串. + */ + public static String toSBC(String input, Set notConvertSet) + { + char[] c = input.toCharArray(); + for (int i = 0; i < c.length; i++) + { + if (null != notConvertSet && notConvertSet.contains(c[i])) + { + // 跳过不替换的字符 + continue; + } + + if (c[i] == ' ') + { + c[i] = '\u3000'; + } + else if (c[i] < '\177') + { + c[i] = (char) (c[i] + 65248); + + } + } + return new String(c); + } + + /** + * 全角转半角 + * + * @param input String. + * @return 半角字符串 + */ + public static String toDBC(String input) + { + return toDBC(input, null); + } + + /** + * 替换全角为半角 + * + * @param text 文本 + * @param notConvertSet 不替换的字符集合 + * @return 替换后的字符 + */ + public static String toDBC(String text, Set notConvertSet) + { + char[] c = text.toCharArray(); + for (int i = 0; i < c.length; i++) + { + if (null != notConvertSet && notConvertSet.contains(c[i])) + { + // 跳过不替换的字符 + continue; + } + + if (c[i] == '\u3000') + { + c[i] = ' '; + } + else if (c[i] > '\uFF00' && c[i] < '\uFF5F') + { + c[i] = (char) (c[i] - 65248); + } + } + String returnString = new String(c); + + return returnString; + } + + /** + * 数字金额大写转换 先写个完整的然后将如零拾替换成零 + * + * @param n 数字 + * @return 中文大写数字 + */ + public static String digitUppercase(double n) + { + String[] fraction = { "角", "分" }; + String[] digit = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }; + String[][] unit = { { "元", "万", "亿" }, { "", "拾", "佰", "仟" } }; + + String head = n < 0 ? "负" : ""; + n = Math.abs(n); + + String s = ""; + for (int i = 0; i < fraction.length; i++) + { + s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", ""); + } + if (s.length() < 1) + { + s = "整"; + } + int integerPart = (int) Math.floor(n); + + for (int i = 0; i < unit[0].length && integerPart > 0; i++) + { + String p = ""; + for (int j = 0; j < unit[1].length && n > 0; j++) + { + p = digit[integerPart % 10] + unit[1][j] + p; + integerPart = integerPart / 10; + } + s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s; + } + return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整"); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/core/text/StrFormatter.java b/boyue-common/src/main/java/com/boyue/common/core/text/StrFormatter.java new file mode 100644 index 0000000..97af39d --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/core/text/StrFormatter.java @@ -0,0 +1,92 @@ +package com.boyue.common.core.text; + +import com.boyue.common.utils.StringUtils; + +/** + * 字符串格式化 + * + * @author boyue + */ +public class StrFormatter +{ + public static final String EMPTY_JSON = "{}"; + public static final char C_BACKSLASH = '\\'; + public static final char C_DELIM_START = '{'; + public static final char C_DELIM_END = '}'; + + /** + * 格式化字符串
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ * + * @param strPattern 字符串模板 + * @param argArray 参数列表 + * @return 结果 + */ + public static String format(final String strPattern, final Object... argArray) + { + if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray)) + { + return strPattern; + } + final int strPatternLength = strPattern.length(); + + // 初始化定义好的长度以获得更好的性能 + StringBuilder sbuf = new StringBuilder(strPatternLength + 50); + + int handledPosition = 0; + int delimIndex;// 占位符所在位置 + for (int argIndex = 0; argIndex < argArray.length; argIndex++) + { + delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition); + if (delimIndex == -1) + { + if (handledPosition == 0) + { + return strPattern; + } + else + { // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果 + sbuf.append(strPattern, handledPosition, strPatternLength); + return sbuf.toString(); + } + } + else + { + if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH) + { + if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH) + { + // 转义符之前还有一个转义符,占位符依旧有效 + sbuf.append(strPattern, handledPosition, delimIndex - 1); + sbuf.append(Convert.utf8Str(argArray[argIndex])); + handledPosition = delimIndex + 2; + } + else + { + // 占位符被转义 + argIndex--; + sbuf.append(strPattern, handledPosition, delimIndex - 1); + sbuf.append(C_DELIM_START); + handledPosition = delimIndex + 1; + } + } + else + { + // 正常占位符 + sbuf.append(strPattern, handledPosition, delimIndex); + sbuf.append(Convert.utf8Str(argArray[argIndex])); + handledPosition = delimIndex + 2; + } + } + } + // 加入最后一个占位符后所有的字符 + sbuf.append(strPattern, handledPosition, strPattern.length()); + + return sbuf.toString(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/enums/BusinessStatus.java b/boyue-common/src/main/java/com/boyue/common/enums/BusinessStatus.java new file mode 100644 index 0000000..761d2ff --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/enums/BusinessStatus.java @@ -0,0 +1,20 @@ +package com.boyue.common.enums; + +/** + * 操作状态 + * + * @author boyue + * + */ +public enum BusinessStatus +{ + /** + * 成功 + */ + SUCCESS, + + /** + * 失败 + */ + FAIL, +} diff --git a/boyue-common/src/main/java/com/boyue/common/enums/BusinessType.java b/boyue-common/src/main/java/com/boyue/common/enums/BusinessType.java new file mode 100644 index 0000000..34a4dcb --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/enums/BusinessType.java @@ -0,0 +1,59 @@ +package com.boyue.common.enums; + +/** + * 业务操作类型 + * + * @author boyue + */ +public enum BusinessType +{ + /** + * 其它 + */ + OTHER, + + /** + * 新增 + */ + INSERT, + + /** + * 修改 + */ + UPDATE, + + /** + * 删除 + */ + DELETE, + + /** + * 授权 + */ + GRANT, + + /** + * 导出 + */ + EXPORT, + + /** + * 导入 + */ + IMPORT, + + /** + * 强退 + */ + FORCE, + + /** + * 生成代码 + */ + GENCODE, + + /** + * 清空数据 + */ + CLEAN, +} diff --git a/boyue-common/src/main/java/com/boyue/common/enums/DataSourceType.java b/boyue-common/src/main/java/com/boyue/common/enums/DataSourceType.java new file mode 100644 index 0000000..4622cb9 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/enums/DataSourceType.java @@ -0,0 +1,18 @@ +package com.boyue.common.enums; + +/** + * 数据源 + * + * @author boyue + */ +public enum DataSourceType { + /** + * 主库 + */ + MASTER, + + /** + * 从库 + */ + SLAVE, +} diff --git a/boyue-common/src/main/java/com/boyue/common/enums/DesensitizedType.java b/boyue-common/src/main/java/com/boyue/common/enums/DesensitizedType.java new file mode 100644 index 0000000..2b62ad9 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/enums/DesensitizedType.java @@ -0,0 +1,60 @@ +package com.boyue.common.enums; + +import java.util.function.Function; + +import com.boyue.common.utils.DesensitizedUtil; + +/** + * 脱敏类型 + * + * @author boyue + */ +public enum DesensitizedType +{ + /** + * 姓名,第2位星号替换 + */ + USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")), + + /** + * 密码,全部字符都用*代替 + */ + PASSWORD(DesensitizedUtil::password), + + /** + * 身份证,中间10位星号替换 + */ + ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{3}[Xx]|\\d{4})", "$1** **** ****$2")), + + /** + * 手机号,中间4位星号替换 + */ + PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")), + + /** + * 电子邮箱,仅显示第一个字母和@后面的地址显示,其他星号替换 + */ + EMAIL(s -> s.replaceAll("(^.)[^@]*(@.*$)", "$1****$2")), + + /** + * 银行卡号,保留最后4位,其他星号替换 + */ + BANK_CARD(s -> s.replaceAll("\\d{15}(\\d{3})", "**** **** **** **** $1")), + + /** + * 车牌号码,包含普通车辆、新能源车辆 + */ + CAR_LICENSE(DesensitizedUtil::carLicense); + + private final Function desensitizer; + + DesensitizedType(Function desensitizer) + { + this.desensitizer = desensitizer; + } + + public Function desensitizer() + { + return desensitizer; + } +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/enums/HttpMethod.java b/boyue-common/src/main/java/com/boyue/common/enums/HttpMethod.java new file mode 100644 index 0000000..6e2f46d --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/enums/HttpMethod.java @@ -0,0 +1,52 @@ +package com.boyue.common.enums; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.lang.Nullable; + +/** + * 请求方式 + * + * @author boyue + */ +public enum HttpMethod +{ + /** GET 请求 */ + GET, + /** POST 请求 */ + HEAD, + /** HEAD 请求 */ + POST, + /** PUT 请求 */ + PUT, + /** PATCH 请求 */ + PATCH, + /** DELETE 请求 */ + DELETE, + /** OPTIONS 请求 */ + OPTIONS, + /** TRACE 请求 */ + TRACE; + + private static final Map mappings = new HashMap<>(16); + + static + { + for (HttpMethod httpMethod : values()) + { + mappings.put(httpMethod.name(), httpMethod); + } + } + + @Nullable + public static HttpMethod resolve(@Nullable String method) + { + return (method != null ? mappings.get(method) : null); + } + + public boolean matches(String method) + { + return (this == resolve(method)); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/enums/LimitType.java b/boyue-common/src/main/java/com/boyue/common/enums/LimitType.java new file mode 100644 index 0000000..ea1fe50 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/enums/LimitType.java @@ -0,0 +1,29 @@ +package com.boyue.common.enums; + +/** + * 限流类型 + * + * @author boyue + */ + +public enum LimitType { + /** + * 默认策略全局限流 + */ + DEFAULT, + + /** + * 根据请求者IP进行限流 + */ + IP, + + /** + * 根据请求者的用户ID进行限流 + */ + USER, + + /** + * 根据请求者的部门进行限流 + */ + DEPT, +} diff --git a/boyue-common/src/main/java/com/boyue/common/enums/OperatorType.java b/boyue-common/src/main/java/com/boyue/common/enums/OperatorType.java new file mode 100644 index 0000000..5306015 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/enums/OperatorType.java @@ -0,0 +1,24 @@ +package com.boyue.common.enums; + +/** + * 操作人类别 + * + * @author boyue + */ +public enum OperatorType +{ + /** + * 其它 + */ + OTHER, + + /** + * 后台用户 + */ + MANAGE, + + /** + * 手机端用户 + */ + MOBILE +} diff --git a/boyue-common/src/main/java/com/boyue/common/enums/UserStatus.java b/boyue-common/src/main/java/com/boyue/common/enums/UserStatus.java new file mode 100644 index 0000000..8240e4b --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/enums/UserStatus.java @@ -0,0 +1,35 @@ +package com.boyue.common.enums; + +/** + * 用户状态 + * + * @author boyue + */ +public enum UserStatus +{ + /** 正常 */ + OK("0", "正常"), + /** 停用 */ + DISABLE("1", "停用"), + /** 删除 */ + DELETED("2", "删除"); + + private final String code; + private final String info; + + UserStatus(String code, String info) + { + this.code = code; + this.info = info; + } + + public String getCode() + { + return code; + } + + public String getInfo() + { + return info; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/DemoModeException.java b/boyue-common/src/main/java/com/boyue/common/exception/DemoModeException.java new file mode 100644 index 0000000..ba7c514 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/DemoModeException.java @@ -0,0 +1,15 @@ +package com.boyue.common.exception; + +/** + * 演示模式异常 + * + * @author boyue + */ +public class DemoModeException extends RuntimeException +{ + private static final long serialVersionUID = 1L; + + public DemoModeException() + { + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/GlobalException.java b/boyue-common/src/main/java/com/boyue/common/exception/GlobalException.java new file mode 100644 index 0000000..73e74fd --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/GlobalException.java @@ -0,0 +1,58 @@ +package com.boyue.common.exception; + +/** + * 全局异常 + * + * @author boyue + */ +public class GlobalException extends RuntimeException +{ + private static final long serialVersionUID = 1L; + + /** + * 错误提示 + */ + private String message; + + /** + * 错误明细,内部调试错误 + * + * 和 {@link CommonResult#getDetailMessage()} 一致的设计 + */ + private String detailMessage; + + /** + * 空构造方法,避免反序列化问题 + */ + public GlobalException() + { + } + + public GlobalException(String message) + { + this.message = message; + } + + public String getDetailMessage() + { + return detailMessage; + } + + public GlobalException setDetailMessage(String detailMessage) + { + this.detailMessage = detailMessage; + return this; + } + + @Override + public String getMessage() + { + return message; + } + + public GlobalException setMessage(String message) + { + this.message = message; + return this; + } +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/exception/ServiceException.java b/boyue-common/src/main/java/com/boyue/common/exception/ServiceException.java new file mode 100644 index 0000000..249ff81 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/ServiceException.java @@ -0,0 +1,74 @@ +package com.boyue.common.exception; + +/** + * 业务异常 + * + * @author boyue + */ +public final class ServiceException extends RuntimeException +{ + private static final long serialVersionUID = 1L; + + /** + * 错误码 + */ + private Integer code; + + /** + * 错误提示 + */ + private String message; + + /** + * 错误明细,内部调试错误 + * + * 和 {@link CommonResult#getDetailMessage()} 一致的设计 + */ + private String detailMessage; + + /** + * 空构造方法,避免反序列化问题 + */ + public ServiceException() + { + } + + public ServiceException(String message) + { + this.message = message; + } + + public ServiceException(String message, Integer code) + { + this.message = message; + this.code = code; + } + + public String getDetailMessage() + { + return detailMessage; + } + + @Override + public String getMessage() + { + return message; + } + + public Integer getCode() + { + return code; + } + + public ServiceException setMessage(String message) + { + this.message = message; + return this; + } + + public ServiceException setDetailMessage(String detailMessage) + { + this.detailMessage = detailMessage; + return this; + } +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/exception/UtilException.java b/boyue-common/src/main/java/com/boyue/common/exception/UtilException.java new file mode 100644 index 0000000..49f868f --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/UtilException.java @@ -0,0 +1,26 @@ +package com.boyue.common.exception; + +/** + * 工具类异常 + * + * @author boyue + */ +public class UtilException extends RuntimeException +{ + private static final long serialVersionUID = 8247610319171014183L; + + public UtilException(Throwable e) + { + super(e.getMessage(), e); + } + + public UtilException(String message) + { + super(message); + } + + public UtilException(String message, Throwable throwable) + { + super(message, throwable); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/base/BaseException.java b/boyue-common/src/main/java/com/boyue/common/exception/base/BaseException.java new file mode 100644 index 0000000..4cd33f2 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/base/BaseException.java @@ -0,0 +1,97 @@ +package com.boyue.common.exception.base; + +import com.boyue.common.utils.MessageUtils; +import com.boyue.common.utils.StringUtils; + +/** + * 基础异常 + * + * @author boyue + */ +public class BaseException extends RuntimeException +{ + private static final long serialVersionUID = 1L; + + /** + * 所属模块 + */ + private String module; + + /** + * 错误码 + */ + private String code; + + /** + * 错误码对应的参数 + */ + private Object[] args; + + /** + * 错误消息 + */ + private String defaultMessage; + + public BaseException(String module, String code, Object[] args, String defaultMessage) + { + this.module = module; + this.code = code; + this.args = args; + this.defaultMessage = defaultMessage; + } + + public BaseException(String module, String code, Object[] args) + { + this(module, code, args, null); + } + + public BaseException(String module, String defaultMessage) + { + this(module, null, null, defaultMessage); + } + + public BaseException(String code, Object[] args) + { + this(null, code, args, null); + } + + public BaseException(String defaultMessage) + { + this(null, null, null, defaultMessage); + } + + @Override + public String getMessage() + { + String message = null; + if (!StringUtils.isEmpty(code)) + { + message = MessageUtils.message(code, args); + } + if (message == null) + { + message = defaultMessage; + } + return message; + } + + public String getModule() + { + return module; + } + + public String getCode() + { + return code; + } + + public Object[] getArgs() + { + return args; + } + + public String getDefaultMessage() + { + return defaultMessage; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/file/FileException.java b/boyue-common/src/main/java/com/boyue/common/exception/file/FileException.java new file mode 100644 index 0000000..039bc6e --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/file/FileException.java @@ -0,0 +1,19 @@ +package com.boyue.common.exception.file; + +import com.boyue.common.exception.base.BaseException; + +/** + * 文件信息异常类 + * + * @author boyue + */ +public class FileException extends BaseException +{ + private static final long serialVersionUID = 1L; + + public FileException(String code, Object[] args) + { + super("file", code, args, null); + } + +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/file/FileNameLengthLimitExceededException.java b/boyue-common/src/main/java/com/boyue/common/exception/file/FileNameLengthLimitExceededException.java new file mode 100644 index 0000000..1609109 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/file/FileNameLengthLimitExceededException.java @@ -0,0 +1,16 @@ +package com.boyue.common.exception.file; + +/** + * 文件名称超长限制异常类 + * + * @author boyue + */ +public class FileNameLengthLimitExceededException extends FileException +{ + private static final long serialVersionUID = 1L; + + public FileNameLengthLimitExceededException(int defaultFileNameLength) + { + super("upload.filename.exceed.length", new Object[] { defaultFileNameLength }); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/file/FileSizeLimitExceededException.java b/boyue-common/src/main/java/com/boyue/common/exception/file/FileSizeLimitExceededException.java new file mode 100644 index 0000000..9272a2f --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/file/FileSizeLimitExceededException.java @@ -0,0 +1,16 @@ +package com.boyue.common.exception.file; + +/** + * 文件名大小限制异常类 + * + * @author boyue + */ +public class FileSizeLimitExceededException extends FileException +{ + private static final long serialVersionUID = 1L; + + public FileSizeLimitExceededException(long defaultMaxSize) + { + super("upload.exceed.maxSize", new Object[] { defaultMaxSize }); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/file/FileUploadException.java b/boyue-common/src/main/java/com/boyue/common/exception/file/FileUploadException.java new file mode 100644 index 0000000..5b8eb21 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/file/FileUploadException.java @@ -0,0 +1,61 @@ +package com.boyue.common.exception.file; + +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + * 文件上传异常类 + * + * @author boyue + */ +public class FileUploadException extends Exception +{ + + private static final long serialVersionUID = 1L; + + private final Throwable cause; + + public FileUploadException() + { + this(null, null); + } + + public FileUploadException(final String msg) + { + this(msg, null); + } + + public FileUploadException(String msg, Throwable cause) + { + super(msg); + this.cause = cause; + } + + @Override + public void printStackTrace(PrintStream stream) + { + super.printStackTrace(stream); + if (cause != null) + { + stream.println("Caused by:"); + cause.printStackTrace(stream); + } + } + + @Override + public void printStackTrace(PrintWriter writer) + { + super.printStackTrace(writer); + if (cause != null) + { + writer.println("Caused by:"); + cause.printStackTrace(writer); + } + } + + @Override + public Throwable getCause() + { + return cause; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/file/InvalidExtensionException.java b/boyue-common/src/main/java/com/boyue/common/exception/file/InvalidExtensionException.java new file mode 100644 index 0000000..c1fc58c --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/file/InvalidExtensionException.java @@ -0,0 +1,80 @@ +package com.boyue.common.exception.file; + +import java.util.Arrays; + +/** + * 文件上传 误异常类 + * + * @author boyue + */ +public class InvalidExtensionException extends FileUploadException +{ + private static final long serialVersionUID = 1L; + + private String[] allowedExtension; + private String extension; + private String filename; + + public InvalidExtensionException(String[] allowedExtension, String extension, String filename) + { + super("文件[" + filename + "]后缀[" + extension + "]不正确,请上传" + Arrays.toString(allowedExtension) + "格式"); + this.allowedExtension = allowedExtension; + this.extension = extension; + this.filename = filename; + } + + public String[] getAllowedExtension() + { + return allowedExtension; + } + + public String getExtension() + { + return extension; + } + + public String getFilename() + { + return filename; + } + + public static class InvalidImageExtensionException extends InvalidExtensionException + { + private static final long serialVersionUID = 1L; + + public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename) + { + super(allowedExtension, extension, filename); + } + } + + public static class InvalidFlashExtensionException extends InvalidExtensionException + { + private static final long serialVersionUID = 1L; + + public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename) + { + super(allowedExtension, extension, filename); + } + } + + public static class InvalidMediaExtensionException extends InvalidExtensionException + { + private static final long serialVersionUID = 1L; + + public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename) + { + super(allowedExtension, extension, filename); + } + } + + public static class InvalidVideoExtensionException extends InvalidExtensionException + { + private static final long serialVersionUID = 1L; + + public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename) + { + super(allowedExtension, extension, filename); + } + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/job/TaskException.java b/boyue-common/src/main/java/com/boyue/common/exception/job/TaskException.java new file mode 100644 index 0000000..7e09689 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/job/TaskException.java @@ -0,0 +1,40 @@ +package com.boyue.common.exception.job; + +/** + * 计划策略异常 + * + * @author boyue + */ +public class TaskException extends Exception { + private static final long serialVersionUID = 1L; + + private Code code; + + public TaskException(String msg, Code code) { + this(msg, code, null); + } + + public TaskException(String msg, Code code, Exception nestedEx) { + super(msg, nestedEx); + this.code = code; + } + + public Code getCode() { + return code; + } + + public enum Code { + /** 任务存在 */ + TASK_EXISTS, + /** 任务不存在 */ + NO_TASK_EXISTS, + /** 任务已经开始 */ + TASK_ALREADY_STARTED, + /** 未知 */ + UNKNOWN, + /** 配置错误 */ + CONFIG_ERROR, + /** 任务节点不可用 */ + TASK_NODE_NOT_AVAILABLE + } +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/exception/user/BlackListException.java b/boyue-common/src/main/java/com/boyue/common/exception/user/BlackListException.java new file mode 100644 index 0000000..d5b5844 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/user/BlackListException.java @@ -0,0 +1,16 @@ +package com.boyue.common.exception.user; + +/** + * 黑名单IP异常类 + * + * @author boyue + */ +public class BlackListException extends UserException +{ + private static final long serialVersionUID = 1L; + + public BlackListException() + { + super("login.blocked", null); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/user/CaptchaException.java b/boyue-common/src/main/java/com/boyue/common/exception/user/CaptchaException.java new file mode 100644 index 0000000..e862ae2 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/user/CaptchaException.java @@ -0,0 +1,16 @@ +package com.boyue.common.exception.user; + +/** + * 验证码错误异常类 + * + * @author boyue + */ +public class CaptchaException extends UserException +{ + private static final long serialVersionUID = 1L; + + public CaptchaException() + { + super("user.jcaptcha.error", null); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/user/CaptchaExpireException.java b/boyue-common/src/main/java/com/boyue/common/exception/user/CaptchaExpireException.java new file mode 100644 index 0000000..6afbd22 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/user/CaptchaExpireException.java @@ -0,0 +1,16 @@ +package com.boyue.common.exception.user; + +/** + * 验证码失效异常类 + * + * @author boyue + */ +public class CaptchaExpireException extends UserException +{ + private static final long serialVersionUID = 1L; + + public CaptchaExpireException() + { + super("user.jcaptcha.expire", null); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/user/IpRetryLimitExceedException.java b/boyue-common/src/main/java/com/boyue/common/exception/user/IpRetryLimitExceedException.java new file mode 100644 index 0000000..d58b3af --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/user/IpRetryLimitExceedException.java @@ -0,0 +1,15 @@ +package com.boyue.common.exception.user; + +/** + * IP 登录重试次数超限异常类 + * + */ +public class IpRetryLimitExceedException extends RuntimeException +{ + private static final long serialVersionUID = 1L; + + public IpRetryLimitExceedException(int retryLimitCount, int lockTime) + { + super("失败次数过多,你的ip暂时被限制登录."); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/user/UserException.java b/boyue-common/src/main/java/com/boyue/common/exception/user/UserException.java new file mode 100644 index 0000000..877d0b8 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/user/UserException.java @@ -0,0 +1,18 @@ +package com.boyue.common.exception.user; + +import com.boyue.common.exception.base.BaseException; + +/** + * 用户信息异常类 + * + * @author boyue + */ +public class UserException extends BaseException +{ + private static final long serialVersionUID = 1L; + + public UserException(String code, Object[] args) + { + super("user", code, args, null); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/user/UserNotExistsException.java b/boyue-common/src/main/java/com/boyue/common/exception/user/UserNotExistsException.java new file mode 100644 index 0000000..0dfc9b0 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/user/UserNotExistsException.java @@ -0,0 +1,16 @@ +package com.boyue.common.exception.user; + +/** + * 用户不存在异常类 + * + * @author boyue + */ +public class UserNotExistsException extends UserException +{ + private static final long serialVersionUID = 1L; + + public UserNotExistsException() + { + super("user.not.exists", null); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/user/UserPasswordNotMatchException.java b/boyue-common/src/main/java/com/boyue/common/exception/user/UserPasswordNotMatchException.java new file mode 100644 index 0000000..2435666 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/user/UserPasswordNotMatchException.java @@ -0,0 +1,16 @@ +package com.boyue.common.exception.user; + +/** + * 用户密码不正确或不符合规范异常类 + * + * @author boyue + */ +public class UserPasswordNotMatchException extends UserException +{ + private static final long serialVersionUID = 1L; + + public UserPasswordNotMatchException() + { + super("user.password.not.match", null); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/exception/user/UserPasswordRetryLimitExceedException.java b/boyue-common/src/main/java/com/boyue/common/exception/user/UserPasswordRetryLimitExceedException.java new file mode 100644 index 0000000..c906d0d --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/exception/user/UserPasswordRetryLimitExceedException.java @@ -0,0 +1,16 @@ +package com.boyue.common.exception.user; + +/** + * 用户错误最大次数异常类 + * + * @author boyue + */ +public class UserPasswordRetryLimitExceedException extends UserException +{ + private static final long serialVersionUID = 1L; + + public UserPasswordRetryLimitExceedException(int retryLimitCount, int lockTime) + { + super("user.password.retry.limit.exceed", new Object[] { retryLimitCount, lockTime }); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/filter/PropertyPreExcludeFilter.java b/boyue-common/src/main/java/com/boyue/common/filter/PropertyPreExcludeFilter.java new file mode 100644 index 0000000..d2e624a --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/filter/PropertyPreExcludeFilter.java @@ -0,0 +1,24 @@ +package com.boyue.common.filter; + +import com.alibaba.fastjson2.filter.SimplePropertyPreFilter; + +/** + * 排除JSON敏感属性 + * + * @author boyue + */ +public class PropertyPreExcludeFilter extends SimplePropertyPreFilter +{ + public PropertyPreExcludeFilter() + { + } + + public PropertyPreExcludeFilter addExcludes(String... filters) + { + for (int i = 0; i < filters.length; i++) + { + this.getExcludes().add(filters[i]); + } + return this; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/filter/RepeatableFilter.java b/boyue-common/src/main/java/com/boyue/common/filter/RepeatableFilter.java new file mode 100644 index 0000000..70f4d63 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/filter/RepeatableFilter.java @@ -0,0 +1,52 @@ +package com.boyue.common.filter; + +import java.io.IOException; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.http.MediaType; +import com.boyue.common.utils.StringUtils; + +/** + * Repeatable 过滤器 + * + * @author boyue + */ +public class RepeatableFilter implements Filter +{ + @Override + public void init(FilterConfig filterConfig) throws ServletException + { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException + { + ServletRequest requestWrapper = null; + if (request instanceof HttpServletRequest + && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) + { + requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response); + } + if (null == requestWrapper) + { + chain.doFilter(request, response); + } + else + { + chain.doFilter(requestWrapper, response); + } + } + + @Override + public void destroy() + { + + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/filter/RepeatedlyRequestWrapper.java b/boyue-common/src/main/java/com/boyue/common/filter/RepeatedlyRequestWrapper.java new file mode 100644 index 0000000..08f5e30 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/filter/RepeatedlyRequestWrapper.java @@ -0,0 +1,76 @@ +package com.boyue.common.filter; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; +import com.boyue.common.utils.http.HttpHelper; +import com.boyue.common.constant.Constants; + +/** + * 构建可重复读取inputStream的request + * + * @author boyue + */ +public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper +{ + private final byte[] body; + + public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException + { + super(request); + request.setCharacterEncoding(Constants.UTF8); + response.setCharacterEncoding(Constants.UTF8); + + body = HttpHelper.getBodyString(request).getBytes(Constants.UTF8); + } + + @Override + public BufferedReader getReader() throws IOException + { + return new BufferedReader(new InputStreamReader(getInputStream())); + } + + @Override + public ServletInputStream getInputStream() throws IOException + { + final ByteArrayInputStream bais = new ByteArrayInputStream(body); + return new ServletInputStream() + { + @Override + public int read() throws IOException + { + return bais.read(); + } + + @Override + public int available() throws IOException + { + return body.length; + } + + @Override + public boolean isFinished() + { + return false; + } + + @Override + public boolean isReady() + { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) + { + + } + }; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/filter/XssFilter.java b/boyue-common/src/main/java/com/boyue/common/filter/XssFilter.java new file mode 100644 index 0000000..34cf439 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/filter/XssFilter.java @@ -0,0 +1,75 @@ +package com.boyue.common.filter; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.enums.HttpMethod; + +/** + * 防止XSS攻击的过滤器 + * + * @author boyue + */ +public class XssFilter implements Filter +{ + /** + * 排除链接 + */ + public List excludes = new ArrayList<>(); + + @Override + public void init(FilterConfig filterConfig) throws ServletException + { + String tempExcludes = filterConfig.getInitParameter("excludes"); + if (StringUtils.isNotEmpty(tempExcludes)) + { + String[] url = tempExcludes.split(","); + for (int i = 0; url != null && i < url.length; i++) + { + excludes.add(url[i]); + } + } + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException + { + HttpServletRequest req = (HttpServletRequest) request; + HttpServletResponse resp = (HttpServletResponse) response; + if (handleExcludeURL(req, resp)) + { + chain.doFilter(request, response); + return; + } + XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request); + chain.doFilter(xssRequest, response); + } + + private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) + { + String url = request.getServletPath(); + String method = request.getMethod(); + // GET DELETE 不过滤 + if (method == null || HttpMethod.GET.matches(method) || HttpMethod.DELETE.matches(method)) + { + return true; + } + return StringUtils.matches(url, excludes); + } + + @Override + public void destroy() + { + + } +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/filter/XssHttpServletRequestWrapper.java b/boyue-common/src/main/java/com/boyue/common/filter/XssHttpServletRequestWrapper.java new file mode 100644 index 0000000..b67fff9 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/filter/XssHttpServletRequestWrapper.java @@ -0,0 +1,111 @@ +package com.boyue.common.filter; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; +import org.apache.commons.io.IOUtils; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.html.EscapeUtil; + +/** + * XSS过滤处理 + * + * @author boyue + */ +public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper +{ + /** + * @param request + */ + public XssHttpServletRequestWrapper(HttpServletRequest request) + { + super(request); + } + + @Override + public String[] getParameterValues(String name) + { + String[] values = super.getParameterValues(name); + if (values != null) + { + int length = values.length; + String[] escapesValues = new String[length]; + for (int i = 0; i < length; i++) + { + // 防xss攻击和过滤前后空格 + escapesValues[i] = EscapeUtil.clean(values[i]).trim(); + } + return escapesValues; + } + return super.getParameterValues(name); + } + + @Override + public ServletInputStream getInputStream() throws IOException + { + // 非json类型,直接返回 + if (!isJsonRequest()) + { + return super.getInputStream(); + } + + // 为空,直接返回 + String json = IOUtils.toString(super.getInputStream(), "utf-8"); + if (StringUtils.isEmpty(json)) + { + return super.getInputStream(); + } + + // xss过滤 + json = EscapeUtil.clean(json).trim(); + byte[] jsonBytes = json.getBytes("utf-8"); + final ByteArrayInputStream bis = new ByteArrayInputStream(jsonBytes); + return new ServletInputStream() + { + @Override + public boolean isFinished() + { + return true; + } + + @Override + public boolean isReady() + { + return true; + } + + @Override + public int available() throws IOException + { + return jsonBytes.length; + } + + @Override + public void setReadListener(ReadListener readListener) + { + } + + @Override + public int read() throws IOException + { + return bis.read(); + } + }; + } + + /** + * 是否是Json请求 + * + * @param request + */ + public boolean isJsonRequest() + { + String header = super.getHeader(HttpHeaders.CONTENT_TYPE); + return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE); + } +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/handler/GenericListTypeHandler.java b/boyue-common/src/main/java/com/boyue/common/handler/GenericListTypeHandler.java new file mode 100644 index 0000000..ffb967c --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/handler/GenericListTypeHandler.java @@ -0,0 +1,131 @@ +package com.boyue.common.handler; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; + +import com.boyue.common.utils.StringUtils; + +/** + * 通用的List类型处理器,可处理任何元素类型 + * + * 用法示例: + * 1. 在XML中配置: + * {@code } + * + * 2. 在字段上使用注解: + * {@code @Result(column="tags", property="tags", + * typeHandler=GenericListTypeHandler.StringList.class)} + * + * 3. 在xml插值语法中使用 + * {@code #{tags,typeHandler=handler.com.boyue.common.GenericListTypeHandler$StringList} + * } + * + * @param 列表元素类型 + */ +public class GenericListTypeHandler extends BaseTypeHandler> { + + private final Function converter; + + /** + * 构造函数 + * + * @param converter 字符串到元素类型T的转换器 + */ + protected GenericListTypeHandler(Function converter) { + this.converter = converter; + } + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, List parameter, JdbcType jdbcType) + throws SQLException { + String value = StringUtils.join(parameter, ","); + ps.setString(i, value); + } + + @Override + public List getNullableResult(ResultSet rs, String columnName) throws SQLException { + return convertToList(rs.getString(columnName)); + } + + @Override + public List getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + return convertToList(rs.getString(columnIndex)); + } + + @Override + public List getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + return convertToList(cs.getString(columnIndex)); + } + + private List convertToList(String value) { + if (StringUtils.isBlank(value)) { + return null; + } + + List list = new ArrayList<>(); + String[] items = value.split(","); + for (String item : items) { + if (StringUtils.isNotBlank(item)) { + list.add(converter.apply(item.trim())); + } + } + return list; + } + + // 内部类 - 常用类型的TypeHandler实现 + + /** + * String类型列表的TypeHandler + */ + public static class StringList extends GenericListTypeHandler { + public StringList() { + super(String::valueOf); + } + } + + /** + * Integer类型列表的TypeHandler + */ + public static class IntegerList extends GenericListTypeHandler { + public IntegerList() { + super(Integer::valueOf); + } + } + + /** + * Long类型列表的TypeHandler + */ + public static class LongList extends GenericListTypeHandler { + public LongList() { + super(Long::valueOf); + } + } + + /** + * Double类型列表的TypeHandler + */ + public static class DoubleList extends GenericListTypeHandler { + public DoubleList() { + super(Double::valueOf); + } + } + + /** + * Boolean类型列表的TypeHandler + */ + public static class BooleanList extends GenericListTypeHandler { + public BooleanList() { + super(Boolean::valueOf); + } + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/service/cache/CacheKeys.java b/boyue-common/src/main/java/com/boyue/common/service/cache/CacheKeys.java new file mode 100644 index 0000000..ce0db91 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/service/cache/CacheKeys.java @@ -0,0 +1,10 @@ +package com.boyue.common.service.cache; + +import java.util.Set; + +import org.springframework.cache.Cache; + +public interface CacheKeys { + + public Set getCachekeys(final Cache cache); +} diff --git a/boyue-common/src/main/java/com/boyue/common/service/cache/CacheNoTimeOut.java b/boyue-common/src/main/java/com/boyue/common/service/cache/CacheNoTimeOut.java new file mode 100644 index 0000000..f71b6a6 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/service/cache/CacheNoTimeOut.java @@ -0,0 +1,7 @@ +package com.boyue.common.service.cache; + +public interface CacheNoTimeOut { + + public void setCacheObject(final String cacheName,final String key, final T value); + +} diff --git a/boyue-common/src/main/java/com/boyue/common/service/cache/CacheTimeOut.java b/boyue-common/src/main/java/com/boyue/common/service/cache/CacheTimeOut.java new file mode 100644 index 0000000..648d63b --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/service/cache/CacheTimeOut.java @@ -0,0 +1,10 @@ +package com.boyue.common.service.cache; + +import java.util.concurrent.TimeUnit; + +public interface CacheTimeOut extends CacheNoTimeOut { + + public void setCacheObject(final String cacheName, final String key, final T value, final long timeout, + final TimeUnit timeUnit); + +} diff --git a/boyue-common/src/main/java/com/boyue/common/service/datasource/AfterCreateDataSource.java b/boyue-common/src/main/java/com/boyue/common/service/datasource/AfterCreateDataSource.java new file mode 100644 index 0000000..dbca225 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/service/datasource/AfterCreateDataSource.java @@ -0,0 +1,10 @@ +package com.boyue.common.service.datasource; + +import java.util.Properties; + +import javax.sql.CommonDataSource; +import javax.sql.DataSource; + +public interface AfterCreateDataSource { + DataSource afterCreateDataSource(String name,Properties prop, CommonDataSource dataSource); +} diff --git a/boyue-common/src/main/java/com/boyue/common/service/datasource/CreateDataSource.java b/boyue-common/src/main/java/com/boyue/common/service/datasource/CreateDataSource.java new file mode 100644 index 0000000..5d4472f --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/service/datasource/CreateDataSource.java @@ -0,0 +1,9 @@ +package com.boyue.common.service.datasource; + +import java.util.Properties; + +import javax.sql.CommonDataSource; + +public interface CreateDataSource { + CommonDataSource createDataSource(String name, Properties prop); +} diff --git a/boyue-common/src/main/java/com/boyue/common/service/mybatis/CreateSqlSessionFactory.java b/boyue-common/src/main/java/com/boyue/common/service/mybatis/CreateSqlSessionFactory.java new file mode 100644 index 0000000..478d4c6 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/service/mybatis/CreateSqlSessionFactory.java @@ -0,0 +1,10 @@ +package com.boyue.common.service.mybatis; + +import javax.sql.DataSource; + +import org.apache.ibatis.session.SqlSessionFactory; +import org.springframework.core.env.Environment; + +public interface CreateSqlSessionFactory { + public SqlSessionFactory createSqlSessionFactory(Environment env, DataSource dataSource) throws Exception; +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/Arith.java b/boyue-common/src/main/java/com/boyue/common/utils/Arith.java new file mode 100644 index 0000000..043cb73 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/Arith.java @@ -0,0 +1,114 @@ +package com.boyue.common.utils; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * 精确的浮点数运算 + * + * @author boyue + */ +public class Arith +{ + + /** 默认除法运算精度 */ + private static final int DEF_DIV_SCALE = 10; + + /** 这个类不能实例化 */ + private Arith() + { + } + + /** + * 提供精确的加法运算。 + * @param v1 被加数 + * @param v2 加数 + * @return 两个参数的和 + */ + public static double add(double v1, double v2) + { + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + return b1.add(b2).doubleValue(); + } + + /** + * 提供精确的减法运算。 + * @param v1 被减数 + * @param v2 减数 + * @return 两个参数的差 + */ + public static double sub(double v1, double v2) + { + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + return b1.subtract(b2).doubleValue(); + } + + /** + * 提供精确的乘法运算。 + * @param v1 被乘数 + * @param v2 乘数 + * @return 两个参数的积 + */ + public static double mul(double v1, double v2) + { + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + return b1.multiply(b2).doubleValue(); + } + + /** + * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 + * 小数点以后10位,以后的数字四舍五入。 + * @param v1 被除数 + * @param v2 除数 + * @return 两个参数的商 + */ + public static double div(double v1, double v2) + { + return div(v1, v2, DEF_DIV_SCALE); + } + + /** + * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 + * 定精度,以后的数字四舍五入。 + * @param v1 被除数 + * @param v2 除数 + * @param scale 表示表示需要精确到小数点以后几位。 + * @return 两个参数的商 + */ + public static double div(double v1, double v2, int scale) + { + if (scale < 0) + { + throw new IllegalArgumentException( + "The scale must be a positive integer or zero"); + } + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + if (b1.compareTo(BigDecimal.ZERO) == 0) + { + return BigDecimal.ZERO.doubleValue(); + } + return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue(); + } + + /** + * 提供精确的小数位四舍五入处理。 + * @param v 需要四舍五入的数字 + * @param scale 小数点后保留几位 + * @return 四舍五入后的结果 + */ + public static double round(double v, int scale) + { + if (scale < 0) + { + throw new IllegalArgumentException( + "The scale must be a positive integer or zero"); + } + BigDecimal b = new BigDecimal(Double.toString(v)); + BigDecimal one = BigDecimal.ONE; + return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/CacheUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/CacheUtils.java new file mode 100644 index 0000000..aca52b3 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/CacheUtils.java @@ -0,0 +1,161 @@ +package com.boyue.common.utils; + +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.cache.jcache.JCacheCache; +import org.springframework.cache.transaction.TransactionAwareCacheDecorator; +import org.springframework.lang.Nullable; +import org.springframework.util.ObjectUtils; + +import com.boyue.common.service.cache.CacheKeys; +import com.boyue.common.service.cache.CacheTimeOut; +import com.boyue.common.utils.spring.SpringUtils; + +public class CacheUtils { + + /** + * 获取CacheManager + * + * @return + */ + public static CacheManager getCacheManager() { + return SpringUtils.getBean(CacheManager.class); + } + + /** + * 根据cacheName从CacheManager中获取cache + * + * @param cacheName + * @return + */ + public static Cache getCache(String cacheName) { + return getCacheManager().getCache(cacheName); + } + + /** + * 获取缓存的所有key值(由于springcache不支持获取所有key,只能根据cache类型来单独获取) + * + * @param cacheName + * @return + */ + public static Set getkeys(String cacheName) { + Cache cache = getCacheManager().getCache(cacheName); + CacheKeys cacheGetKets = SpringUtils.getBean(CacheKeys.class); + return cacheGetKets.getCachekeys(cache); + } + + /** + * 根据cacheName,key缓存数据 + * + * @param cacheName + * @param key + * @param value + * @param + */ + public static void put(String cacheName, String key, T value) { + put(cacheName, key, value, 0, null); + } + + /** + * 如果没有则进行缓存,根据cacheName,key缓存数据 + * + * @param cacheName + * @param key + * @param value + * @param + */ + public static void putIfAbsent(String cacheName, String key, T value) { + if (ObjectUtils.isEmpty(get(cacheName, key))) { + put(cacheName, key, value, 0, null); + } + } + + public static boolean hasKey(String cacheName, String key) { + return !ObjectUtils.isEmpty(get(cacheName, key)); + } + + /** + * 根据cacheName,key和缓存过期时间进行缓存数据,使用各种不同缓存可以单独进行操作 + * + * @param cacheName + * @param key + * @param value + * @param timeout + * @param unit + * @param + */ + public static void put(String cacheName, String key, T value, long timeout, TimeUnit unit) { + Cache cache = getCacheManager().getCache(cacheName); + if (cache instanceof JCacheCache) { + JCacheCache ehcache = (JCacheCache) cache; + ehcache.put(key, value); + } else if (cache instanceof TransactionAwareCacheDecorator) { + CacheTimeOut cacheTimeOut = SpringUtils.getBean(CacheTimeOut.class); + if (timeout != 0 && unit != null) { + cacheTimeOut.setCacheObject(cacheName, key, value, timeout, unit); + } else { + cacheTimeOut.setCacheObject(cacheName, key, value); + } + } else { + cache.put(key, value); + } + } + + /** + * 获取数据 + * + * @param cacheName + * @param key + * @return + */ + public static Cache.ValueWrapper get(String cacheName, String key) { + return getCacheManager().getCache(cacheName).get(key); + } + + /** + * 根据类型获取数据 + * + * @param cacheName + * @param key + * @param type + * @param + * @return + */ + public static T get(String cacheName, String key, @Nullable Class type) { + return getCacheManager().getCache(cacheName).get(key, type); + } + + /** + * 移除缓存数据 + * + * @param cacheName + * @param key + */ + public static void remove(String cacheName, String key) { + getCacheManager().getCache(cacheName).evict(key); + } + + /** + * 如果存在则移除缓存数据 + * + * @param cacheName + * @param key + * @return + */ + public static boolean removeIfPresent(String cacheName, String key) { + remove(cacheName, key); + return false; + } + + /** + * 清除缓存名称为cacheName的所有缓存数据 + * + * @param cacheName + */ + public static void clear(String cacheName) { + getCacheManager().getCache(cacheName).clear(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/DateUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/DateUtils.java new file mode 100644 index 0000000..233b62e --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/DateUtils.java @@ -0,0 +1,174 @@ +package com.boyue.common.utils; + +import java.lang.management.ManagementFactory; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Date; + +import org.apache.commons.lang3.time.DateFormatUtils; + +/** + * 时间工具类 + * + * @author boyue + */ +public class DateUtils extends org.apache.commons.lang3.time.DateUtils { + + public static String YYYY = "yyyy"; + + public static String YYYY_MM = "yyyy-MM"; + + public static String YYYY_MM_DD = "yyyy-MM-dd"; + + public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss"; + + public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; + + private static String[] parsePatterns = { + "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", + "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", + "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM" }; + + /** + * 获取当前Date型日期 + * + * @return Date() 当前日期 + */ + public static Date getNowDate() { + return new Date(); + } + + /** + * 获取当前日期, 默认格式为yyyy-MM-dd + * + * @return String + */ + public static String getDate() { + return dateTimeNow(YYYY_MM_DD); + } + + public static final String getTime() { + return dateTimeNow(YYYY_MM_DD_HH_MM_SS); + } + + public static final String dateTimeNow() { + return dateTimeNow(YYYYMMDDHHMMSS); + } + + public static final String dateTimeNow(final String format) { + return parseDateToStr(format, new Date()); + } + + public static final String dateTime(final Date date) { + return parseDateToStr(YYYY_MM_DD, date); + } + + public static final String parseDateToStr(final String format, final Date date) { + return new SimpleDateFormat(format).format(date); + } + + public static final Date dateTime(final String format, final String ts) { + try { + return new SimpleDateFormat(format).parse(ts); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + /** + * 日期路径 即年/月/日 如2018/08/08 + */ + public static final String datePath() { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyy/MM/dd"); + } + + /** + * 日期路径 即年/月/日 如20180808 + */ + public static final String dateTime() { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyyMMdd"); + } + + /** + * 日期型字符串转化为日期 格式 + */ + public static Date parseDate(Object str) { + if (str == null) { + return null; + } + try { + return parseDate(str.toString(), parsePatterns); + } catch (ParseException e) { + return null; + } + } + + /** + * 获取服务器启动时间 + */ + public static Date getServerStartDate() { + long time = ManagementFactory.getRuntimeMXBean().getStartTime(); + return new Date(time); + } + + /** + * 计算相差天数 + */ + public static int differentDaysByMillisecond(Date date1, Date date2) { + return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24))); + } + + /** + * 计算时间差 + * + * @param endTime 最后时间 + * @param startTime 开始时间 + * @return 时间差(天/小时/分钟) + */ + public static String timeDistance(Date endDate, Date startTime) { + long nd = 1000 * 24 * 60 * 60; + long nh = 1000 * 60 * 60; + long nm = 1000 * 60; + // long ns = 1000; + // 获得两个时间的毫秒时间差异 + long diff = endDate.getTime() - startTime.getTime(); + // 计算差多少天 + long day = diff / nd; + // 计算差多少小时 + long hour = diff % nd / nh; + // 计算差多少分钟 + long min = diff % nd % nh / nm; + // 计算差多少秒//输出结果 + // long sec = diff % nd % nh % nm / ns; + return day + "天" + hour + "小时" + min + "分钟"; + } + + /** + * 增加 LocalDateTime ==> Date + */ + public static Date toDate(LocalDateTime temporalAccessor) { + ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault()); + return Date.from(zdt.toInstant()); + } + + /** + * 增加 LocalDate ==> Date + */ + public static Date toDate(LocalDate temporalAccessor) { + LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0)); + ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault()); + return Date.from(zdt.toInstant()); + } + + /** @deprecated */ + @Deprecated + public DateUtils() { + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/DesensitizedUtil.java b/boyue-common/src/main/java/com/boyue/common/utils/DesensitizedUtil.java new file mode 100644 index 0000000..7880b68 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/DesensitizedUtil.java @@ -0,0 +1,49 @@ +package com.boyue.common.utils; + +/** + * 脱敏工具类 + * + * @author boyue + */ +public class DesensitizedUtil +{ + /** + * 密码的全部字符都用*代替,比如:****** + * + * @param password 密码 + * @return 脱敏后的密码 + */ + public static String password(String password) + { + if (StringUtils.isBlank(password)) + { + return StringUtils.EMPTY; + } + return StringUtils.repeat('*', password.length()); + } + + /** + * 车牌中间用*代替,如果是错误的车牌,不处理 + * + * @param carLicense 完整的车牌号 + * @return 脱敏后的车牌 + */ + public static String carLicense(String carLicense) + { + if (StringUtils.isBlank(carLicense)) + { + return StringUtils.EMPTY; + } + // 普通车牌 + if (carLicense.length() == 7) + { + carLicense = StringUtils.hide(carLicense, 3, 6); + } + else if (carLicense.length() == 8) + { + // 新能源车牌 + carLicense = StringUtils.hide(carLicense, 3, 7); + } + return carLicense; + } +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/utils/DictUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/DictUtils.java new file mode 100644 index 0000000..c24c94b --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/DictUtils.java @@ -0,0 +1,204 @@ +package com.boyue.common.utils; + +import java.util.List; + +import org.springframework.cache.Cache; + +import com.boyue.common.constant.CacheConstants; +import com.boyue.common.core.domain.entity.SysDictData; + +/** + * 字典工具类 + * + * @author boyue + */ +public class DictUtils +{ + /** + * 分隔符 + */ + public static final String SEPARATOR = ","; + + /** + * 设置字典缓存 + * + * @param key 参数键 + * @param dictDatas 字典数据列表 + */ + public static void setDictCache(String key, List dictDatas) + { + getDictCacheKey().put(key, dictDatas); + } + + /** + * 获取字典缓存 + * + * @param key 参数键 + * @return dictDatas 字典数据列表 + */ + @SuppressWarnings("unchecked") + public static List getDictCache(String key) + { + List arrayCache = (List) getDictCacheKey().get(key, List.class); + if (StringUtils.isNotNull(arrayCache)) + { + return arrayCache; + } + return null; + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @return 字典标签 + */ + public static String getDictLabel(String dictType, String dictValue) + { + return getDictLabel(dictType, dictValue, SEPARATOR); + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @return 字典值 + */ + public static String getDictValue(String dictType, String dictLabel) + { + return getDictValue(dictType, dictLabel, SEPARATOR); + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @param separator 分隔符 + * @return 字典标签 + */ + public static String getDictLabel(String dictType, String dictValue, String separator) + { + StringBuilder propertyString = new StringBuilder(); + List datas = getDictCache(dictType); + if (StringUtils.isNotNull(datas)) + { + if (StringUtils.containsAny(separator, dictValue)) + { + for (SysDictData dict : datas) + { + for (String value : dictValue.split(separator)) + { + if (value.equals(dict.getDictValue())) + { + propertyString.append(dict.getDictLabel()).append(separator); + break; + } + } + } + } + else + { + for (SysDictData dict : datas) + { + if (dictValue.equals(dict.getDictValue())) + { + return dict.getDictLabel(); + } + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param separator 分隔符 + * @return 字典值 + */ + public static String getDictValue(String dictType, String dictLabel, String separator) + { + StringBuilder propertyString = new StringBuilder(); + List datas = getDictCache(dictType); + if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas)) + { + for (SysDictData dict : datas) + { + for (String label : dictLabel.split(separator)) + { + if (label.equals(dict.getDictLabel())) + { + propertyString.append(dict.getDictValue()).append(separator); + break; + } + } + } + } + else + { + for (SysDictData dict : datas) + { + if (dictLabel.equals(dict.getDictLabel())) + { + return dict.getDictValue(); + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + + /** + * 根据字典类型获取字典所有标签 + * + * @param dictType 字典类型 + * @return 字典值 + */ + public static String getDictLabels(String dictType) + { + StringBuilder propertyString = new StringBuilder(); + List datas = getDictCache(dictType); + if (StringUtils.isNull(datas)) + { + return StringUtils.EMPTY; + } + for (SysDictData dict : datas) + { + propertyString.append(dict.getDictLabel()).append(SEPARATOR); + } + return StringUtils.stripEnd(propertyString.toString(), SEPARATOR); + } + + /** + * 删除指定字典缓存 + * + * @param key 字典键 + */ + public static void removeDictCache(String key) + { + getDictCacheKey().evict(key); + } + + /** + * 清空字典缓存 + */ + public static void clearDictCache() + { + getDictCacheKey().clear(); + } + + /** + * 获取dict缓存 + * + * @return 缓存Cache + */ + public static Cache getDictCacheKey() + { + return CacheUtils.getCache(CacheConstants.SYS_DICT_KEY); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/ExceptionUtil.java b/boyue-common/src/main/java/com/boyue/common/utils/ExceptionUtil.java new file mode 100644 index 0000000..be10248 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/ExceptionUtil.java @@ -0,0 +1,39 @@ +package com.boyue.common.utils; + +import java.io.PrintWriter; +import java.io.StringWriter; +import org.apache.commons.lang3.exception.ExceptionUtils; + +/** + * 错误信息处理类。 + * + * @author boyue + */ +public class ExceptionUtil +{ + /** + * 获取exception的详细错误信息。 + */ + public static String getExceptionMessage(Throwable e) + { + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw, true)); + return sw.toString(); + } + + public static String getRootErrorMessage(Exception e) + { + Throwable root = ExceptionUtils.getRootCause(e); + root = (root == null ? e : root); + if (root == null) + { + return ""; + } + String msg = root.getMessage(); + if (msg == null) + { + return "null"; + } + return StringUtils.defaultString(msg); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/LogUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/LogUtils.java new file mode 100644 index 0000000..15eb06a --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/LogUtils.java @@ -0,0 +1,18 @@ +package com.boyue.common.utils; + +/** + * 处理并记录日志文件 + * + * @author boyue + */ +public class LogUtils +{ + public static String getBlock(Object msg) + { + if (msg == null) + { + msg = ""; + } + return "[" + msg.toString() + "]"; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/MessageUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/MessageUtils.java new file mode 100644 index 0000000..a3b55da --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/MessageUtils.java @@ -0,0 +1,26 @@ +package com.boyue.common.utils; + +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; +import com.boyue.common.utils.spring.SpringUtils; + +/** + * 获取i18n资源文件 + * + * @author boyue + */ +public class MessageUtils +{ + /** + * 根据消息键和参数 获取消息 委托给spring messageSource + * + * @param code 消息键 + * @param args 参数 + * @return 获取国际化翻译值 + */ + public static String message(String code, Object... args) + { + MessageSource messageSource = SpringUtils.getBean(MessageSource.class); + return messageSource.getMessage(code, args, LocaleContextHolder.getLocale()); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/MybatisUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/MybatisUtils.java new file mode 100644 index 0000000..9cb5bf2 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/MybatisUtils.java @@ -0,0 +1,77 @@ +package com.boyue.common.utils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.util.ClassUtils; + +public class MybatisUtils { + static final String DEFAULT_RESOURCE_PATTERN = "**/*.class"; + + public static String setTypeAliasesPackage(String typeAliasesPackage) { + ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver(); + MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver); + List allResult = new ArrayList(); + try { + for (String aliasesPackage : typeAliasesPackage.split(",")) { + List result = new ArrayList(); + aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + + DEFAULT_RESOURCE_PATTERN; + Resource[] resources = resolver.getResources(aliasesPackage); + if (resources != null && resources.length > 0) { + MetadataReader metadataReader = null; + for (Resource resource : resources) { + if (resource.isReadable()) { + metadataReader = metadataReaderFactory.getMetadataReader(resource); + try { + result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage() + .getName()); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + } + } + if (result.size() > 0) { + HashSet hashResult = new HashSet(result); + allResult.addAll(hashResult); + } + } + if (allResult.size() > 0) { + typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0])); + } else { + throw new RuntimeException( + "mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包"); + } + } catch (IOException e) { + e.printStackTrace(); + } + return typeAliasesPackage; + } + + public static Resource[] resolveMapperLocations(String[] mapperLocations) { + ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); + List resources = new ArrayList(); + if (mapperLocations != null) { + for (String mapperLocation : mapperLocations) { + try { + Resource[] mappers = resourceResolver.getResources(mapperLocation); + resources.addAll(Arrays.asList(mappers)); + } catch (IOException e) { + // ignore + } + } + } + return resources.toArray(new Resource[resources.size()]); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/PageUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/PageUtils.java new file mode 100644 index 0000000..e048a6f --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/PageUtils.java @@ -0,0 +1,35 @@ +package com.boyue.common.utils; + +import com.github.pagehelper.PageHelper; +import com.boyue.common.core.page.PageDomain; +import com.boyue.common.core.page.TableSupport; +import com.boyue.common.utils.sql.SqlUtil; + +/** + * 分页工具类 + * + * @author boyue + */ +public class PageUtils extends PageHelper +{ + /** + * 设置请求分页数据 + */ + public static void startPage() + { + PageDomain pageDomain = TableSupport.buildPageRequest(); + Integer pageNum = pageDomain.getPageNum(); + Integer pageSize = pageDomain.getPageSize(); + String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy()); + Boolean reasonable = pageDomain.getReasonable(); + PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable); + } + + /** + * 清理分页的线程变量 + */ + public static void clearPage() + { + PageHelper.clearPage(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/SecurityUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/SecurityUtils.java new file mode 100644 index 0000000..095dd6c --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/SecurityUtils.java @@ -0,0 +1,178 @@ +package com.boyue.common.utils; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.util.PatternMatchUtils; +import com.boyue.common.constant.Constants; +import com.boyue.common.constant.HttpStatus; +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.exception.ServiceException; + +/** + * 安全服务工具类 + * + * @author boyue + */ +public class SecurityUtils +{ + + /** + * 用户ID + **/ + public static Long getUserId() + { + try + { + return getLoginUser().getUserId(); + } + catch (Exception e) + { + throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED); + } + } + + /** + * 获取部门ID + **/ + public static Long getDeptId() + { + try + { + return getLoginUser().getDeptId(); + } + catch (Exception e) + { + throw new ServiceException("获取部门ID异常", HttpStatus.UNAUTHORIZED); + } + } + + /** + * 获取用户账户 + **/ + public static String getUsername() + { + try + { + return getLoginUser().getUsername(); + } + catch (Exception e) + { + throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED); + } + } + + /** + * 获取用户 + **/ + public static LoginUser getLoginUser() + { + try + { + return (LoginUser) getAuthentication().getPrincipal(); + } + catch (Exception e) + { + throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED); + } + } + + /** + * 获取Authentication + */ + public static Authentication getAuthentication() + { + return SecurityContextHolder.getContext().getAuthentication(); + } + + /** + * 生成BCryptPasswordEncoder密码 + * + * @param password 密码 + * @return 加密字符串 + */ + public static String encryptPassword(String password) + { + BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + return passwordEncoder.encode(password); + } + + /** + * 判断密码是否相同 + * + * @param rawPassword 真实密码 + * @param encodedPassword 加密后字符 + * @return 结果 + */ + public static boolean matchesPassword(String rawPassword, String encodedPassword) + { + BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + return passwordEncoder.matches(rawPassword, encodedPassword); + } + + /** + * 是否为管理员 + * + * @param userId 用户ID + * @return 结果 + */ + public static boolean isAdmin(Long userId) + { + return userId != null && 1L == userId; + } + + /** + * 验证用户是否具备某权限 + * + * @param permission 权限字符串 + * @return 用户是否具备某权限 + */ + public static boolean hasPermi(String permission) + { + return hasPermi(getLoginUser().getPermissions(), permission); + } + + /** + * 判断是否包含权限 + * + * @param authorities 权限列表 + * @param permission 权限字符串 + * @return 用户是否具备某权限 + */ + public static boolean hasPermi(Collection authorities, String permission) + { + return authorities.stream().filter(StringUtils::hasText) + .anyMatch(x -> Constants.ALL_PERMISSION.equals(x) || PatternMatchUtils.simpleMatch(x, permission)); + } + + /** + * 验证用户是否拥有某个角色 + * + * @param role 角色标识 + * @return 用户是否具备某角色 + */ + public static boolean hasRole(String role) + { + List roleList = getLoginUser().getUser().getRoles(); + Collection roles = roleList.stream().map(SysRole::getRoleKey).collect(Collectors.toSet()); + return hasRole(roles, role); + } + + /** + * 判断是否包含角色 + * + * @param roles 角色列表 + * @param role 角色 + * @return 用户是否具备某角色权限 + */ + public static boolean hasRole(Collection roles, String role) + { + return roles.stream().filter(StringUtils::hasText) + .anyMatch(x -> Constants.SUPER_ADMIN.equals(x) || PatternMatchUtils.simpleMatch(x, role)); + } + +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/ServletUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/ServletUtils.java new file mode 100644 index 0000000..f249ee2 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/ServletUtils.java @@ -0,0 +1,218 @@ +package com.boyue.common.utils; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import com.boyue.common.constant.Constants; +import com.boyue.common.core.text.Convert; + +/** + * 客户端工具类 + * + * @author boyue + */ +public class ServletUtils +{ + /** + * 获取String参数 + */ + public static String getParameter(String name) + { + return getRequest().getParameter(name); + } + + /** + * 获取String参数 + */ + public static String getParameter(String name, String defaultValue) + { + return Convert.toStr(getRequest().getParameter(name), defaultValue); + } + + /** + * 获取Integer参数 + */ + public static Integer getParameterToInt(String name) + { + return Convert.toInt(getRequest().getParameter(name)); + } + + /** + * 获取Integer参数 + */ + public static Integer getParameterToInt(String name, Integer defaultValue) + { + return Convert.toInt(getRequest().getParameter(name), defaultValue); + } + + /** + * 获取Boolean参数 + */ + public static Boolean getParameterToBool(String name) + { + return Convert.toBool(getRequest().getParameter(name)); + } + + /** + * 获取Boolean参数 + */ + public static Boolean getParameterToBool(String name, Boolean defaultValue) + { + return Convert.toBool(getRequest().getParameter(name), defaultValue); + } + + /** + * 获得所有请求参数 + * + * @param request 请求对象{@link ServletRequest} + * @return Map + */ + public static Map getParams(ServletRequest request) + { + final Map map = request.getParameterMap(); + return Collections.unmodifiableMap(map); + } + + /** + * 获得所有请求参数 + * + * @param request 请求对象{@link ServletRequest} + * @return Map + */ + public static Map getParamMap(ServletRequest request) + { + Map params = new HashMap<>(); + for (Map.Entry entry : getParams(request).entrySet()) + { + params.put(entry.getKey(), StringUtils.join(entry.getValue(), ",")); + } + return params; + } + + /** + * 获取request + */ + public static HttpServletRequest getRequest() + { + return getRequestAttributes().getRequest(); + } + + /** + * 获取response + */ + public static HttpServletResponse getResponse() + { + return getRequestAttributes().getResponse(); + } + + /** + * 获取session + */ + public static HttpSession getSession() + { + return getRequest().getSession(); + } + + public static ServletRequestAttributes getRequestAttributes() + { + RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); + return (ServletRequestAttributes) attributes; + } + + /** + * 将字符串渲染到客户端 + * + * @param response 渲染对象 + * @param string 待渲染的字符串 + */ + public static void renderString(HttpServletResponse response, String string) + { + try + { + response.setStatus(200); + response.setContentType("application/json"); + response.setCharacterEncoding("utf-8"); + response.getWriter().print(string); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + /** + * 是否是Ajax异步请求 + * + * @param request + */ + public static boolean isAjaxRequest(HttpServletRequest request) + { + String accept = request.getHeader("accept"); + if (accept != null && accept.contains("application/json")) + { + return true; + } + + String xRequestedWith = request.getHeader("X-Requested-With"); + if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) + { + return true; + } + + String uri = request.getRequestURI(); + if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) + { + return true; + } + + String ajax = request.getParameter("__ajax"); + return StringUtils.inStringIgnoreCase(ajax, "json", "xml"); + } + + /** + * 内容编码 + * + * @param str 内容 + * @return 编码后的内容 + */ + public static String urlEncode(String str) + { + try + { + return URLEncoder.encode(str, Constants.UTF8); + } + catch (UnsupportedEncodingException e) + { + return StringUtils.EMPTY; + } + } + + /** + * 内容解码 + * + * @param str 内容 + * @return 解码后的内容 + */ + public static String urlDecode(String str) + { + try + { + return URLDecoder.decode(str, Constants.UTF8); + } + catch (UnsupportedEncodingException e) + { + return StringUtils.EMPTY; + } + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/StringUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/StringUtils.java new file mode 100644 index 0000000..8d38818 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/StringUtils.java @@ -0,0 +1,588 @@ +package com.boyue.common.utils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.springframework.util.AntPathMatcher; + +import com.boyue.common.constant.Constants; +import com.boyue.common.core.text.StrFormatter; + +/** + * 字符串工具类 + * + * @author boyue + */ +public class StringUtils extends org.apache.commons.lang3.StringUtils { + + /** 空字符串 */ + private static final String NULLSTR = ""; + + /** 下划线 */ + private static final char SEPARATOR = '_'; + + /** 星号 */ + private static final char ASTERISK = '*'; + + /** + * 获取参数不为空值 + * + * @param value defaultValue 要判断的value + * @return value 返回值 + */ + public static T nvl(T value, T defaultValue) { + return value != null ? value : defaultValue; + } + + /** + * * 判断一个Collection是否为空, 包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Collection coll) { + return isNull(coll) || coll.isEmpty(); + } + + /** + * * 判断一个Collection是否非空,包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Collection coll) { + return !isEmpty(coll); + } + + /** + * * 判断一个对象数组是否为空 + * + * @param objects 要判断的对象数组 + ** @return true:为空 false:非空 + */ + public static boolean isEmpty(Object[] objects) { + return isNull(objects) || (objects.length == 0); + } + + /** + * * 判断一个对象数组是否非空 + * + * @param objects 要判断的对象数组 + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Object[] objects) { + return !isEmpty(objects); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Map map) { + return isNull(map) || map.isEmpty(); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Map map) { + return !isEmpty(map); + } + + /** + * * 判断一个字符串是否为空串 + * + * @param str String + * @return true:为空 false:非空 + */ + public static boolean isEmpty(String str) { + return isNull(str) || NULLSTR.equals(str.trim()); + } + + /** + * * 判断一个字符串是否为非空串 + * + * @param str String + * @return true:非空串 false:空串 + */ + public static boolean isNotEmpty(String str) { + return !isEmpty(str); + } + + /** + * * 判断一个对象是否为空 + * + * @param object Object + * @return true:为空 false:非空 + */ + public static boolean isNull(Object object) { + return object == null; + } + + /** + * * 判断一个对象是否非空 + * + * @param object Object + * @return true:非空 false:空 + */ + public static boolean isNotNull(Object object) { + return !isNull(object); + } + + /** + * * 判断一个对象是否是数组类型(Java基本型别的数组) + * + * @param object 对象 + * @return true:是数组 false:不是数组 + */ + public static boolean isArray(Object object) { + return isNotNull(object) && object.getClass().isArray(); + } + + /** + * 去空格 + */ + public static String trim(String str) { + return (str == null ? "" : str.trim()); + } + + /** + * 替换指定字符串的指定区间内字符为"*" + * + * @param str 字符串 + * @param startInclude 开始位置(包含) + * @param endExclude 结束位置(不包含) + * @return 替换后的字符串 + */ + public static String hide(CharSequence str, int startInclude, int endExclude) { + if (isEmpty(str)) { + return NULLSTR; + } + final int strLength = str.length(); + if (startInclude > strLength) { + return NULLSTR; + } + if (endExclude > strLength) { + endExclude = strLength; + } + if (startInclude > endExclude) { + // 如果起始位置大于结束位置,不替换 + return NULLSTR; + } + final char[] chars = new char[strLength]; + for (int i = 0; i < strLength; i++) { + if (i >= startInclude && i < endExclude) { + chars[i] = ASTERISK; + } else { + chars[i] = str.charAt(i); + } + } + return new String(chars); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @return 结果 + */ + public static String substring(final String str, int start) { + if (str == null) { + return NULLSTR; + } + + if (start < 0) { + start = str.length() + start; + } + + if (start < 0) { + start = 0; + } + if (start > str.length()) { + return NULLSTR; + } + + return str.substring(start); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @param end 结束 + * @return 结果 + */ + public static String substring(final String str, int start, int end) { + if (str == null) { + return NULLSTR; + } + + if (end < 0) { + end = str.length() + end; + } + if (start < 0) { + start = str.length() + start; + } + + if (end > str.length()) { + end = str.length(); + } + + if (start > end) { + return NULLSTR; + } + + if (start < 0) { + start = 0; + } + if (end < 0) { + end = 0; + } + + return str.substring(start, end); + } + + /** + * 判断是否为空,并且不是空白字符 + * + * @param str 要判断的value + * @return 结果 + */ + public static boolean hasText(String str) { + return (str != null && !str.isEmpty() && containsText(str)); + } + + private static boolean containsText(CharSequence str) { + int strLen = str.length(); + for (int i = 0; i < strLen; i++) { + if (!Character.isWhitespace(str.charAt(i))) { + return true; + } + } + return false; + } + + /** + * 格式化文本, {} 表示占位符
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ * + * @param template 文本模板,被替换的部分用 {} 表示 + * @param params 参数值 + * @return 格式化后的文本 + */ + public static String format(String template, Object... params) { + if (isEmpty(params) || isEmpty(template)) { + return template; + } + return StrFormatter.format(template, params); + } + + /** + * 是否为http(s)://开头 + * + * @param link 链接 + * @return 结果 + */ + public static boolean ishttp(String link) { + return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS); + } + + /** + * 字符串转set + * + * @param str 字符串 + * @param sep 分隔符 + * @return set集合 + */ + public static final Set str2Set(String str, String sep) { + return new HashSet(str2List(str, sep, true, false)); + } + + /** + * 字符串转list + * + * @param str 字符串 + * @param sep 分隔符 + * @param filterBlank 过滤纯空白 + * @param trim 去掉首尾空白 + * @return list集合 + */ + public static final List str2List(String str, String sep, boolean filterBlank, boolean trim) { + List list = new ArrayList(); + if (StringUtils.isEmpty(str)) { + return list; + } + + // 过滤空白字符串 + if (filterBlank && StringUtils.isBlank(str)) { + return list; + } + String[] split = str.split(sep); + for (String string : split) { + if (filterBlank && StringUtils.isBlank(string)) { + continue; + } + if (trim) { + string = string.trim(); + } + list.add(string); + } + + return list; + } + + /** + * 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value + * + * @param collection 给定的集合 + * @param array 给定的数组 + * @return boolean 结果 + */ + public static boolean containsAny(Collection collection, String... array) { + if (isEmpty(collection) || isEmpty(array)) { + return false; + } else { + for (String str : array) { + if (collection.contains(str)) { + return true; + } + } + return false; + } + } + + /** + * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写 + * + * @param cs 指定字符串 + * @param searchCharSequences 需要检查的字符串数组 + * @return 是否包含任意一个字符串 + */ + public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) { + if (isEmpty(cs) || isEmpty(searchCharSequences)) { + return false; + } + for (CharSequence testStr : searchCharSequences) { + if (containsIgnoreCase(cs, testStr)) { + return true; + } + } + return false; + } + + /** + * 驼峰转下划线命名 + */ + public static String toUnderScoreCase(String str) { + if (str == null) { + return null; + } + StringBuilder sb = new StringBuilder(); + // 前置字符是否大写 + boolean preCharIsUpperCase = true; + // 当前字符是否大写 + boolean curreCharIsUpperCase = true; + // 下一字符是否大写 + boolean nexteCharIsUpperCase = true; + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (i > 0) { + preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); + } else { + preCharIsUpperCase = false; + } + + curreCharIsUpperCase = Character.isUpperCase(c); + + if (i < (str.length() - 1)) { + nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); + } + + if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) { + sb.append(SEPARATOR); + } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) { + sb.append(SEPARATOR); + } + sb.append(Character.toLowerCase(c)); + } + + return sb.toString(); + } + + /** + * 是否包含字符串 + * + * @param str 验证字符串 + * @param strs 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) { + if (str != null && strs != null) { + for (String s : strs) { + if (str.equalsIgnoreCase(trim(s))) { + return true; + } + } + } + return false; + } + + /** + * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 + * 例如:HELLO_WORLD->HelloWorld + * + * @param name 转换前的下划线大写方式命名的字符串 + * @return 转换后的驼峰式命名的字符串 + */ + public static String convertToCamelCase(String name) { + StringBuilder result = new StringBuilder(); + // 快速检查 + if (name == null || name.isEmpty()) { + // 没必要转换 + return ""; + } else if (!name.contains("_")) { + // 不含下划线,仅将首字母大写 + return name.substring(0, 1).toUpperCase() + name.substring(1); + } + // 用下划线将原始字符串分割 + String[] camels = name.split("_"); + for (String camel : camels) { + // 跳过原始字符串中开头、结尾的下换线或双重下划线 + if (camel.isEmpty()) { + continue; + } + // 首字母大写 + result.append(camel.substring(0, 1).toUpperCase()); + result.append(camel.substring(1).toLowerCase()); + } + return result.toString(); + } + + /** + * 驼峰式命名法 + * 例如:user_name->userName + */ + public static String toCamelCase(String s) { + if (s == null) { + return null; + } + if (s.indexOf(SEPARATOR) == -1) { + return s; + } + s = s.toLowerCase(); + StringBuilder sb = new StringBuilder(s.length()); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + if (c == SEPARATOR) { + upperCase = true; + } else if (upperCase) { + sb.append(Character.toUpperCase(c)); + upperCase = false; + } else { + sb.append(c); + } + } + return sb.toString(); + } + + /** + * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 + * + * @param str 指定字符串 + * @param strs 需要检查的字符串数组 + * @return 是否匹配 + */ + public static boolean matches(String str, List strs) { + if (isEmpty(str) || isEmpty(strs)) { + return false; + } + for (String pattern : strs) { + if (isMatch(pattern, str)) { + return true; + } + } + return false; + } + + /** + * 判断url是否与规则配置: + * ? 表示单个字符; + * * 表示一层路径内的任意字符串,不可跨层级; + * ** 表示任意层路径; + * + * @param pattern 匹配规则 + * @param url 需要匹配的url + * @return + */ + public static boolean isMatch(String pattern, String url) { + AntPathMatcher matcher = new AntPathMatcher(); + return matcher.match(pattern, url); + } + + @SuppressWarnings("unchecked") + public static T cast(Object obj) { + return (T) obj; + } + + /** + * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。 + * + * @param num 数字对象 + * @param size 字符串指定长度 + * @return 返回数字的字符串格式,该字符串为指定长度。 + */ + public static final String padl(final Number num, final int size) { + return padl(num.toString(), size, '0'); + } + + /** + * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。 + * + * @param s 原始字符串 + * @param size 字符串指定长度 + * @param c 用于补齐的字符 + * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。 + */ + public static final String padl(final String s, final int size, final char c) { + final StringBuilder sb = new StringBuilder(size); + if (s != null) { + final int len = s.length(); + if (s.length() <= size) { + for (int i = size - len; i > 0; i--) { + sb.append(c); + } + sb.append(s); + } else { + return s.substring(len - size, len); + } + } else { + for (int i = size; i > 0; i--) { + sb.append(c); + } + } + return sb.toString(); + } + + /** @deprecated */ + @Deprecated + public StringUtils() { + } +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/utils/Threads.java b/boyue-common/src/main/java/com/boyue/common/utils/Threads.java new file mode 100644 index 0000000..50b0b48 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/Threads.java @@ -0,0 +1,99 @@ +package com.boyue.common.utils; + +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 线程相关工具类. + * + * @author boyue + */ +public class Threads +{ + private static final Logger logger = LoggerFactory.getLogger(Threads.class); + + /** + * sleep等待,单位为毫秒 + */ + public static void sleep(long milliseconds) + { + try + { + Thread.sleep(milliseconds); + } + catch (InterruptedException e) + { + return; + } + } + + /** + * 停止线程池 + * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务. + * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数. + * 如果仍然超時,則強制退出. + * 另对在shutdown时线程本身被调用中断做了处理. + */ + public static void shutdownAndAwaitTermination(ExecutorService pool) + { + if (pool != null && !pool.isShutdown()) + { + pool.shutdown(); + try + { + if (!pool.awaitTermination(120, TimeUnit.SECONDS)) + { + pool.shutdownNow(); + if (!pool.awaitTermination(120, TimeUnit.SECONDS)) + { + logger.info("Pool did not terminate"); + } + } + } + catch (InterruptedException ie) + { + pool.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + } + + /** + * 打印线程异常信息 + */ + public static void printException(Runnable r, Throwable t) + { + if (t == null && r instanceof Future) + { + try + { + Future future = (Future) r; + if (future.isDone()) + { + future.get(); + } + } + catch (CancellationException ce) + { + t = ce; + } + catch (ExecutionException ee) + { + t = ee.getCause(); + } + catch (InterruptedException ie) + { + Thread.currentThread().interrupt(); + } + } + if (t != null) + { + logger.error(t.getMessage(), t); + } + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/bean/BeanUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/bean/BeanUtils.java new file mode 100644 index 0000000..98da101 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/bean/BeanUtils.java @@ -0,0 +1,110 @@ +package com.boyue.common.utils.bean; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Bean 工具类 + * + * @author boyue + */ +public class BeanUtils extends org.springframework.beans.BeanUtils +{ + /** Bean方法名中属性名开始的下标 */ + private static final int BEAN_METHOD_PROP_INDEX = 3; + + /** * 匹配getter方法的正则表达式 */ + private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)"); + + /** * 匹配setter方法的正则表达式 */ + private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)"); + + /** + * Bean属性复制工具方法。 + * + * @param dest 目标对象 + * @param src 源对象 + */ + public static void copyBeanProp(Object dest, Object src) + { + try + { + copyProperties(src, dest); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + /** + * 获取对象的setter方法。 + * + * @param obj 对象 + * @return 对象的setter方法列表 + */ + public static List getSetterMethods(Object obj) + { + // setter方法列表 + List setterMethods = new ArrayList(); + + // 获取所有方法 + Method[] methods = obj.getClass().getMethods(); + + // 查找setter方法 + + for (Method method : methods) + { + Matcher m = SET_PATTERN.matcher(method.getName()); + if (m.matches() && (method.getParameterTypes().length == 1)) + { + setterMethods.add(method); + } + } + // 返回setter方法列表 + return setterMethods; + } + + /** + * 获取对象的getter方法。 + * + * @param obj 对象 + * @return 对象的getter方法列表 + */ + + public static List getGetterMethods(Object obj) + { + // getter方法列表 + List getterMethods = new ArrayList(); + // 获取所有方法 + Method[] methods = obj.getClass().getMethods(); + // 查找getter方法 + for (Method method : methods) + { + Matcher m = GET_PATTERN.matcher(method.getName()); + if (m.matches() && (method.getParameterTypes().length == 0)) + { + getterMethods.add(method); + } + } + // 返回getter方法列表 + return getterMethods; + } + + /** + * 检查Bean方法名中的属性名是否相等。
+ * 如getName()和setName()属性名一样,getName()和setAge()属性名不一样。 + * + * @param m1 方法名1 + * @param m2 方法名2 + * @return 属性名一样返回true,否则返回false + */ + + public static boolean isMethodPropEquals(String m1, String m2) + { + return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX)); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/bean/BeanValidators.java b/boyue-common/src/main/java/com/boyue/common/utils/bean/BeanValidators.java new file mode 100644 index 0000000..ae3315b --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/bean/BeanValidators.java @@ -0,0 +1,24 @@ +package com.boyue.common.utils.bean; + +import java.util.Set; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validator; + +/** + * bean对象属性验证 + * + * @author boyue + */ +public class BeanValidators +{ + public static void validateWithException(Validator validator, Object object, Class... groups) + throws ConstraintViolationException + { + Set> constraintViolations = validator.validate(object, groups); + if (!constraintViolations.isEmpty()) + { + throw new ConstraintViolationException(constraintViolations); + } + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/file/FileTypeUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/file/FileTypeUtils.java new file mode 100644 index 0000000..8658f68 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/file/FileTypeUtils.java @@ -0,0 +1,77 @@ +package com.boyue.common.utils.file; + +import org.apache.commons.lang3.StringUtils; + +import java.io.File; + +/** + * 文件类型工具类 + * + * @author boyue + */ +public class FileTypeUtils +{ + /** + * 获取文件类型 + *

+ * 例如: boyue.txt, 返回: txt + * + * @param file 文件名 + * @return 后缀(不含".") + */ + public static String getFileType(File file) + { + if (null == file) + { + return StringUtils.EMPTY; + } + return getFileType(file.getName()); + } + + /** + * 获取文件类型 + *

+ * 例如: boyue.txt, 返回: txt + * + * @param fileName 文件名 + * @return 后缀(不含".") + */ + public static String getFileType(String fileName) + { + int separatorIndex = fileName.lastIndexOf("."); + if (separatorIndex < 0) + { + return ""; + } + return fileName.substring(separatorIndex + 1).toLowerCase(); + } + + /** + * 获取文件类型 + * + * @param photoByte 文件字节码 + * @return 后缀(不含".") + */ + public static String getFileExtendName(byte[] photoByte) + { + String strFileExtendName = "JPG"; + if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56) + && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) + { + strFileExtendName = "GIF"; + } + else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) + { + strFileExtendName = "JPG"; + } + else if ((photoByte[0] == 66) && (photoByte[1] == 77)) + { + strFileExtendName = "BMP"; + } + else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) + { + strFileExtendName = "PNG"; + } + return strFileExtendName; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/file/FileUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/file/FileUtils.java new file mode 100644 index 0000000..30238a8 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/file/FileUtils.java @@ -0,0 +1,405 @@ +package com.boyue.common.utils.file; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.web.multipart.MultipartFile; + +import com.boyue.common.config.BoYueConfig; +import com.boyue.common.constant.Constants; +import com.boyue.common.exception.file.FileSizeLimitExceededException; +import com.boyue.common.exception.file.InvalidExtensionException; +import com.boyue.common.utils.DateUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.spring.SpringUtils; +import com.boyue.common.utils.uuid.IdUtils; +import com.boyue.common.utils.uuid.Seq; +import com.boyue.common.utils.uuid.UUID; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 文件处理工具类 + * + * @author boyue + */ +public class FileUtils { + public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+"; + + /** + * 默认的文件名最大长度 100 + */ + public static final int DEFAULT_FILE_NAME_LENGTH = 100; + public static final long DEFAULT_MAX_SIZE = Long.valueOf(SpringUtils.getRequiredProperty("boyue.fileMaxSize")) + * 1024 * 1024; + + /** + * 输出指定文件的byte数组 + * + * @param os 输出流 + * @return + */ + public static void writeBytes(InputStream inputStream, OutputStream os) throws IOException { + + try { + + byte[] b = new byte[1024]; + int length; + while ((length = inputStream.read(b)) > 0) { + os.write(b, 0, length); + } + } catch (IOException e) { + throw e; + } finally { + IOUtils.close(os); + IOUtils.close(inputStream); + } + } + + /** + * 写数据到文件中 + * + * @param data 数据 + * @return 目标文件 + * @throws IOException IO异常 + */ + public static String writeImportBytes(byte[] data) throws IOException { + return writeBytes(data, BoYueConfig.getImportPath()); + } + + /** + * 写数据到文件中 + * + * @param data 数据 + * @param uploadDir 目标文件 + * @return 目标文件 + * @throws IOException IO异常 + */ + public static String writeBytes(byte[] data, String uploadDir) throws IOException { + FileOutputStream fos = null; + String pathName = ""; + try { + String extension = getFileExtendName(data); + pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension; + File file = FileUtils.getAbsoluteFile(uploadDir, pathName); + fos = new FileOutputStream(file); + fos.write(data); + } finally { + IOUtils.close(fos); + } + return FileUtils.getPathFileName(uploadDir, pathName); + } + + /** + * 删除文件 + * + * @param filePath 文件 + * @return + */ + public static boolean deleteFile(String filePath) { + boolean flag = false; + File file = new File(filePath); + // 路径为文件且不为空则进行删除 + if (file.isFile() && file.exists()) { + flag = file.delete(); + } + return flag; + } + + /** + * 文件名称验证 + * + * @param filename 文件名称 + * @return true 正常 false 非法 + */ + public static boolean isValidFilename(String filename) { + return filename.matches(FILENAME_PATTERN); + } + + /** + * 检查文件是否可下载 + * + * @param resource 需要下载的文件 + * @return true 正常 false 非法 + */ + public static boolean checkAllowDownload(String resource) { + // 禁止目录上跳级别 + if (StringUtils.contains(resource, "..")) { + return false; + } + + // 检查允许下载的文件规则 + if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource))) { + return true; + } + + // 不在允许下载的文件规则 + return false; + } + + /** + * 下载文件名重新编码 + * + * @param request 请求对象 + * @param fileName 文件名 + * @return 编码后的文件名 + */ + public static String setFileDownloadHeader(HttpServletRequest request, String fileName) + throws UnsupportedEncodingException { + final String agent = request.getHeader("USER-AGENT"); + String filename = fileName; + if (agent.contains("MSIE")) { + // IE浏览器 + filename = URLEncoder.encode(filename, "utf-8"); + filename = filename.replace("+", " "); + } else if (agent.contains("Firefox")) { + // 火狐浏览器 + filename = new String(fileName.getBytes(), "ISO8859-1"); + } else if (agent.contains("Chrome")) { + // google浏览器 + filename = URLEncoder.encode(filename, "utf-8"); + } else { + // 其它浏览器 + filename = URLEncoder.encode(filename, "utf-8"); + } + return filename; + } + + /** + * 下载文件名重新编码 + * + * @param response 响应对象 + * @param realFileName 真实文件名 + */ + public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) + throws UnsupportedEncodingException { + String percentEncodedFileName = percentEncode(realFileName); + + StringBuilder contentDispositionValue = new StringBuilder(); + contentDispositionValue.append("attachment; filename=") + .append(percentEncodedFileName) + .append(";") + .append("filename*=") + .append("utf-8''") + .append(percentEncodedFileName); + + response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename"); + response.setHeader("Content-disposition", contentDispositionValue.toString()); + response.setHeader("download-filename", percentEncodedFileName); + } + + /** + * 百分号编码工具方法 + * + * @param s 需要百分号编码的字符串 + * @return 百分号编码后的字符串 + */ + public static String percentEncode(String s) throws UnsupportedEncodingException { + String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString()); + return encode.replaceAll("\\+", "%20"); + } + + /** + * 获取图像后缀 + * + * @param photoByte 图像数据 + * @return 后缀名 + */ + public static String getFileExtendName(byte[] photoByte) { + String strFileExtendName = "jpg"; + if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56) + && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) { + strFileExtendName = "gif"; + } else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) { + strFileExtendName = "jpg"; + } else if ((photoByte[0] == 66) && (photoByte[1] == 77)) { + strFileExtendName = "bmp"; + } else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) { + strFileExtendName = "png"; + } + return strFileExtendName; + } + + /** + * 获取文件名称 /profile/upload/2022/04/16/boyue.png -- boyue.png + * + * @param fileName 路径名称 + * @return 没有文件路径的名称 + */ + public static String getName(String fileName) { + if (fileName == null) { + return null; + } + int lastUnixPos = fileName.lastIndexOf('/'); + int lastWindowsPos = fileName.lastIndexOf('\\'); + int index = Math.max(lastUnixPos, lastWindowsPos); + return fileName.substring(index + 1); + } + + /** + * 获取不带后缀文件名称 /profile/upload/2022/04/16/boyue.png -- boyue + * + * @param fileName 路径名称 + * @return 没有文件路径和后缀的名称 + */ + public static String getNameNotSuffix(String fileName) { + if (fileName == null) { + return null; + } + String baseName = FilenameUtils.getBaseName(fileName); + return baseName; + } + + /** + * 编码文件名 + */ + public static final String extractFilename(MultipartFile file) { + return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(), + FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), + getExtension(file)); + } + + public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException { + File desc = new File(uploadDir + File.separator + fileName); + + if (!desc.exists()) { + if (!desc.getParentFile().exists()) { + desc.getParentFile().mkdirs(); + } + } + return desc; + } + + public static final File getAbsoluteFile(String filePath) throws IOException { + File desc = new File(filePath); + if (!desc.exists()) { + if (!desc.getParentFile().exists()) { + desc.getParentFile().mkdirs(); + } + } + return desc; + } + + public static final String getPathFileName(String uploadDir, String fileName) throws IOException { + int dirLastIndex = BoYueConfig.getProfile().length() + 1; + String currentDir = StringUtils.substring(uploadDir, dirLastIndex); + StringBuilder sb = new StringBuilder(); + sb.append(Constants.RESOURCE_PREFIX) + .append("/").append(currentDir) + .append("/").append(fileName); + return sb.toString().replace("\\", "/"); + } + + /** + * 文件大小校验 + * + * @param file 上传的文件 + * @return + * @throws FileSizeLimitExceededException 如果超出最大大小 + * @throws InvalidExtensionException + */ + public static final void assertAllowed(MultipartFile file, String[] allowedExtension) + throws FileSizeLimitExceededException, InvalidExtensionException { + long size = file.getSize(); + if (size > DEFAULT_MAX_SIZE) { + throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); + } + + String fileName = file.getOriginalFilename(); + String extension = getExtension(file); + if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) { + if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) { + throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension, + fileName); + } else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) { + throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension, + fileName); + } else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) { + throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension, + fileName); + } else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) { + throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension, + fileName); + } else { + throw new InvalidExtensionException(allowedExtension, extension, fileName); + } + } + } + + /** + * 判断MIME类型是否是允许的MIME类型 + * + * @param extension + * @param allowedExtension + * @return + */ + public static final boolean isAllowedExtension(String extension, String[] allowedExtension) { + for (String str : allowedExtension) { + if (str.equalsIgnoreCase(extension)) { + return true; + } + } + return false; + } + + /** + * 获取文件名的后缀 + * + * @param file 表单文件 + * @return 后缀名 + */ + public static final String getExtension(MultipartFile file) { + String extension = FilenameUtils.getExtension(file.getOriginalFilename()); + if (StringUtils.isEmpty(extension)) { + extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType())); + } + return extension; + } + + /** + * 获取相对路径 + * + * @param filePath 文件路径,可以是绝对路径或相对路径 + * @return 相对路径,将反斜杠替换为斜杠,如果输入是绝对路径则去除根路径部分。 + */ + public static final String getRelativePath(String filePath) { + Path absolute = Paths.get(filePath); + if (!absolute.isAbsolute()) { + if (filePath.startsWith("/") || filePath.startsWith("\\")) { + return filePath.replace("\\", "/").substring(1); + } else { + return filePath.replace("\\", "/"); + } + } + Path root = absolute.getRoot(); + Path normalize = absolute.normalize(); + String relativePath = normalize.subpath(root.getNameCount(), normalize.getNameCount()).toString(); + return relativePath.replace("\\", "/"); + } + + public static final boolean isAbsolutePath(String path) { + Path filePath = Paths.get(path); + return filePath.isAbsolute(); + } + + public static final String fastFilePath(MultipartFile file) { + return new StringBuilder(DateUtils.datePath()) + .append(File.separatorChar).append(DateUtils.dateTimeNow()) + .append("_").append(UUID.fastUUID().toString().substring(0, 4)) + .append(".").append(FileUtils.getExtension(file)).toString(); + } + +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/file/ImageUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/file/ImageUtils.java new file mode 100644 index 0000000..46478be --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/file/ImageUtils.java @@ -0,0 +1,101 @@ +package com.boyue.common.utils.file; + +import com.boyue.common.config.BoYueConfig; +import com.boyue.common.constant.Constants; +import com.boyue.common.utils.StringUtils; +import org.apache.poi.util.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.util.Arrays; + +/** + * 图片处理工具类 + * + * @author boyue + */ +public class ImageUtils +{ + private static final Logger log = LoggerFactory.getLogger(ImageUtils.class); + + public static byte[] getImage(String imagePath) + { + InputStream is = getFile(imagePath); + try + { + return IOUtils.toByteArray(is); + } + catch (Exception e) + { + log.error("图片加载异常 {}", e); + return null; + } + finally + { + IOUtils.closeQuietly(is); + } + } + + public static InputStream getFile(String imagePath) + { + try + { + byte[] result = readFile(imagePath); + result = Arrays.copyOf(result, result.length); + return new ByteArrayInputStream(result); + } + catch (Exception e) + { + log.error("获取图片异常 {}", e); + } + return null; + } + + /** + * 读取文件为字节数据 + * + * @param url 地址 + * @return 字节数据 + */ + public static byte[] readFile(String url) + { + InputStream in = null; + try + { + if (url.startsWith("http")) + { + // 网络地址 + URI uriObj = new URI(url); + URL urlObj = uriObj.toURL(); + URLConnection urlConnection = urlObj.openConnection(); + urlConnection.setConnectTimeout(30 * 1000); + urlConnection.setReadTimeout(60 * 1000); + urlConnection.setDoInput(true); + in = urlConnection.getInputStream(); + } + else + { + // 本机地址 + String localPath = BoYueConfig.getProfile(); + String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX); + in = new FileInputStream(downloadPath); + } + return IOUtils.toByteArray(in); + } + catch (Exception e) + { + log.error("获取文件路径异常 {}", e); + return null; + } + finally + { + IOUtils.closeQuietly(in); + } + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/file/MimeTypeUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/file/MimeTypeUtils.java new file mode 100644 index 0000000..c486440 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/file/MimeTypeUtils.java @@ -0,0 +1,61 @@ +package com.boyue.common.utils.file; + +/** + * 媒体类型工具类 + * + * @author boyue + */ +public class MimeTypeUtils +{ + public static final String IMAGE_PNG = "image/png"; + + public static final String IMAGE_JPG = "image/jpg"; + + public static final String IMAGE_JPEG = "image/jpeg"; + + public static final String IMAGE_BMP = "image/bmp"; + + public static final String IMAGE_GIF = "image/gif"; + + public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" }; + + public static final String[] FLASH_EXTENSION = { "swf", "flv" }; + + public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", + "asf", "rm", "rmvb" }; + + public static final String[] VIDEO_EXTENSION = { "mp4", "avi", "rmvb" }; + + public static final String[] DEFAULT_ALLOWED_EXTENSION = { + // 图片 + "bmp", "gif", "jpg", "jpeg", "png", + // word excel powerpoint + "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", + // 压缩文件 + "rar", "zip", "gz", "bz2", + // 音频格式 + "mp3", "wav", + // 视频格式 + "mp4", "avi", "rmvb", + // pdf + "pdf" }; + + public static String getExtension(String prefix) + { + switch (prefix) + { + case IMAGE_PNG: + return "png"; + case IMAGE_JPG: + return "jpg"; + case IMAGE_JPEG: + return "jpeg"; + case IMAGE_BMP: + return "bmp"; + case IMAGE_GIF: + return "gif"; + default: + return ""; + } + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/html/EscapeUtil.java b/boyue-common/src/main/java/com/boyue/common/utils/html/EscapeUtil.java new file mode 100644 index 0000000..d0dc42a --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/html/EscapeUtil.java @@ -0,0 +1,167 @@ +package com.boyue.common.utils.html; + +import com.boyue.common.utils.StringUtils; + +/** + * 转义和反转义工具类 + * + * @author boyue + */ +public class EscapeUtil +{ + public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)"; + + private static final char[][] TEXT = new char[64][]; + + static + { + for (int i = 0; i < 64; i++) + { + TEXT[i] = new char[] { (char) i }; + } + + // special HTML characters + TEXT['\''] = "'".toCharArray(); // 单引号 + TEXT['"'] = """.toCharArray(); // 双引号 + TEXT['&'] = "&".toCharArray(); // &符 + TEXT['<'] = "<".toCharArray(); // 小于号 + TEXT['>'] = ">".toCharArray(); // 大于号 + } + + /** + * 转义文本中的HTML字符为安全的字符 + * + * @param text 被转义的文本 + * @return 转义后的文本 + */ + public static String escape(String text) + { + return encode(text); + } + + /** + * 还原被转义的HTML特殊字符 + * + * @param content 包含转义符的HTML内容 + * @return 转换后的字符串 + */ + public static String unescape(String content) + { + return decode(content); + } + + /** + * 清除所有HTML标签,但是不删除标签内的内容 + * + * @param content 文本 + * @return 清除标签后的文本 + */ + public static String clean(String content) + { + return new HTMLFilter().filter(content); + } + + /** + * Escape编码 + * + * @param text 被编码的文本 + * @return 编码后的字符 + */ + private static String encode(String text) + { + if (StringUtils.isEmpty(text)) + { + return StringUtils.EMPTY; + } + + final StringBuilder tmp = new StringBuilder(text.length() * 6); + char c; + for (int i = 0; i < text.length(); i++) + { + c = text.charAt(i); + if (c < 256) + { + tmp.append("%"); + if (c < 16) + { + tmp.append("0"); + } + tmp.append(Integer.toString(c, 16)); + } + else + { + tmp.append("%u"); + if (c <= 0xfff) + { + // issue#I49JU8@Gitee + tmp.append("0"); + } + tmp.append(Integer.toString(c, 16)); + } + } + return tmp.toString(); + } + + /** + * Escape解码 + * + * @param content 被转义的内容 + * @return 解码后的字符串 + */ + public static String decode(String content) + { + if (StringUtils.isEmpty(content)) + { + return content; + } + + StringBuilder tmp = new StringBuilder(content.length()); + int lastPos = 0, pos = 0; + char ch; + while (lastPos < content.length()) + { + pos = content.indexOf("%", lastPos); + if (pos == lastPos) + { + if (content.charAt(pos + 1) == 'u') + { + ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16); + tmp.append(ch); + lastPos = pos + 6; + } + else + { + ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16); + tmp.append(ch); + lastPos = pos + 3; + } + } + else + { + if (pos == -1) + { + tmp.append(content.substring(lastPos)); + lastPos = content.length(); + } + else + { + tmp.append(content.substring(lastPos, pos)); + lastPos = pos; + } + } + } + return tmp.toString(); + } + + public static void main(String[] args) + { + String html = ""; + String escape = EscapeUtil.escape(html); + // String html = "ipt>alert(\"XSS\")ipt>"; + // String html = "<123"; + // String html = "123>"; + System.out.println("clean: " + EscapeUtil.clean(html)); + System.out.println("escape: " + escape); + System.out.println("unescape: " + EscapeUtil.unescape(escape)); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/html/HTMLFilter.java b/boyue-common/src/main/java/com/boyue/common/utils/html/HTMLFilter.java new file mode 100644 index 0000000..44a0ca0 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/html/HTMLFilter.java @@ -0,0 +1,570 @@ +package com.boyue.common.utils.html; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * HTML过滤器,用于去除XSS漏洞隐患。 + * + * @author boyue + */ +public final class HTMLFilter +{ + /** + * regex flag union representing /si modifiers in php + **/ + private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL; + private static final Pattern P_COMMENTS = Pattern.compile("", Pattern.DOTALL); + private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI); + private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL); + private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI); + private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI); + private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI); + private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI); + private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI); + private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?"); + private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?"); + private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?"); + private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))"); + private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL); + private static final Pattern P_END_ARROW = Pattern.compile("^>"); + private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_AMP = Pattern.compile("&"); + private static final Pattern P_QUOTE = Pattern.compile("\""); + private static final Pattern P_LEFT_ARROW = Pattern.compile("<"); + private static final Pattern P_RIGHT_ARROW = Pattern.compile(">"); + private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>"); + + // @xxx could grow large... maybe use sesat's ReferenceMap + private static final ConcurrentMap P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>(); + private static final ConcurrentMap P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>(); + + /** + * set of allowed html elements, along with allowed attributes for each element + **/ + private final Map> vAllowed; + /** + * counts of open tags for each (allowable) html element + **/ + private final Map vTagCounts = new HashMap<>(); + + /** + * html elements which must always be self-closing (e.g. "") + **/ + private final String[] vSelfClosingTags; + /** + * html elements which must always have separate opening and closing tags (e.g. "") + **/ + private final String[] vNeedClosingTags; + /** + * set of disallowed html elements + **/ + private final String[] vDisallowed; + /** + * attributes which should be checked for valid protocols + **/ + private final String[] vProtocolAtts; + /** + * allowed protocols + **/ + private final String[] vAllowedProtocols; + /** + * tags which should be removed if they contain no content (e.g. "" or "") + **/ + private final String[] vRemoveBlanks; + /** + * entities allowed within html markup + **/ + private final String[] vAllowedEntities; + /** + * flag determining whether comments are allowed in input String. + */ + private final boolean stripComment; + private final boolean encodeQuotes; + /** + * flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "" + * becomes " text "). If set to false, unbalanced angle brackets will be html escaped. + */ + private final boolean alwaysMakeTags; + + /** + * Default constructor. + */ + public HTMLFilter() + { + vAllowed = new HashMap<>(); + + final ArrayList a_atts = new ArrayList<>(); + a_atts.add("href"); + a_atts.add("target"); + vAllowed.put("a", a_atts); + + final ArrayList img_atts = new ArrayList<>(); + img_atts.add("src"); + img_atts.add("width"); + img_atts.add("height"); + img_atts.add("alt"); + vAllowed.put("img", img_atts); + + final ArrayList no_atts = new ArrayList<>(); + vAllowed.put("b", no_atts); + vAllowed.put("strong", no_atts); + vAllowed.put("i", no_atts); + vAllowed.put("em", no_atts); + + vSelfClosingTags = new String[] { "img" }; + vNeedClosingTags = new String[] { "a", "b", "strong", "i", "em" }; + vDisallowed = new String[] {}; + vAllowedProtocols = new String[] { "http", "mailto", "https" }; // no ftp. + vProtocolAtts = new String[] { "src", "href" }; + vRemoveBlanks = new String[] { "a", "b", "strong", "i", "em" }; + vAllowedEntities = new String[] { "amp", "gt", "lt", "quot" }; + stripComment = true; + encodeQuotes = true; + alwaysMakeTags = false; + } + + /** + * Map-parameter configurable constructor. + * + * @param conf map containing configuration. keys match field names. + */ + @SuppressWarnings("unchecked") + public HTMLFilter(final Map conf) + { + + assert conf.containsKey("vAllowed") : "configuration requires vAllowed"; + assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags"; + assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags"; + assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed"; + assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols"; + assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts"; + assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks"; + assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities"; + + vAllowed = Collections.unmodifiableMap((HashMap>) conf.get("vAllowed")); + vSelfClosingTags = (String[]) conf.get("vSelfClosingTags"); + vNeedClosingTags = (String[]) conf.get("vNeedClosingTags"); + vDisallowed = (String[]) conf.get("vDisallowed"); + vAllowedProtocols = (String[]) conf.get("vAllowedProtocols"); + vProtocolAtts = (String[]) conf.get("vProtocolAtts"); + vRemoveBlanks = (String[]) conf.get("vRemoveBlanks"); + vAllowedEntities = (String[]) conf.get("vAllowedEntities"); + stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true; + encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true; + alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true; + } + + private void reset() + { + vTagCounts.clear(); + } + + // --------------------------------------------------------------- + // my versions of some PHP library functions + public static String chr(final int decimal) + { + return String.valueOf((char) decimal); + } + + public static String htmlSpecialChars(final String s) + { + String result = s; + result = regexReplace(P_AMP, "&", result); + result = regexReplace(P_QUOTE, """, result); + result = regexReplace(P_LEFT_ARROW, "<", result); + result = regexReplace(P_RIGHT_ARROW, ">", result); + return result; + } + + // --------------------------------------------------------------- + + /** + * given a user submitted input String, filter out any invalid or restricted html. + * + * @param input text (i.e. submitted by a user) than may contain html + * @return "clean" version of input, with only valid, whitelisted html elements allowed + */ + public String filter(final String input) + { + reset(); + String s = input; + + s = escapeComments(s); + + s = balanceHTML(s); + + s = checkTags(s); + + s = processRemoveBlanks(s); + + // s = validateEntities(s); + + return s; + } + + public boolean isAlwaysMakeTags() + { + return alwaysMakeTags; + } + + public boolean isStripComments() + { + return stripComment; + } + + private String escapeComments(final String s) + { + final Matcher m = P_COMMENTS.matcher(s); + final StringBuffer buf = new StringBuffer(); + if (m.find()) + { + final String match = m.group(1); // (.*?) + m.appendReplacement(buf, Matcher.quoteReplacement("")); + } + m.appendTail(buf); + + return buf.toString(); + } + + private String balanceHTML(String s) + { + if (alwaysMakeTags) + { + // + // try and form html + // + s = regexReplace(P_END_ARROW, "", s); + // 不追加结束标签 + s = regexReplace(P_BODY_TO_END, "<$1>", s); + s = regexReplace(P_XML_CONTENT, "$1<$2", s); + + } + else + { + // + // escape stray brackets + // + s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s); + s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s); + + // + // the last regexp causes '<>' entities to appear + // (we need to do a lookahead assertion so that the last bracket can + // be used in the next pass of the regexp) + // + s = regexReplace(P_BOTH_ARROWS, "", s); + } + + return s; + } + + private String checkTags(String s) + { + Matcher m = P_TAGS.matcher(s); + + final StringBuffer buf = new StringBuffer(); + while (m.find()) + { + String replaceStr = m.group(1); + replaceStr = processTag(replaceStr); + m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr)); + } + m.appendTail(buf); + + // these get tallied in processTag + // (remember to reset before subsequent calls to filter method) + final StringBuilder sBuilder = new StringBuilder(buf.toString()); + for (String key : vTagCounts.keySet()) + { + for (int ii = 0; ii < vTagCounts.get(key); ii++) + { + sBuilder.append(""); + } + } + s = sBuilder.toString(); + + return s; + } + + private String processRemoveBlanks(final String s) + { + String result = s; + for (String tag : vRemoveBlanks) + { + if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) + { + P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?>")); + } + result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result); + if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) + { + P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>")); + } + result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result); + } + + return result; + } + + private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) + { + Matcher m = regex_pattern.matcher(s); + return m.replaceAll(replacement); + } + + private String processTag(final String s) + { + // ending tags + Matcher m = P_END_TAG.matcher(s); + if (m.find()) + { + final String name = m.group(1).toLowerCase(); + if (allowed(name)) + { + if (!inArray(name, vSelfClosingTags)) + { + if (vTagCounts.containsKey(name)) + { + vTagCounts.put(name, vTagCounts.get(name) - 1); + return ""; + } + } + } + } + + // starting tags + m = P_START_TAG.matcher(s); + if (m.find()) + { + final String name = m.group(1).toLowerCase(); + final String body = m.group(2); + String ending = m.group(3); + + // debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" ); + if (allowed(name)) + { + final StringBuilder params = new StringBuilder(); + + final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body); + final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body); + final List paramNames = new ArrayList<>(); + final List paramValues = new ArrayList<>(); + while (m2.find()) + { + paramNames.add(m2.group(1)); // ([a-z0-9]+) + paramValues.add(m2.group(3)); // (.*?) + } + while (m3.find()) + { + paramNames.add(m3.group(1)); // ([a-z0-9]+) + paramValues.add(m3.group(3)); // ([^\"\\s']+) + } + + String paramName, paramValue; + for (int ii = 0; ii < paramNames.size(); ii++) + { + paramName = paramNames.get(ii).toLowerCase(); + paramValue = paramValues.get(ii); + + // debug( "paramName='" + paramName + "'" ); + // debug( "paramValue='" + paramValue + "'" ); + // debug( "allowed? " + vAllowed.get( name ).contains( paramName ) ); + + if (allowedAttribute(name, paramName)) + { + if (inArray(paramName, vProtocolAtts)) + { + paramValue = processParamProtocol(paramValue); + } + params.append(' ').append(paramName).append("=\\\"").append(paramValue).append("\\\""); + } + } + + if (inArray(name, vSelfClosingTags)) + { + ending = " /"; + } + + if (inArray(name, vNeedClosingTags)) + { + ending = ""; + } + + if (ending == null || ending.length() < 1) + { + if (vTagCounts.containsKey(name)) + { + vTagCounts.put(name, vTagCounts.get(name) + 1); + } + else + { + vTagCounts.put(name, 1); + } + } + else + { + ending = " /"; + } + return "<" + name + params + ending + ">"; + } + else + { + return ""; + } + } + + // comments + m = P_COMMENT.matcher(s); + if (!stripComment && m.find()) + { + return "<" + m.group() + ">"; + } + + return ""; + } + + private String processParamProtocol(String s) + { + s = decodeEntities(s); + final Matcher m = P_PROTOCOL.matcher(s); + if (m.find()) + { + final String protocol = m.group(1); + if (!inArray(protocol, vAllowedProtocols)) + { + // bad protocol, turn into local anchor link instead + s = "#" + s.substring(protocol.length() + 1); + if (s.startsWith("#//")) + { + s = "#" + s.substring(3); + } + } + } + + return s; + } + + private String decodeEntities(String s) + { + StringBuffer buf = new StringBuffer(); + + Matcher m = P_ENTITY.matcher(s); + while (m.find()) + { + final String match = m.group(1); + final int decimal = Integer.decode(match).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENTITY_UNICODE.matcher(s); + while (m.find()) + { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENCODE.matcher(s); + while (m.find()) + { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + s = validateEntities(s); + return s; + } + + private String validateEntities(final String s) + { + StringBuffer buf = new StringBuffer(); + + // validate entities throughout the string + Matcher m = P_VALID_ENTITIES.matcher(s); + while (m.find()) + { + final String one = m.group(1); // ([^&;]*) + final String two = m.group(2); // (?=(;|&|$)) + m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two))); + } + m.appendTail(buf); + + return encodeQuotes(buf.toString()); + } + + private String encodeQuotes(final String s) + { + if (encodeQuotes) + { + StringBuffer buf = new StringBuffer(); + Matcher m = P_VALID_QUOTES.matcher(s); + while (m.find()) + { + final String one = m.group(1); // (>|^) + final String two = m.group(2); // ([^<]+?) + final String three = m.group(3); // (<|$) + // 不替换双引号为",防止json格式无效 regexReplace(P_QUOTE, """, two) + m.appendReplacement(buf, Matcher.quoteReplacement(one + two + three)); + } + m.appendTail(buf); + return buf.toString(); + } + else + { + return s; + } + } + + private String checkEntity(final String preamble, final String term) + { + + return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&" + preamble; + } + + private boolean isValidEntity(final String entity) + { + return inArray(entity, vAllowedEntities); + } + + private static boolean inArray(final String s, final String[] array) + { + for (String item : array) + { + if (item != null && item.equals(s)) + { + return true; + } + } + return false; + } + + private boolean allowed(final String name) + { + return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed); + } + + private boolean allowedAttribute(final String name, final String paramName) + { + return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName)); + } +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/utils/http/HttpClientUtil.java b/boyue-common/src/main/java/com/boyue/common/utils/http/HttpClientUtil.java new file mode 100644 index 0000000..53fe7f0 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/http/HttpClientUtil.java @@ -0,0 +1,322 @@ +package com.boyue.common.utils.http; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.conn.ssl.DefaultHostnameVerifier; +import org.apache.http.conn.util.PublicSuffixMatcher; +import org.apache.http.conn.util.PublicSuffixMatcherLoader; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.fastjson2.JSON; + +public class HttpClientUtil { + + private static final Logger log = LoggerFactory.getLogger(HttpClientUtil.class); + /** + * 默认参数设置 + * setConnectTimeout:设置连接超时时间,单位毫秒。 + * setConnectionRequestTimeout:设置从connect Manager获取Connection 超时时间,单位毫秒。 + * setSocketTimeout:请求获取数据的超时时间,单位毫秒。访问一个接口,多少时间内无法返回数据,就直接放弃此次调用。 暂时定义15分钟 + */ + private static RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(600000) + .setConnectTimeout(600000) + .setConnectionRequestTimeout(600000).build(); + + private static CloseableHttpClient client = HttpUtils.initClient(); + + /** + * 发送 post请求 + * + * @param httpUrl 地址 + */ + public static String sendHttpPost(String httpUrl) { + HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost + return sendHttpPost(httpPost); + } + + /** + * 发送 post请求 + * + * @param httpUrl 地址 + * @param params 参数(格式:key1=value1&key2=value2) + */ + public static String sendHttpPost(String httpUrl, String params) { + HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost + try { + // 设置参数 + StringEntity stringEntity = new StringEntity(params, "UTF-8"); + stringEntity.setContentType("application/x-www-form-urlencoded"); + httpPost.setEntity(stringEntity); + } catch (Exception e) { + e.printStackTrace(); + } + return sendHttpPost(httpPost); + } + + public static String sendHttpPost(String httpUrl, Object object) { + HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost + String jsonString = JSON.toJSONString(object); + httpPost.setHeader("Accept", ContentType.APPLICATION_JSON.getMimeType()); + httpPost.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType()); + log.debug(jsonString); + try { + + // 设置参数 + StringEntity stringEntity = new StringEntity(jsonString, ContentType.APPLICATION_JSON); + + httpPost.setEntity(stringEntity); + } catch (Exception e) { + e.printStackTrace(); + } + return sendHttpPost(httpPost); + } + + public static String sendHttpPost(String httpUrl, Object data, Map headersMap) { + HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost + String jsonString = JSON.toJSONString(data); + httpPost.setHeader("Accept", ContentType.APPLICATION_JSON.getMimeType()); + httpPost.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType()); + for (String keySet : headersMap.keySet()) { + httpPost.setHeader(keySet, headersMap.get(keySet)); + } + log.debug(jsonString); + try { + // 设置参数 + StringEntity stringEntity = new StringEntity(jsonString, ContentType.APPLICATION_JSON); + + httpPost.setEntity(stringEntity); + } catch (Exception e) { + e.printStackTrace(); + } + return sendHttpPost(httpPost); + } + + /** + * 发送 post请求 + * + * @param httpUrl 地址 + * @param maps 参数 + */ + public static String sendHttpPost(String httpUrl, Map maps) { + HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost + // 创建参数队列 + List nameValuePairs = new ArrayList(); + for (String key : maps.keySet()) { + nameValuePairs.add(new BasicNameValuePair(key, maps.get(key))); + } + try { + httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8")); + } catch (Exception e) { + e.printStackTrace(); + } + return sendHttpPost(httpPost); + } + + /** + * 发送 get请求 + * + * @param httpUrl + */ + public static String sendHttpGet(String httpUrl) { + HttpGet httpGet = new HttpGet(httpUrl);// 创建get请求 + return sendHttpGet(httpGet); + } + + /** + * 发送 get请求Https + * + * @param httpUrl + */ + public static String sendHttpsGet(String httpUrl) { + HttpGet httpGet = new HttpGet(httpUrl);// 创建get请求 + return sendHttpsGet(httpGet); + } + + /** + * 发送Post请求 + * + * @param httpPost + * @return + */ + private static String sendHttpPost(HttpPost httpPost) { + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + HttpEntity entity = null; + String responseContent = null; + try { + // 创建默认的httpClient实例 + // httpClient = HttpClients.createDefault(); + httpPost.setConfig(requestConfig); + // 执行请求 + long execStart = System.currentTimeMillis(); + response = client.execute(httpPost); + long execEnd = System.currentTimeMillis(); + log.debug("=================执行post请求耗时:" + (execEnd - execStart) + "ms"); + long getStart = System.currentTimeMillis(); + entity = response.getEntity(); + responseContent = EntityUtils.toString(entity, "UTF-8"); + long getEnd = System.currentTimeMillis(); + log.debug("=================获取响应结果耗时:" + (getEnd - getStart) + "ms"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + // 关闭连接,释放资源 + if (response != null) { + response.close(); + } + if (httpClient != null) { + httpClient.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return responseContent; + } + + /** + * 发送Get请求 + * + * @param httpGet + * @return + */ + private static String sendHttpGet(HttpGet httpGet) { + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + HttpEntity entity = null; + String responseContent = null; + try { + // 创建默认的httpClient实例. + + httpGet.setConfig(requestConfig); + // 执行请求 + response = client.execute(httpGet); + entity = response.getEntity(); + responseContent = EntityUtils.toString(entity, "UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + // 关闭连接,释放资源 + if (response != null) { + response.close(); + } + if (httpClient != null) { + httpClient.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return responseContent; + } + + /** + * 发送Get请求Https + * + * @param httpGet + * @return + */ + private static String sendHttpsGet(HttpGet httpGet) { + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + HttpEntity entity = null; + String responseContent = null; + try { + // 创建默认的httpClient实例. + PublicSuffixMatcher publicSuffixMatcher = PublicSuffixMatcherLoader + .load(httpGet.getURI().toURL()); + DefaultHostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(publicSuffixMatcher); + httpClient = HttpClients.custom().setSSLHostnameVerifier(hostnameVerifier).build(); + httpGet.setConfig(requestConfig); + // 执行请求 + response = httpClient.execute(httpGet); + entity = response.getEntity(); + responseContent = EntityUtils.toString(entity, "UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + // 关闭连接,释放资源 + if (response != null) { + response.close(); + } + if (httpClient != null) { + httpClient.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return responseContent; + } + + /** + * 发送xml数据 + * + * @param url + * @param xmlData + * @return + * @throws ClientProtocolException + * @throws IOException + */ + public static HttpResponse sendXMLDataByPost(String url, String xmlData) + throws ClientProtocolException, IOException { + + HttpPost httppost = new HttpPost(url); + StringEntity entity = new StringEntity(xmlData); + httppost.setEntity(entity); + httppost.setHeader("Content-Type", "text/xml;charset=UTF-8"); + HttpResponse response = client.execute(httppost); + return response; + } + + /** + * 获得响应HTTP实体内容 + * + * @param response + * @return + * @throws IOException + * @throws UnsupportedEncodingException + */ + public static String getHttpEntityContent(HttpResponse response) throws IOException, UnsupportedEncodingException { + HttpEntity entity = response.getEntity(); + if (entity != null) { + InputStream is = entity.getContent(); + BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8")); + String line = br.readLine(); + StringBuilder sb = new StringBuilder(); + while (line != null) { + sb.append(line + "\n"); + line = br.readLine(); + } + return sb.toString(); + } + return ""; + } + +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/http/HttpConf.java b/boyue-common/src/main/java/com/boyue/common/utils/http/HttpConf.java new file mode 100644 index 0000000..571f9d2 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/http/HttpConf.java @@ -0,0 +1,33 @@ +package com.boyue.common.utils.http; + +/** + * http 配置信息 + * + * @author boyue + */ +public class HttpConf +{ + // 获取连接的最大等待时间 + public static int WAIT_TIMEOUT = 10000; + + // 连接超时时间 + public static int CONNECT_TIMEOUT = 10000; + + // 读取超时时间 + public static int SO_TIMEOUT = 60000; + + // 最大连接数 + public static int MAX_TOTAL_CONN = 200; + + // 每个路由最大连接数 + public static int MAX_ROUTE_CONN = 150; + + // 重试次数 + public static int RETRY_COUNT = 3; + + // EPTWebServes地址 + public static String EPTWEBSERVES_URL; + + // tomcat默认keepAliveTimeout为20s + public static int KEEP_ALIVE_TIMEOUT; +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/utils/http/HttpHelper.java b/boyue-common/src/main/java/com/boyue/common/utils/http/HttpHelper.java new file mode 100644 index 0000000..e692194 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/http/HttpHelper.java @@ -0,0 +1,55 @@ +package com.boyue.common.utils.http; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import jakarta.servlet.ServletRequest; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 通用http工具封装 + * + * @author boyue + */ +public class HttpHelper +{ + private static final Logger LOGGER = LoggerFactory.getLogger(HttpHelper.class); + + public static String getBodyString(ServletRequest request) + { + StringBuilder sb = new StringBuilder(); + BufferedReader reader = null; + try (InputStream inputStream = request.getInputStream()) + { + reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + String line = ""; + while ((line = reader.readLine()) != null) + { + sb.append(line); + } + } + catch (IOException e) + { + LOGGER.warn("getBodyString出现问题!"); + } + finally + { + if (reader != null) + { + try + { + reader.close(); + } + catch (IOException e) + { + LOGGER.error(ExceptionUtils.getMessage(e)); + } + } + } + return sb.toString(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/http/HttpUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/http/HttpUtils.java new file mode 100644 index 0000000..927109f --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/http/HttpUtils.java @@ -0,0 +1,748 @@ +package com.boyue.common.utils.http; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.ConnectException; +import java.net.SocketTimeoutException; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.StandardCharsets; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.NameValuePair; +import org.apache.http.client.HttpRequestRetryHandler; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.config.RequestConfig.Builder; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.conn.ConnectTimeoutException; +import org.apache.http.conn.ConnectionKeepAliveStrategy; +import org.apache.http.conn.HttpClientConnectionManager; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustStrategy; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.protocol.HttpContext; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.boyue.common.constant.Constants; +import com.boyue.common.utils.StringUtils; + +/** + * 通用http发送方法 + * + * @author boyue + */ +public class HttpUtils +{ + private static final Logger log = LoggerFactory.getLogger(HttpUtils.class); + + public static RequestConfig requestConfig; + + private static CloseableHttpClient httpClient; + + private static PoolingHttpClientConnectionManager connMgr; + + private static IdleConnectionMonitorThread idleThread; + + static + { + HttpUtils.initClient(); + } + + /** + * 向指定 URL 发送GET方法的请求 + * + * @param url 发送请求的 URL + * @return 所代表远程资源的响应结果 + */ + public static String sendGet(String url) + { + return sendGet(url, StringUtils.EMPTY); + } + + /** + * 向指定 URL 发送GET方法的请求 + * + * @param url 发送请求的 URL + * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 + * @return 所代表远程资源的响应结果 + */ + public static String sendGet(String url, String param) + { + return sendGet(url, param, Constants.UTF8); + } + + /** + * 向指定 URL 发送GET方法的请求 + * + * @param url 发送请求的 URL + * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 + * @param contentType 编码类型 + * @return 所代表远程资源的响应结果 + */ + public static String sendGet(String url, String param, String contentType) + { + StringBuilder result = new StringBuilder(); + BufferedReader in = null; + try + { + String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url; + log.info("sendGet - {}", urlNameString); + URI uri = new URI(urlNameString); + URL realUrl = uri.toURL(); + URLConnection connection = realUrl.openConnection(); + connection.setRequestProperty("accept", "*/*"); + connection.setRequestProperty("connection", "Keep-Alive"); + connection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); + connection.connect(); + in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType)); + String line; + while ((line = in.readLine()) != null) + { + result.append(line); + } + log.info("recv - {}", result); + } + catch (ConnectException e) + { + log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e); + } + catch (SocketTimeoutException e) + { + log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e); + } + catch (IOException e) + { + log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e); + } + catch (Exception e) + { + log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e); + } + finally + { + try + { + if (in != null) + { + in.close(); + } + } + catch (Exception ex) + { + log.error("调用in.close Exception, url=" + url + ",param=" + param, ex); + } + } + return result.toString(); + } + + /** + * 向指定 URL 发送POST方法的请求 + * + * @param url 发送请求的 URL + * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 + * @return 所代表远程资源的响应结果 + */ + public static String sendPost(String url, String param) + { + PrintWriter out = null; + BufferedReader in = null; + StringBuilder result = new StringBuilder(); + try + { + log.info("sendPost - {}", url); + URI uri = new URI(url); + URL realUrl = uri.toURL(); + URLConnection conn = realUrl.openConnection(); + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); + conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); + conn.setRequestProperty("Accept-Charset", "utf-8"); + conn.setRequestProperty("contentType", "utf-8"); + conn.setDoOutput(true); + conn.setDoInput(true); + out = new PrintWriter(conn.getOutputStream()); + out.print(param); + out.flush(); + in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8)); + String line; + while ((line = in.readLine()) != null) + { + result.append(line); + } + log.info("recv - {}", result); + } + catch (ConnectException e) + { + log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e); + } + catch (SocketTimeoutException e) + { + log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e); + } + catch (IOException e) + { + log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e); + } + catch (Exception e) + { + log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e); + } + finally + { + try + { + if (out != null) + { + out.close(); + } + if (in != null) + { + in.close(); + } + } + catch (IOException ex) + { + log.error("调用in.close Exception, url=" + url + ",param=" + param, ex); + } + } + return result.toString(); + } + + public static String sendSSLPost(String url, String param) + { + StringBuilder result = new StringBuilder(); + String urlNameString = url + "?" + param; + try + { + log.info("sendSSLPost - {}", urlNameString); + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom()); + URI uri = new URI(urlNameString); + URL console = uri.toURL(); + HttpsURLConnection conn = (HttpsURLConnection) console.openConnection(); + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); + conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); + conn.setRequestProperty("Accept-Charset", "utf-8"); + conn.setRequestProperty("contentType", "utf-8"); + conn.setDoOutput(true); + conn.setDoInput(true); + + conn.setSSLSocketFactory(sc.getSocketFactory()); + conn.setHostnameVerifier(new TrustAnyHostnameVerifier()); + conn.connect(); + InputStream is = conn.getInputStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + String ret = ""; + while ((ret = br.readLine()) != null) + { + if (ret != null && !ret.trim().equals("")) + { + result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8)); + } + } + log.info("recv - {}", result); + conn.disconnect(); + br.close(); + } + catch (ConnectException e) + { + log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e); + } + catch (SocketTimeoutException e) + { + log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e); + } + catch (IOException e) + { + log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e); + } + catch (Exception e) + { + log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e); + } + return result.toString(); + } + + private static class TrustAnyTrustManager implements X509TrustManager + { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + { + } + + @Override + public X509Certificate[] getAcceptedIssuers() + { + return new X509Certificate[] {}; + } + } + + private static class TrustAnyHostnameVerifier implements HostnameVerifier + { + @Override + public boolean verify(String hostname, SSLSession session) + { + return true; + } + } + + /** + * 获取httpClient + * + * @return + */ + public static CloseableHttpClient getHttpClient() + { + if (httpClient != null) + { + return httpClient; + } + else + { + return HttpClients.createDefault(); + } + } + + /** + * 创建连接池管理器 + * + * @return + */ + private static PoolingHttpClientConnectionManager createConnectionManager() + { + + PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(); + // 将最大连接数增加到 + connMgr.setMaxTotal(HttpConf.MAX_TOTAL_CONN); + // 将每个路由基础的连接增加到 + connMgr.setDefaultMaxPerRoute(HttpConf.MAX_ROUTE_CONN); + + return connMgr; + } + + /** + * 根据当前配置创建HTTP请求配置参数。 + * + * @return 返回HTTP请求配置。 + */ + private static RequestConfig createRequestConfig() + { + Builder builder = RequestConfig.custom(); + builder.setConnectionRequestTimeout(StringUtils.nvl(HttpConf.WAIT_TIMEOUT, 10000)); + builder.setConnectTimeout(StringUtils.nvl(HttpConf.CONNECT_TIMEOUT, 10000)); + builder.setSocketTimeout(StringUtils.nvl(HttpConf.SO_TIMEOUT, 60000)); + return builder.build(); + } + + /** + * 创建默认的HTTPS客户端,信任所有的证书。 + * + * @return 返回HTTPS客户端,如果创建失败,返回HTTP客户端。 + */ + private static CloseableHttpClient createHttpClient(HttpClientConnectionManager connMgr) + { + try + { + final SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() + { + @Override + public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException + { + // 信任所有 + return true; + } + }).build(); + final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext); + + // 重试机制 + HttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(HttpConf.RETRY_COUNT, true); + ConnectionKeepAliveStrategy connectionKeepAliveStrategy = new ConnectionKeepAliveStrategy() + { + @Override + public long getKeepAliveDuration(HttpResponse httpResponse, HttpContext httpContext) + { + return HttpConf.KEEP_ALIVE_TIMEOUT; // tomcat默认keepAliveTimeout为20s + } + }; + httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).setConnectionManager(connMgr) + .setDefaultRequestConfig(requestConfig).setRetryHandler(retryHandler) + .setKeepAliveStrategy(connectionKeepAliveStrategy).build(); + } + catch (Exception e) + { + log.error("Create http client failed", e); + httpClient = HttpClients.createDefault(); + } + + return httpClient; + } + + /** + * 初始化 只需调用一次 + */ + public synchronized static CloseableHttpClient initClient() + { + if (httpClient == null) + { + connMgr = createConnectionManager(); + requestConfig = createRequestConfig(); + // 初始化httpClient连接池 + httpClient = createHttpClient(connMgr); + // 清理连接池 + idleThread = new IdleConnectionMonitorThread(connMgr); + idleThread.start(); + } + + return httpClient; + } + + /** + * 关闭HTTP客户端。 + * + * @param httpClient HTTP客户端。 + */ + public synchronized static void shutdown() + { + try + { + if (idleThread != null) + { + idleThread.shutdown(); + idleThread = null; + } + } + catch (Exception e) + { + log.error("httpclient connection manager close", e); + } + + try + { + if (httpClient != null) + { + httpClient.close(); + httpClient = null; + } + } + catch (IOException e) + { + log.error("httpclient close", e); + } + } + + /** + * 请求上游 GET提交 + * + * @param uri + * @throws IOException + */ + public static String getCall(final String uri) throws Exception + { + + return getCall(uri, null, Constants.UTF8); + } + + /** + * 请求上游 GET提交 + * + * @param uri + * @param contentType + * @throws IOException + */ + public static String getCall(final String uri, String contentType) throws Exception + { + + return getCall(uri, contentType, Constants.UTF8); + } + + /** + * 请求上游 GET提交 + * + * @param uri + * @param contentType + * @param charsetName + * @throws IOException + */ + public static String getCall(final String uri, String contentType, String charsetName) throws Exception + { + + final String url = uri; + final HttpGet httpGet = new HttpGet(url); + httpGet.setConfig(requestConfig); + if (!StringUtils.isEmpty(contentType)) + { + httpGet.addHeader("Content-Type", contentType); + } + final CloseableHttpResponse httpRsp = getHttpClient().execute(httpGet); + try + { + if (httpRsp.getStatusLine().getStatusCode() == HttpStatus.SC_OK + || httpRsp.getStatusLine().getStatusCode() == HttpStatus.SC_FORBIDDEN) + { + final HttpEntity entity = httpRsp.getEntity(); + final String rspText = EntityUtils.toString(entity, charsetName); + EntityUtils.consume(entity); + return rspText; + } + else + { + throw new IOException("HTTP StatusCode=" + httpRsp.getStatusLine().getStatusCode()); + } + } + finally + { + try + { + httpRsp.close(); + } + catch (Exception e) + { + log.error("关闭httpRsp异常", e); + } + } + } + + /** + * 请求上游 POST提交 + * + * @param uri + * @param paramsMap + * @throws IOException + */ + public static String postCall(final String uri, Map paramsMap) throws Exception + { + return postCall(uri, null, paramsMap, Constants.UTF8); + } + + /** + * 请求上游 POST提交 + * + * @param uri + * @param contentType + * @param paramsMap + * @throws IOException + */ + public static String postCall(final String uri, String contentType, Map paramsMap) throws Exception + { + + return postCall(uri, contentType, paramsMap, Constants.UTF8); + } + + /** + * 请求上游 POST提交 + * + * @param uri + * @param contentType + * @param paramsMap + * @param charsetName + * @throws IOException + */ + public static String postCall(final String uri, String contentType, Map paramsMap, + String charsetName) throws Exception + { + + final String url = uri; + final HttpPost httpPost = new HttpPost(url); + httpPost.setConfig(requestConfig); + if (!StringUtils.isEmpty(contentType)) + { + httpPost.addHeader("Content-Type", contentType); + } + // 添加参数 + List list = new ArrayList(); + if (paramsMap != null) + { + for (Map.Entry entry : paramsMap.entrySet()) + { + list.add(new BasicNameValuePair(entry.getKey(), (String) entry.getValue())); + } + } + httpPost.setEntity(new UrlEncodedFormEntity(list, charsetName)); + + final CloseableHttpResponse httpRsp = getHttpClient().execute(httpPost); + + try + { + if (httpRsp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) + { + final HttpEntity entity = httpRsp.getEntity(); + final String rspText = EntityUtils.toString(entity, charsetName); + EntityUtils.consume(entity); + return rspText; + } + else + { + throw new IOException("HTTP StatusCode=" + httpRsp.getStatusLine().getStatusCode()); + } + } + finally + { + try + { + httpRsp.close(); + } + catch (Exception e) + { + log.error("关闭httpRsp异常", e); + } + } + } + + /** + * 请求上游 POST提交 + * + * @param uri + * @param param + * @throws IOException + */ + public static String postCall(final String uri, String param) throws Exception + { + + return postCall(uri, null, param, Constants.UTF8); + } + + /** + * 请求上游 POST提交 + * + * @param uri + * @param contentType + * @param param + * @throws IOException + */ + public static String postCall(final String uri, String contentType, String param) throws Exception + { + + return postCall(uri, contentType, param, Constants.UTF8); + } + + /** + * 请求上游 POST提交 + * + * @param uri + * @param contentType + * @param param + * @param charsetName + * @throws IOException + */ + public static String postCall(final String uri, String contentType, String param, String charsetName) + throws Exception + { + + final String url = uri; + final HttpPost httpPost = new HttpPost(url); + httpPost.setConfig(requestConfig); + if (!StringUtils.isEmpty(contentType)) + { + httpPost.addHeader("Content-Type", contentType); + } + else + { + httpPost.addHeader("Content-Type", "application/json"); + } + // 添加参数 + StringEntity paramEntity = new StringEntity(param, charsetName); + httpPost.setEntity(paramEntity); + + final CloseableHttpResponse httpRsp = getHttpClient().execute(httpPost); + + try + { + if (httpRsp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) + { + final HttpEntity entity = httpRsp.getEntity(); + final String rspText = EntityUtils.toString(entity, charsetName); + EntityUtils.consume(entity); + return rspText; + } + else + { + throw new IOException("HTTP StatusCode=" + httpRsp.getStatusLine().getStatusCode()); + } + } + finally + { + try + { + httpRsp.close(); + } + catch (Exception e) + { + log.error("关闭httpRsp异常", e); + } + } + } + + /** + * 判断HTTP异常是否为读取超时。 + * + * @param e 异常对象。 + * @return 如果是读取引起的异常(而非连接),则返回true;否则返回false。 + */ + public static boolean isReadTimeout(final Throwable e) + { + return (!isCausedBy(e, ConnectTimeoutException.class) && isCausedBy(e, SocketTimeoutException.class)); + } + + /** + * 检测异常e被触发的原因是不是因为异常cause。检测被封装的异常。 + * + * @param e 捕获的异常。 + * @param cause 异常触发原因。 + * @return 如果异常e是由cause类异常触发,则返回true;否则返回false。 + */ + public static boolean isCausedBy(final Throwable e, final Class cause) + { + if (cause.isAssignableFrom(e.getClass())) + { + return true; + } + else + { + Throwable t = e.getCause(); + while (t != null && t != e) + { + if (cause.isAssignableFrom(t.getClass())) + { + return true; + } + t = t.getCause(); + } + return false; + } + } +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/utils/http/IdleConnectionMonitorThread.java b/boyue-common/src/main/java/com/boyue/common/utils/http/IdleConnectionMonitorThread.java new file mode 100644 index 0000000..1b8398e --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/http/IdleConnectionMonitorThread.java @@ -0,0 +1,73 @@ +package com.boyue.common.utils.http; + +import java.util.concurrent.TimeUnit; + +import org.apache.http.conn.HttpClientConnectionManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 连接池清理 + * + * @author boyue + */ +public class IdleConnectionMonitorThread extends Thread +{ + private static final Logger log = LoggerFactory.getLogger(IdleConnectionMonitorThread.class); + + private final HttpClientConnectionManager connMgr; + + private volatile boolean shutdown; + + public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr) + { + super(); + this.shutdown = false; + this.connMgr = connMgr; + } + + @Override + public void run() + { + while (!shutdown) + { + try + { + synchronized (this) + { + // 每5秒检查一次关闭连接 + wait(HttpConf.KEEP_ALIVE_TIMEOUT / 4); + // 关闭失效的连接 + connMgr.closeExpiredConnections(); + // 可选的, 关闭20秒内不活动的连接 + connMgr.closeIdleConnections(HttpConf.KEEP_ALIVE_TIMEOUT, TimeUnit.MILLISECONDS); + // log.debug("关闭失效的连接"); + } + } + catch (Exception e) + { + log.error("关闭失效连接异常", e); + } + } + } + + public void shutdown() + { + shutdown = true; + if (connMgr != null) + { + try + { + connMgr.shutdown(); + } + catch (Exception e) + { + log.error("连接池异常", e); + } + } + synchronized (this) + { + notifyAll(); + } + } +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/utils/ip/AddressUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/ip/AddressUtils.java new file mode 100644 index 0000000..1769467 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/ip/AddressUtils.java @@ -0,0 +1,56 @@ +package com.boyue.common.utils.ip; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.boyue.common.config.BoYueConfig; +import com.boyue.common.constant.Constants; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.http.HttpUtils; + +/** + * 获取地址类 + * + * @author boyue + */ +public class AddressUtils +{ + private static final Logger log = LoggerFactory.getLogger(AddressUtils.class); + + // IP地址查询 + public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp"; + + // 未知地址 + public static final String UNKNOWN = "XX XX"; + + public static String getRealAddressByIP(String ip) + { + // 内网不查询 + if (IpUtils.internalIp(ip)) + { + return "内网IP"; + } + if (BoYueConfig.isAddressEnabled()) + { + try + { + String rspStr = HttpUtils.sendGet(IP_URL, "ip=" + ip + "&json=true", Constants.GBK); + if (StringUtils.isEmpty(rspStr)) + { + log.error("获取地理位置异常 {}", ip); + return UNKNOWN; + } + JSONObject obj = JSON.parseObject(rspStr); + String region = obj.getString("pro"); + String city = obj.getString("city"); + return String.format("%s %s", region, city); + } + catch (Exception e) + { + log.error("获取地理位置异常 {}", ip); + } + } + return UNKNOWN; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/ip/IpUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/ip/IpUtils.java new file mode 100644 index 0000000..5057fb4 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/ip/IpUtils.java @@ -0,0 +1,382 @@ +package com.boyue.common.utils.ip; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import jakarta.servlet.http.HttpServletRequest; +import com.boyue.common.utils.ServletUtils; +import com.boyue.common.utils.StringUtils; + +/** + * 获取IP方法 + * + * @author boyue + */ +public class IpUtils +{ + public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)"; + // 匹配 ip + public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")"; + public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))"; + // 匹配网段 + public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")"; + + /** + * 获取客户端IP + * + * @return IP地址 + */ + public static String getIpAddr() + { + return getIpAddr(ServletUtils.getRequest()); + } + + /** + * 获取客户端IP + * + * @param request 请求对象 + * @return IP地址 + */ + public static String getIpAddr(HttpServletRequest request) + { + if (request == null) + { + return "unknown"; + } + String ip = request.getHeader("x-forwarded-for"); + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) + { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) + { + ip = request.getHeader("X-Forwarded-For"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) + { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) + { + ip = request.getHeader("X-Real-IP"); + } + + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) + { + ip = request.getRemoteAddr(); + } + + return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip); + } + + /** + * 检查是否为内部IP地址 + * + * @param ip IP地址 + * @return 结果 + */ + public static boolean internalIp(String ip) + { + byte[] addr = textToNumericFormatV4(ip); + return internalIp(addr) || "127.0.0.1".equals(ip); + } + + /** + * 检查是否为内部IP地址 + * + * @param addr byte地址 + * @return 结果 + */ + private static boolean internalIp(byte[] addr) + { + if (StringUtils.isNull(addr) || addr.length < 2) + { + return true; + } + final byte b0 = addr[0]; + final byte b1 = addr[1]; + // 10.x.x.x/8 + final byte SECTION_1 = 0x0A; + // 172.16.x.x/12 + final byte SECTION_2 = (byte) 0xAC; + final byte SECTION_3 = (byte) 0x10; + final byte SECTION_4 = (byte) 0x1F; + // 192.168.x.x/16 + final byte SECTION_5 = (byte) 0xC0; + final byte SECTION_6 = (byte) 0xA8; + switch (b0) + { + case SECTION_1: + return true; + case SECTION_2: + if (b1 >= SECTION_3 && b1 <= SECTION_4) + { + return true; + } + case SECTION_5: + switch (b1) + { + case SECTION_6: + return true; + } + default: + return false; + } + } + + /** + * 将IPv4地址转换成字节 + * + * @param text IPv4地址 + * @return byte 字节 + */ + public static byte[] textToNumericFormatV4(String text) + { + if (text.length() == 0) + { + return null; + } + + byte[] bytes = new byte[4]; + String[] elements = text.split("\\.", -1); + try + { + long l; + int i; + switch (elements.length) + { + case 1: + l = Long.parseLong(elements[0]); + if ((l < 0L) || (l > 4294967295L)) + { + return null; + } + bytes[0] = (byte) (int) (l >> 24 & 0xFF); + bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF); + bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 2: + l = Integer.parseInt(elements[0]); + if ((l < 0L) || (l > 255L)) + { + return null; + } + bytes[0] = (byte) (int) (l & 0xFF); + l = Integer.parseInt(elements[1]); + if ((l < 0L) || (l > 16777215L)) + { + return null; + } + bytes[1] = (byte) (int) (l >> 16 & 0xFF); + bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 3: + for (i = 0; i < 2; ++i) + { + l = Integer.parseInt(elements[i]); + if ((l < 0L) || (l > 255L)) + { + return null; + } + bytes[i] = (byte) (int) (l & 0xFF); + } + l = Integer.parseInt(elements[2]); + if ((l < 0L) || (l > 65535L)) + { + return null; + } + bytes[2] = (byte) (int) (l >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 4: + for (i = 0; i < 4; ++i) + { + l = Integer.parseInt(elements[i]); + if ((l < 0L) || (l > 255L)) + { + return null; + } + bytes[i] = (byte) (int) (l & 0xFF); + } + break; + default: + return null; + } + } + catch (NumberFormatException e) + { + return null; + } + return bytes; + } + + /** + * 获取IP地址 + * + * @return 本地IP地址 + */ + public static String getHostIp() + { + try + { + return InetAddress.getLocalHost().getHostAddress(); + } + catch (UnknownHostException e) + { + } + return "127.0.0.1"; + } + + /** + * 获取主机名 + * + * @return 本地主机名 + */ + public static String getHostName() + { + try + { + return InetAddress.getLocalHost().getHostName(); + } + catch (UnknownHostException e) + { + } + return "未知"; + } + + /** + * 从多级反向代理中获得第一个非unknown IP地址 + * + * @param ip 获得的IP地址 + * @return 第一个非unknown IP地址 + */ + public static String getMultistageReverseProxyIp(String ip) + { + // 多级反向代理检测 + if (ip != null && ip.indexOf(",") > 0) + { + final String[] ips = ip.trim().split(","); + for (String subIp : ips) + { + if (false == isUnknown(subIp)) + { + ip = subIp; + break; + } + } + } + return StringUtils.substring(ip, 0, 255); + } + + /** + * 检测给定字符串是否为未知,多用于检测HTTP请求相关 + * + * @param checkString 被检测的字符串 + * @return 是否未知 + */ + public static boolean isUnknown(String checkString) + { + return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString); + } + + /** + * 是否为IP + */ + public static boolean isIP(String ip) + { + return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP); + } + + /** + * 是否为IP,或 *为间隔的通配符地址 + */ + public static boolean isIpWildCard(String ip) + { + return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD); + } + + /** + * 检测参数是否在ip通配符里 + */ + public static boolean ipIsInWildCardNoCheck(String ipWildCard, String ip) + { + String[] s1 = ipWildCard.split("\\."); + String[] s2 = ip.split("\\."); + boolean isMatchedSeg = true; + for (int i = 0; i < s1.length && !s1[i].equals("*"); i++) + { + if (!s1[i].equals(s2[i])) + { + isMatchedSeg = false; + break; + } + } + return isMatchedSeg; + } + + /** + * 是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串 + */ + public static boolean isIPSegment(String ipSeg) + { + return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG); + } + + /** + * 判断ip是否在指定网段中 + */ + public static boolean ipIsInNetNoCheck(String iparea, String ip) + { + int idx = iparea.indexOf('-'); + String[] sips = iparea.substring(0, idx).split("\\."); + String[] sipe = iparea.substring(idx + 1).split("\\."); + String[] sipt = ip.split("\\."); + long ips = 0L, ipe = 0L, ipt = 0L; + for (int i = 0; i < 4; ++i) + { + ips = ips << 8 | Integer.parseInt(sips[i]); + ipe = ipe << 8 | Integer.parseInt(sipe[i]); + ipt = ipt << 8 | Integer.parseInt(sipt[i]); + } + if (ips > ipe) + { + long t = ips; + ips = ipe; + ipe = t; + } + return ips <= ipt && ipt <= ipe; + } + + /** + * 校验ip是否符合过滤串规则 + * + * @param filter 过滤IP列表,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99` + * @param ip 校验IP地址 + * @return boolean 结果 + */ + public static boolean isMatchedIp(String filter, String ip) + { + if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip)) + { + return false; + } + String[] ips = filter.split(";"); + for (String iStr : ips) + { + if (isIP(iStr) && iStr.equals(ip)) + { + return true; + } + else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip)) + { + return true; + } + else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip)) + { + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/boyue-common/src/main/java/com/boyue/common/utils/poi/ExcelHandlerAdapter.java b/boyue-common/src/main/java/com/boyue/common/utils/poi/ExcelHandlerAdapter.java new file mode 100644 index 0000000..aef9055 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/poi/ExcelHandlerAdapter.java @@ -0,0 +1,19 @@ +package com.boyue.common.utils.poi; + +/** + * Excel数据格式处理适配器 + * + * @author boyue + */ +public interface ExcelHandlerAdapter +{ + /** + * 格式化 + * + * @param value 单元格数据值 + * @param args excel注解args参数组 + * + * @return 处理后的值 + */ + Object format(Object value, String[] args); +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/poi/ExcelUtil.java b/boyue-common/src/main/java/com/boyue/common/utils/poi/ExcelUtil.java new file mode 100644 index 0000000..0ef92c4 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/poi/ExcelUtil.java @@ -0,0 +1,1903 @@ +package com.boyue.common.utils.poi; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.RegExUtils; +import org.apache.commons.lang3.reflect.FieldUtils; +import org.apache.poi.hssf.usermodel.HSSFClientAnchor; +import org.apache.poi.hssf.usermodel.HSSFPicture; +import org.apache.poi.hssf.usermodel.HSSFPictureData; +import org.apache.poi.hssf.usermodel.HSSFShape; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ooxml.POIXMLDocumentPart; +import org.apache.poi.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.ClientAnchor; +import org.apache.poi.ss.usermodel.DataFormat; +import org.apache.poi.ss.usermodel.DataValidation; +import org.apache.poi.ss.usermodel.DataValidationConstraint; +import org.apache.poi.ss.usermodel.DataValidationHelper; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.Drawing; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.Name; +import org.apache.poi.ss.usermodel.PictureData; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.VerticalAlignment; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.util.IOUtils; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFDataValidation; +import org.apache.poi.xssf.usermodel.XSSFDrawing; +import org.apache.poi.xssf.usermodel.XSSFPicture; +import org.apache.poi.xssf.usermodel.XSSFShape; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.annotation.Excel.ColumnType; +import com.boyue.common.annotation.Excel.Type; +import com.boyue.common.annotation.Excels; +import com.boyue.common.config.BoYueConfig; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.text.Convert; +import com.boyue.common.exception.UtilException; +import com.boyue.common.utils.DateUtils; +import com.boyue.common.utils.DictUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.file.FileTypeUtils; +import com.boyue.common.utils.file.FileUtils; +import com.boyue.common.utils.file.ImageUtils; +import com.boyue.common.utils.reflect.ReflectUtils; + +import jakarta.servlet.http.HttpServletResponse; + +/** + * Excel相关处理 + * + * @author boyue + */ +public class ExcelUtil +{ + private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); + + public static final String FORMULA_REGEX_STR = "=|-|\\+|@"; + + public static final String[] FORMULA_STR = { "=", "-", "+", "@" }; + + /** + * 用于dictType属性数据存储,避免重复查缓存 + */ + public Map sysDictMap = new HashMap(); + + /** + * Excel sheet最大行数,默认65536 + */ + public static final int sheetSize = 65536; + + /** + * 工作表名称 + */ + private String sheetName; + + /** + * 导出类型(EXPORT:导出数据;IMPORT:导入模板) + */ + private Type type; + + /** + * 工作薄对象 + */ + private Workbook wb; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 样式列表 + */ + private Map styles; + + /** + * 导入导出数据列表 + */ + private List list; + + /** + * 注解列表 + */ + private List fields; + + /** + * 当前行号 + */ + private int rownum; + + /** + * 标题 + */ + private String title; + + /** + * 最大高度 + */ + private short maxHeight; + + /** + * 合并后最后行数 + */ + private int subMergedLastRowNum = 0; + + /** + * 合并后开始行数 + */ + private int subMergedFirstRowNum = 1; + + /** + * 对象的子列表方法 + */ + private Method subMethod; + + /** + * 对象的子列表属性 + */ + private List subFields; + + /** + * 统计列表 + */ + private Map statistics = new HashMap(); + + /** + * 数字格式 + */ + private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); + + /** + * 实体对象 + */ + public Class clazz; + + /** + * 需要显示列属性 + */ + public String[] includeFields; + + /** + * 需要排除列属性 + */ + public String[] excludeFields; + + public ExcelUtil(Class clazz) + { + this.clazz = clazz; + } + + /** + * 仅在Excel中显示列属性 + * + * @param fields 列属性名 示例[单个"name"/多个"id","name"] + */ + public void showColumn(String... fields) + { + this.includeFields = fields; + } + + /** + * 隐藏Excel中列属性 + * + * @param fields 列属性名 示例[单个"name"/多个"id","name"] + */ + public void hideColumn(String... fields) + { + this.excludeFields = fields; + } + + public void init(List list, String sheetName, String title, Type type) + { + if (list == null) + { + list = new ArrayList(); + } + this.list = list; + this.sheetName = sheetName; + this.type = type; + this.title = title; + createExcelField(); + createWorkbook(); + createTitle(); + createSubHead(); + } + + /** + * 创建excel第一行标题 + */ + public void createTitle() + { + if (StringUtils.isNotEmpty(title)) + { + int titleLastCol = this.fields.size() - 1; + if (isSubList()) + { + titleLastCol = titleLastCol + subFields.size() - 1; + } + Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0); + titleRow.setHeightInPoints(30); + Cell titleCell = titleRow.createCell(0); + titleCell.setCellStyle(styles.get("title")); + titleCell.setCellValue(title); + sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), 0, titleLastCol)); + } + } + + /** + * 创建对象的子列表名称 + */ + public void createSubHead() + { + if (isSubList()) + { + Row subRow = sheet.createRow(rownum); + int column = 0; + int subFieldSize = subFields != null ? subFields.size() : 0; + for (Object[] objects : fields) + { + Field field = (Field) objects[0]; + Excel attr = (Excel) objects[1]; + if (Collection.class.isAssignableFrom(field.getType())) + { + Cell cell = subRow.createCell(column); + cell.setCellValue(attr.name()); + cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); + if (subFieldSize > 1) + { + CellRangeAddress cellAddress = new CellRangeAddress(rownum, rownum, column, column + subFieldSize - 1); + sheet.addMergedRegion(cellAddress); + } + column += subFieldSize; + } + else + { + Cell cell = subRow.createCell(column++); + cell.setCellValue(attr.name()); + cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); + } + } + rownum++; + } + } + + /** + * 对excel表单默认第一个索引名转换成list + * + * @param is 输入流 + * @return 转换后集合 + */ + public List importExcel(InputStream is) + { + List list = null; + try + { + list = importExcel(is, 0); + } + catch (Exception e) + { + log.error("导入Excel异常{}", e.getMessage()); + throw new UtilException(e.getMessage()); + } + finally + { + IOUtils.closeQuietly(is); + } + return list; + } + + /** + * 对excel表单默认第一个索引名转换成list + * + * @param is 输入流 + * @param titleNum 标题占用行数 + * @return 转换后集合 + */ + public List importExcel(InputStream is, int titleNum) throws Exception + { + return importExcel(StringUtils.EMPTY, is, titleNum); + } + + /** + * 对excel表单指定表格索引名转换成list + * + * @param sheetName 表格索引名 + * @param titleNum 标题占用行数 + * @param is 输入流 + * @return 转换后集合 + */ + public List importExcel(String sheetName, InputStream is, int titleNum) throws Exception + { + this.type = Type.IMPORT; + this.wb = WorkbookFactory.create(is); + List list = new ArrayList(); + // 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet + Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0); + if (sheet == null) + { + throw new IOException("文件sheet不存在"); + } + boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook); + Map pictures; + if (isXSSFWorkbook) + { + pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb); + } + else + { + pictures = getSheetPictures03((HSSFSheet) sheet, (HSSFWorkbook) wb); + } + // 获取最后一个非空行的行下标,比如总行数为n,则返回的为n-1 + int rows = sheet.getLastRowNum(); + if (rows > 0) + { + // 定义一个map用于存放excel列的序号和field. + Map cellMap = new HashMap(); + // 获取表头 + Row heard = sheet.getRow(titleNum); + for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) + { + Cell cell = heard.getCell(i); + if (StringUtils.isNotNull(cell)) + { + String value = this.getCellValue(heard, i).toString(); + cellMap.put(value, i); + } + else + { + cellMap.put(null, i); + } + } + // 有数据时才处理 得到类的所有field. + List fields = this.getFields(); + Map fieldsMap = new HashMap(); + for (Object[] objects : fields) + { + Excel attr = (Excel) objects[1]; + Integer column = cellMap.get(attr.name()); + if (column != null) + { + fieldsMap.put(column, objects); + } + } + for (int i = titleNum + 1; i <= rows; i++) + { + // 从第2行开始取数据,默认第一行是表头. + Row row = sheet.getRow(i); + // 判断当前行是否是空行 + if (isRowEmpty(row)) + { + continue; + } + T entity = null; + for (Map.Entry entry : fieldsMap.entrySet()) + { + Object val = this.getCellValue(row, entry.getKey()); + + // 如果不存在实例则新建. + entity = (entity == null ? clazz.getDeclaredConstructor().newInstance() : entity); + // 从map中得到对应列的field. + Field field = (Field) entry.getValue()[0]; + Excel attr = (Excel) entry.getValue()[1]; + // 取得类型,并根据对象类型设置值. + Class fieldType = field.getType(); + if (String.class == fieldType) + { + String s = Convert.toStr(val); + if (StringUtils.endsWith(s, ".0")) + { + val = StringUtils.substringBefore(s, ".0"); + } + else + { + String dateFormat = field.getAnnotation(Excel.class).dateFormat(); + if (StringUtils.isNotEmpty(dateFormat)) + { + val = parseDateToStr(dateFormat, val); + } + else + { + val = Convert.toStr(val); + } + } + } + else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) + { + val = Convert.toInt(val); + } + else if ((Long.TYPE == fieldType || Long.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) + { + val = Convert.toLong(val); + } + else if (Double.TYPE == fieldType || Double.class == fieldType) + { + val = Convert.toDouble(val); + } + else if (Float.TYPE == fieldType || Float.class == fieldType) + { + val = Convert.toFloat(val); + } + else if (BigDecimal.class == fieldType) + { + val = Convert.toBigDecimal(val); + } + else if (Date.class == fieldType) + { + if (val instanceof String) + { + val = DateUtils.parseDate(val); + } + else if (val instanceof Double) + { + val = DateUtil.getJavaDate((Double) val); + } + } + else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) + { + val = Convert.toBool(val, false); + } + if (StringUtils.isNotNull(fieldType)) + { + String propertyName = field.getName(); + if (StringUtils.isNotEmpty(attr.targetAttr())) + { + propertyName = field.getName() + "." + attr.targetAttr(); + } + if (StringUtils.isNotEmpty(attr.readConverterExp())) + { + val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); + } + else if (StringUtils.isNotEmpty(attr.dictType())) + { + if (!sysDictMap.containsKey(attr.dictType() + val)) + { + String dictValue = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator()); + sysDictMap.put(attr.dictType() + val, dictValue); + } + val = sysDictMap.get(attr.dictType() + val); + } + else if (!attr.handler().equals(ExcelHandlerAdapter.class)) + { + val = dataFormatHandlerAdapter(val, attr, null); + } + else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures)) + { + PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey()); + if (image == null) + { + val = ""; + } + else + { + byte[] data = image.getData(); + val = FileUtils.writeImportBytes(data); + } + } + ReflectUtils.invokeSetter(entity, propertyName, val); + } + } + list.add(entity); + } + } + return list; + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @return 结果 + */ + public AjaxResult exportExcel(List list, String sheetName) + { + return exportExcel(list, sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public AjaxResult exportExcel(List list, String sheetName, String title) + { + this.init(list, sheetName, title, Type.EXPORT); + return exportExcel(); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param response 返回数据 + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @return 结果 + */ + public void exportExcel(HttpServletResponse response, List list, String sheetName) + { + exportExcel(response, list, sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param response 返回数据 + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public void exportExcel(HttpServletResponse response, List list, String sheetName, String title) + { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + this.init(list, sheetName, title, Type.EXPORT); + exportExcel(response); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @return 结果 + */ + public AjaxResult importTemplateExcel(String sheetName) + { + return importTemplateExcel(sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public AjaxResult importTemplateExcel(String sheetName, String title) + { + this.init(null, sheetName, title, Type.IMPORT); + return exportExcel(); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @return 结果 + */ + public void importTemplateExcel(HttpServletResponse response, String sheetName) + { + importTemplateExcel(response, sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public void importTemplateExcel(HttpServletResponse response, String sheetName, String title) + { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + this.init(null, sheetName, title, Type.IMPORT); + exportExcel(response); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @return 结果 + */ + public void exportExcel(HttpServletResponse response) + { + try + { + writeSheet(); + wb.write(response.getOutputStream()); + } + catch (Exception e) + { + log.error("导出Excel异常{}", e.getMessage()); + } + finally + { + IOUtils.closeQuietly(wb); + } + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @return 结果 + */ + public AjaxResult exportExcel() + { + OutputStream out = null; + try + { + writeSheet(); + String filename = encodingFilename(sheetName); + out = new FileOutputStream(getAbsoluteFile(filename)); + wb.write(out); + return AjaxResult.success(filename); + } + catch (Exception e) + { + log.error("导出Excel异常{}", e.getMessage()); + throw new UtilException("导出Excel失败,请联系网站管理员!"); + } + finally + { + IOUtils.closeQuietly(wb); + IOUtils.closeQuietly(out); + } + } + + /** + * 创建写入数据到Sheet + */ + public void writeSheet() + { + // 取出一共有多少个sheet. + int sheetNo = Math.max(1, (int) Math.ceil(list.size() * 1.0 / sheetSize)); + for (int index = 0; index < sheetNo; index++) + { + createSheet(sheetNo, index); + + // 产生一行 + Row row = sheet.createRow(rownum); + int column = 0; + // 写入各个字段的列头名称 + for (Object[] os : fields) + { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + if (Collection.class.isAssignableFrom(field.getType())) + { + for (Field subField : subFields) + { + Excel subExcel = subField.getAnnotation(Excel.class); + this.createHeadCell(subExcel, row, column++); + } + } + else + { + this.createHeadCell(excel, row, column++); + } + } + if (Type.EXPORT.equals(type)) + { + fillExcelData(index, row); + addStatisticsRow(); + } + } + } + + /** + * 填充excel数据 + * + * @param index 序号 + * @param row 单元格行 + */ + @SuppressWarnings("unchecked") + public void fillExcelData(int index, Row row) + { + int startNo = index * sheetSize; + int endNo = Math.min(startNo + sheetSize, list.size()); + int currentRowNum = rownum + 1; // 从标题行后开始 + + for (int i = startNo; i < endNo; i++) + { + row = sheet.createRow(currentRowNum); + T vo = (T) list.get(i); + int column = 0; + int maxSubListSize = getCurrentMaxSubListSize(vo); + for (Object[] os : fields) + { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + if (Collection.class.isAssignableFrom(field.getType())) + { + try + { + Collection subList = (Collection) getTargetValue(vo, field, excel); + if (subList != null && !subList.isEmpty()) + { + int subIndex = 0; + for (Object subVo : subList) + { + Row subRow = sheet.getRow(currentRowNum + subIndex); + if (subRow == null) + { + subRow = sheet.createRow(currentRowNum + subIndex); + } + + int subColumn = column; + for (Field subField : subFields) + { + Excel subExcel = subField.getAnnotation(Excel.class); + addCell(subExcel, subRow, (T) subVo, subField, subColumn++); + } + subIndex++; + } + column += subFields.size(); + } + } + catch (Exception e) + { + log.error("填充集合数据失败", e); + } + } + else + { + // 创建单元格并设置值 + addCell(excel, row, vo, field, column); + if (maxSubListSize > 1 && excel.needMerge()) + { + sheet.addMergedRegion(new CellRangeAddress(currentRowNum, currentRowNum + maxSubListSize - 1, column, column)); + } + column++; + } + } + currentRowNum += maxSubListSize; + } + } + + /** + * 获取子列表最大数 + */ + private int getCurrentMaxSubListSize(T vo) + { + int maxSubListSize = 1; + for (Object[] os : fields) + { + Field field = (Field) os[0]; + if (Collection.class.isAssignableFrom(field.getType())) + { + try + { + Collection subList = (Collection) getTargetValue(vo, field, (Excel) os[1]); + if (subList != null && !subList.isEmpty()) + { + maxSubListSize = Math.max(maxSubListSize, subList.size()); + } + } + catch (Exception e) + { + log.error("获取集合大小失败", e); + } + } + } + return maxSubListSize; + } + + /** + * 创建表格样式 + * + * @param wb 工作薄对象 + * @return 样式列表 + */ + private Map createStyles(Workbook wb) + { + // 写入各条记录,每条记录对应excel表中的一行 + Map styles = new HashMap(); + CellStyle style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font titleFont = wb.createFont(); + titleFont.setFontName("Arial"); + titleFont.setFontHeightInPoints((short) 16); + titleFont.setBold(true); + style.setFont(titleFont); + DataFormat dataFormat = wb.createDataFormat(); + style.setDataFormat(dataFormat.getFormat("@")); + styles.put("title", style); + + style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + style.setFont(dataFont); + styles.put("data", style); + + style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font totalFont = wb.createFont(); + totalFont.setFontName("Arial"); + totalFont.setFontHeightInPoints((short) 10); + style.setFont(totalFont); + styles.put("total", style); + + styles.putAll(annotationHeaderStyles(wb, styles)); + + styles.putAll(annotationDataStyles(wb)); + + return styles; + } + + /** + * 根据Excel注解创建表格头样式 + * + * @param wb 工作薄对象 + * @return 自定义样式列表 + */ + private Map annotationHeaderStyles(Workbook wb, Map styles) + { + Map headerStyles = new HashMap(); + for (Object[] os : fields) + { + Excel excel = (Excel) os[1]; + String key = StringUtils.format("header_{}_{}", excel.headerColor(), excel.headerBackgroundColor()); + if (!headerStyles.containsKey(key)) + { + CellStyle style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setFillForegroundColor(excel.headerBackgroundColor().index); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + Font headerFont = wb.createFont(); + headerFont.setFontName("Arial"); + headerFont.setFontHeightInPoints((short) 10); + headerFont.setBold(true); + headerFont.setColor(excel.headerColor().index); + style.setFont(headerFont); + // 设置表格头单元格文本形式 + DataFormat dataFormat = wb.createDataFormat(); + style.setDataFormat(dataFormat.getFormat("@")); + headerStyles.put(key, style); + } + } + return headerStyles; + } + + /** + * 根据Excel注解创建表格列样式 + * + * @param wb 工作薄对象 + * @return 自定义样式列表 + */ + private Map annotationDataStyles(Workbook wb) + { + Map styles = new HashMap(); + for (Object[] os : fields) + { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + if (Collection.class.isAssignableFrom(field.getType())) + { + ParameterizedType pt = (ParameterizedType) field.getGenericType(); + Class subClass = (Class) pt.getActualTypeArguments()[0]; + List subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class); + for (Field subField : subFields) + { + Excel subExcel = subField.getAnnotation(Excel.class); + annotationDataStyles(styles, subField, subExcel); + } + } + else + { + annotationDataStyles(styles, field, excel); + } + } + return styles; + } + + /** + * 根据Excel注解创建表格列样式 + * + * @param styles 自定义样式列表 + * @param field 属性列信息 + * @param excel 注解信息 + */ + public void annotationDataStyles(Map styles, Field field, Excel excel) + { + String key = StringUtils.format("data_{}_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType()); + if (!styles.containsKey(key)) + { + CellStyle style = wb.createCellStyle(); + style.setAlignment(excel.align()); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setFillForegroundColor(excel.backgroundColor().getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + dataFont.setColor(excel.color().index); + style.setFont(dataFont); + if (ColumnType.TEXT == excel.cellType()) + { + DataFormat dataFormat = wb.createDataFormat(); + style.setDataFormat(dataFormat.getFormat("@")); + } + styles.put(key, style); + } + } + + /** + * 创建单元格 + */ + public Cell createHeadCell(Excel attr, Row row, int column) + { + // 创建列 + Cell cell = row.createCell(column); + // 写入列信息 + cell.setCellValue(attr.name()); + setDataValidation(attr, row, column); + cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); + if (isSubList()) + { + // 填充默认样式,防止合并单元格样式失效 + sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType()))); + if (attr.needMerge()) + { + sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column)); + } + } + return cell; + } + + /** + * 设置单元格信息 + * + * @param value 单元格值 + * @param attr 注解相关 + * @param cell 单元格信息 + */ + public void setCellVo(Object value, Excel attr, Cell cell) + { + if (ColumnType.STRING == attr.cellType() || ColumnType.TEXT == attr.cellType()) + { + String cellValue = Convert.toStr(value); + // 对于任何以表达式触发字符 =-+@开头的单元格,直接使用tab字符作为前缀,防止CSV注入。 + if (StringUtils.startsWithAny(cellValue, FORMULA_STR)) + { + cellValue = RegExUtils.replaceFirst(cellValue, FORMULA_REGEX_STR, "\t$0"); + } + if (value instanceof Collection && StringUtils.equals("[]", cellValue)) + { + cellValue = StringUtils.EMPTY; + } + cell.setCellValue(StringUtils.isNull(cellValue) ? attr.defaultValue() : cellValue + attr.suffix()); + } + else if (ColumnType.NUMERIC == attr.cellType()) + { + if (StringUtils.isNotNull(value)) + { + cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); + } + } + else if (ColumnType.IMAGE == attr.cellType()) + { + ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1); + String imagePath = Convert.toStr(value); + if (StringUtils.isNotEmpty(imagePath)) + { + byte[] data = ImageUtils.getImage(imagePath); + getDrawingPatriarch(cell.getSheet()).createPicture(anchor, + cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); + } + } + } + + /** + * 获取画布 + */ + public static Drawing getDrawingPatriarch(Sheet sheet) + { + if (sheet.getDrawingPatriarch() == null) + { + sheet.createDrawingPatriarch(); + } + return sheet.getDrawingPatriarch(); + } + + /** + * 获取图片类型,设置图片插入类型 + */ + public int getImageType(byte[] value) + { + String type = FileTypeUtils.getFileExtendName(value); + if ("JPG".equalsIgnoreCase(type)) + { + return Workbook.PICTURE_TYPE_JPEG; + } + else if ("PNG".equalsIgnoreCase(type)) + { + return Workbook.PICTURE_TYPE_PNG; + } + return Workbook.PICTURE_TYPE_JPEG; + } + + /** + * 创建表格样式 + */ + public void setDataValidation(Excel attr, Row row, int column) + { + if (attr.name().indexOf("注:") >= 0) + { + sheet.setColumnWidth(column, 6000); + } + else + { + // 设置列宽 + sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); + } + if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0 || attr.comboReadDict()) + { + String[] comboArray = attr.combo(); + if (attr.comboReadDict()) + { + if (!sysDictMap.containsKey("combo_" + attr.dictType())) + { + String labels = DictUtils.getDictLabels(attr.dictType()); + sysDictMap.put("combo_" + attr.dictType(), labels); + } + String val = sysDictMap.get("combo_" + attr.dictType()); + comboArray = StringUtils.split(val, DictUtils.SEPARATOR); + } + if (comboArray.length > 15 || StringUtils.join(comboArray).length() > 255) + { + // 如果下拉数大于15或字符串长度大于255,则使用一个新sheet存储,避免生成的模板下拉值获取不到 + setXSSFValidationWithHidden(sheet, comboArray, attr.prompt(), 1, 100, column, column); + } + else + { + // 提示信息或只能选择不能输入的列内容. + setPromptOrValidation(sheet, comboArray, attr.prompt(), 1, 100, column, column); + } + } + } + + /** + * 添加单元格 + */ + public Cell addCell(Excel attr, Row row, T vo, Field field, int column) + { + Cell cell = null; + try + { + // 设置行高 + row.setHeight(maxHeight); + // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. + if (attr.isExport()) + { + // 创建cell + cell = row.createCell(column); + if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge()) + { + if (subMergedLastRowNum >= subMergedFirstRowNum) + { + sheet.addMergedRegion(new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column)); + } + } + cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType()))); + + // 用于读取对象中的属性 + Object value = getTargetValue(vo, field, attr); + String dateFormat = attr.dateFormat(); + String readConverterExp = attr.readConverterExp(); + String separator = attr.separator(); + String dictType = attr.dictType(); + if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) + { + cell.getCellStyle().setDataFormat(this.wb.getCreationHelper().createDataFormat().getFormat(dateFormat)); + cell.setCellValue(parseDateToStr(dateFormat, value)); + } + else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) + { + cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); + } + else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value)) + { + if (!sysDictMap.containsKey(dictType + value)) + { + String lable = convertDictByExp(Convert.toStr(value), dictType, separator); + sysDictMap.put(dictType + value, lable); + } + cell.setCellValue(sysDictMap.get(dictType + value)); + } + else if (value instanceof BigDecimal && -1 != attr.scale()) + { + cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).doubleValue()); + } + else if (!attr.handler().equals(ExcelHandlerAdapter.class)) + { + cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell)); + } + else + { + // 设置列类型 + setCellVo(value, attr, cell); + } + addStatisticsData(column, Convert.toStr(value), attr); + } + } + catch (Exception e) + { + log.error("导出Excel失败{}", e); + } + return cell; + } + + /** + * 设置 POI XSSFSheet 单元格提示或选择框 + * + * @param sheet 表单 + * @param textlist 下拉框显示的内容 + * @param promptContent 提示内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + */ + public void setPromptOrValidation(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, + int firstCol, int endCol) + { + DataValidationHelper helper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = textlist.length > 0 ? helper.createExplicitListConstraint(textlist) : helper.createCustomConstraint("DD1"); + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + DataValidation dataValidation = helper.createValidation(constraint, regions); + if (StringUtils.isNotEmpty(promptContent)) + { + // 如果设置了提示信息则鼠标放上去提示 + dataValidation.createPromptBox("", promptContent); + dataValidation.setShowPromptBox(true); + } + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) + { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } + else + { + dataValidation.setSuppressDropDownArrow(false); + } + sheet.addValidationData(dataValidation); + } + + /** + * 设置某些列的值只能输入预制的数据,显示下拉框(兼容超出一定数量的下拉框). + * + * @param sheet 要设置的sheet. + * @param textlist 下拉框显示的内容 + * @param promptContent 提示内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + */ + public void setXSSFValidationWithHidden(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, int firstCol, int endCol) + { + String hideSheetName = "combo_" + firstCol + "_" + endCol; + Sheet hideSheet = wb.createSheet(hideSheetName); // 用于存储 下拉菜单数据 + for (int i = 0; i < textlist.length; i++) + { + hideSheet.createRow(i).createCell(0).setCellValue(textlist[i]); + } + // 创建名称,可被其他单元格引用 + Name name = wb.createName(); + name.setNameName(hideSheetName + "_data"); + name.setRefersToFormula(hideSheetName + "!$A$1:$A$" + textlist.length); + DataValidationHelper helper = sheet.getDataValidationHelper(); + // 加载下拉列表内容 + DataValidationConstraint constraint = helper.createFormulaListConstraint(hideSheetName + "_data"); + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + // 数据有效性对象 + DataValidation dataValidation = helper.createValidation(constraint, regions); + if (StringUtils.isNotEmpty(promptContent)) + { + // 如果设置了提示信息则鼠标放上去提示 + dataValidation.createPromptBox("", promptContent); + dataValidation.setShowPromptBox(true); + } + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) + { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } + else + { + dataValidation.setSuppressDropDownArrow(false); + } + + sheet.addValidationData(dataValidation); + // 设置hiddenSheet隐藏 + wb.setSheetHidden(wb.getSheetIndex(hideSheet), true); + } + + /** + * 解析导出值 0=男,1=女,2=未知 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String convertByExp(String propertyValue, String converterExp, String separator) + { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(","); + for (String item : convertSource) + { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(propertyValue, separator)) + { + for (String value : propertyValue.split(separator)) + { + if (itemArray[0].equals(value)) + { + propertyString.append(itemArray[1] + separator); + break; + } + } + } + else + { + if (itemArray[0].equals(propertyValue)) + { + return itemArray[1]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 反向解析值 男=0,女=1,未知=2 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String reverseByExp(String propertyValue, String converterExp, String separator) + { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(","); + for (String item : convertSource) + { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(propertyValue, separator)) + { + for (String value : propertyValue.split(separator)) + { + if (itemArray[1].equals(value)) + { + propertyString.append(itemArray[0] + separator); + break; + } + } + } + else + { + if (itemArray[1].equals(propertyValue)) + { + return itemArray[0]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 解析字典值 + * + * @param dictValue 字典值 + * @param dictType 字典类型 + * @param separator 分隔符 + * @return 字典标签 + */ + public static String convertDictByExp(String dictValue, String dictType, String separator) + { + return DictUtils.getDictLabel(dictType, dictValue, separator); + } + + /** + * 反向解析值字典值 + * + * @param dictLabel 字典标签 + * @param dictType 字典类型 + * @param separator 分隔符 + * @return 字典值 + */ + public static String reverseDictByExp(String dictLabel, String dictType, String separator) + { + return DictUtils.getDictValue(dictType, dictLabel, separator); + } + + /** + * 数据处理器 + * + * @param value 数据值 + * @param excel 数据注解 + * @return + */ + public String dataFormatHandlerAdapter(Object value, Excel excel, Cell cell) + { + try + { + Object instance = excel.handler().getDeclaredConstructor().newInstance(); + Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class, Cell.class, Workbook.class }); + value = formatMethod.invoke(instance, value, excel.args(), cell, this.wb); + } + catch (Exception e) + { + log.error("不能格式化数据 " + excel.handler(), e.getMessage()); + } + return Convert.toStr(value); + } + + /** + * 合计统计信息 + */ + private void addStatisticsData(Integer index, String text, Excel entity) + { + if (entity != null && entity.isStatistics()) + { + Double temp = 0D; + if (!statistics.containsKey(index)) + { + statistics.put(index, temp); + } + try + { + temp = Double.valueOf(text); + } + catch (NumberFormatException e) + { + } + statistics.put(index, statistics.get(index) + temp); + } + } + + /** + * 创建统计行 + */ + public void addStatisticsRow() + { + if (statistics.size() > 0) + { + Row row = sheet.createRow(sheet.getLastRowNum() + 1); + Set keys = statistics.keySet(); + Cell cell = row.createCell(0); + cell.setCellStyle(styles.get("total")); + cell.setCellValue("合计"); + + for (Integer key : keys) + { + cell = row.createCell(key); + cell.setCellStyle(styles.get("total")); + cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key))); + } + statistics.clear(); + } + } + + /** + * 编码文件名 + */ + public String encodingFilename(String filename) + { + filename = UUID.randomUUID() + "_" + filename + ".xlsx"; + return filename; + } + + /** + * 获取下载路径 + * + * @param filename 文件名称 + */ + public String getAbsoluteFile(String filename) + { + String downloadPath = BoYueConfig.getDownloadPath() + filename; + File desc = new File(downloadPath); + if (!desc.getParentFile().exists()) + { + desc.getParentFile().mkdirs(); + } + return downloadPath; + } + + /** + * 获取bean中的属性值 + * + * @param vo 实体对象 + * @param field 字段 + * @param excel 注解 + * @return 最终的属性值 + * @throws Exception + */ + private Object getTargetValue(T vo, Field field, Excel excel) throws Exception + { + field.setAccessible(true); + Object o = field.get(vo); + if (StringUtils.isNotEmpty(excel.targetAttr())) + { + String target = excel.targetAttr(); + if (target.contains(".")) + { + String[] targets = target.split("[.]"); + for (String name : targets) + { + o = getValue(o, name); + } + } + else + { + o = getValue(o, target); + } + } + return o; + } + + /** + * 以类的属性的get方法方法形式获取值 + * + * @param o + * @param name + * @return value + * @throws Exception + */ + private Object getValue(Object o, String name) throws Exception + { + if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name)) + { + Class clazz = o.getClass(); + Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + o = field.get(o); + } + return o; + } + + /** + * 得到所有定义字段 + */ + private void createExcelField() + { + this.fields = getFields(); + this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); + this.maxHeight = getRowHeight(); + } + + /** + * 获取字段注解信息 + */ + public List getFields() + { + List fields = new ArrayList(); + List tempFields = new ArrayList<>(); + tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); + tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); + if (StringUtils.isNotEmpty(includeFields)) + { + for (Field field : tempFields) + { + if (ArrayUtils.contains(this.includeFields, field.getName()) || field.isAnnotationPresent(Excels.class)) + { + addField(fields, field); + } + } + } + else if (StringUtils.isNotEmpty(excludeFields)) + { + for (Field field : tempFields) + { + if (!ArrayUtils.contains(this.excludeFields, field.getName())) + { + addField(fields, field); + } + } + } + else + { + for (Field field : tempFields) + { + addField(fields, field); + } + } + return fields; + } + + /** + * 添加字段信息 + */ + public void addField(List fields, Field field) + { + // 单注解 + if (field.isAnnotationPresent(Excel.class)) + { + Excel attr = field.getAnnotation(Excel.class); + if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) + { + fields.add(new Object[] { field, attr }); + } + if (Collection.class.isAssignableFrom(field.getType())) + { + subMethod = getSubMethod(field.getName(), clazz); + ParameterizedType pt = (ParameterizedType) field.getGenericType(); + Class subClass = (Class) pt.getActualTypeArguments()[0]; + this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class); + } + } + + // 多注解 + if (field.isAnnotationPresent(Excels.class)) + { + Excels attrs = field.getAnnotation(Excels.class); + Excel[] excels = attrs.value(); + for (Excel attr : excels) + { + if (StringUtils.isNotEmpty(includeFields)) + { + if (ArrayUtils.contains(this.includeFields, field.getName() + "." + attr.targetAttr()) + && (attr != null && (attr.type() == Type.ALL || attr.type() == type))) + { + fields.add(new Object[] { field, attr }); + } + } + else + { + if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr()) + && (attr != null && (attr.type() == Type.ALL || attr.type() == type))) + { + fields.add(new Object[] { field, attr }); + } + } + } + } + } + + /** + * 根据注解获取最大行高 + */ + public short getRowHeight() + { + double maxHeight = 0; + for (Object[] os : this.fields) + { + Excel excel = (Excel) os[1]; + maxHeight = Math.max(maxHeight, excel.height()); + } + return (short) (maxHeight * 20); + } + + /** + * 创建一个工作簿 + */ + public void createWorkbook() + { + this.wb = new SXSSFWorkbook(500); + this.sheet = wb.createSheet(); + wb.setSheetName(0, sheetName); + this.styles = createStyles(wb); + } + + /** + * 创建工作表 + * + * @param sheetNo sheet数量 + * @param index 序号 + */ + public void createSheet(int sheetNo, int index) + { + // 设置工作表的名称. + if (sheetNo > 1 && index > 0) + { + this.sheet = wb.createSheet(); + this.createTitle(); + wb.setSheetName(index, sheetName + index); + } + } + + /** + * 获取单元格值 + * + * @param row 获取的行 + * @param column 获取单元格列号 + * @return 单元格值 + */ + public Object getCellValue(Row row, int column) + { + if (row == null) + { + return row; + } + Object val = ""; + try + { + Cell cell = row.getCell(column); + if (StringUtils.isNotNull(cell)) + { + if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA) + { + val = cell.getNumericCellValue(); + if (DateUtil.isCellDateFormatted(cell)) + { + val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换 + } + else + { + if ((Double) val % 1 != 0) + { + val = new BigDecimal(val.toString()); + } + else + { + val = new DecimalFormat("0").format(val); + } + } + } + else if (cell.getCellType() == CellType.STRING) + { + val = cell.getStringCellValue(); + } + else if (cell.getCellType() == CellType.BOOLEAN) + { + val = cell.getBooleanCellValue(); + } + else if (cell.getCellType() == CellType.ERROR) + { + val = cell.getErrorCellValue(); + } + + } + } + catch (Exception e) + { + return val; + } + return val; + } + + /** + * 判断是否是空行 + * + * @param row 判断的行 + * @return + */ + private boolean isRowEmpty(Row row) + { + if (row == null) + { + return true; + } + for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) + { + Cell cell = row.getCell(i); + if (cell != null && cell.getCellType() != CellType.BLANK) + { + return false; + } + } + return true; + } + + /** + * 获取Excel2003图片 + * + * @param sheet 当前sheet对象 + * @param workbook 工作簿对象 + * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData + */ + public static Map getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook) + { + Map sheetIndexPicMap = new HashMap(); + List pictures = workbook.getAllPictures(); + if (!pictures.isEmpty()) + { + for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren()) + { + HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor(); + if (shape instanceof HSSFPicture) + { + HSSFPicture pic = (HSSFPicture) shape; + int pictureIndex = pic.getPictureIndex() - 1; + HSSFPictureData picData = pictures.get(pictureIndex); + String picIndex = anchor.getRow1() + "_" + anchor.getCol1(); + sheetIndexPicMap.put(picIndex, picData); + } + } + return sheetIndexPicMap; + } + else + { + return sheetIndexPicMap; + } + } + + /** + * 获取Excel2007图片 + * + * @param sheet 当前sheet对象 + * @param workbook 工作簿对象 + * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData + */ + public static Map getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook) + { + Map sheetIndexPicMap = new HashMap(); + for (POIXMLDocumentPart dr : sheet.getRelations()) + { + if (dr instanceof XSSFDrawing) + { + XSSFDrawing drawing = (XSSFDrawing) dr; + List shapes = drawing.getShapes(); + for (XSSFShape shape : shapes) + { + if (shape instanceof XSSFPicture) + { + XSSFPicture pic = (XSSFPicture) shape; + XSSFClientAnchor anchor = pic.getPreferredSize(); + CTMarker ctMarker = anchor.getFrom(); + String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol(); + sheetIndexPicMap.put(picIndex, pic.getPictureData()); + } + } + } + } + return sheetIndexPicMap; + } + + /** + * 格式化不同类型的日期对象 + * + * @param dateFormat 日期格式 + * @param val 被格式化的日期对象 + * @return 格式化后的日期字符 + */ + public String parseDateToStr(String dateFormat, Object val) + { + if (val == null) + { + return ""; + } + String str; + if (val instanceof Date) + { + str = DateUtils.parseDateToStr(dateFormat, (Date) val); + } + else if (val instanceof LocalDateTime) + { + str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDateTime) val)); + } + else if (val instanceof LocalDate) + { + str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDate) val)); + } + else + { + str = val.toString(); + } + return str; + } + + /** + * 是否有对象的子列表 + */ + public boolean isSubList() + { + return StringUtils.isNotNull(subFields) && subFields.size() > 0; + } + + /** + * 是否有对象的子列表,集合不为空 + */ + public boolean isSubListValue(T vo) + { + return StringUtils.isNotNull(subFields) && subFields.size() > 0 && StringUtils.isNotNull(getListCellValue(vo)) && getListCellValue(vo).size() > 0; + } + + /** + * 获取集合的值 + */ + public Collection getListCellValue(Object obj) + { + Object value; + try + { + value = subMethod.invoke(obj, new Object[] {}); + } + catch (Exception e) + { + return new ArrayList(); + } + return (Collection) value; + } + + /** + * 获取对象的子列表方法 + * + * @param name 名称 + * @param pojoClass 类对象 + * @return 子列表方法 + */ + public Method getSubMethod(String name, Class pojoClass) + { + StringBuffer getMethodName = new StringBuffer("get"); + getMethodName.append(name.substring(0, 1).toUpperCase()); + getMethodName.append(name.substring(1)); + Method method = null; + try + { + method = pojoClass.getMethod(getMethodName.toString(), new Class[] {}); + } + catch (Exception e) + { + log.error("获取对象异常{}", e.getMessage()); + } + return method; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/reflect/ReflectUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/reflect/ReflectUtils.java new file mode 100644 index 0000000..1a067de --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/reflect/ReflectUtils.java @@ -0,0 +1,410 @@ +package com.boyue.common.utils.reflect; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Date; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.apache.poi.ss.usermodel.DateUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.boyue.common.core.text.Convert; +import com.boyue.common.utils.DateUtils; + +/** + * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. + * + * @author boyue + */ +@SuppressWarnings("rawtypes") +public class ReflectUtils +{ + private static final String SETTER_PREFIX = "set"; + + private static final String GETTER_PREFIX = "get"; + + private static final String CGLIB_CLASS_SEPARATOR = "$$"; + + private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class); + + /** + * 调用Getter方法. + * 支持多级,如:对象名.对象名.方法 + */ + @SuppressWarnings("unchecked") + public static E invokeGetter(Object obj, String propertyName) + { + Object object = obj; + for (String name : StringUtils.split(propertyName, ".")) + { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); + object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); + } + return (E) object; + } + + /** + * 调用Setter方法, 仅匹配方法名。 + * 支持多级,如:对象名.对象名.方法 + */ + public static void invokeSetter(Object obj, String propertyName, E value) + { + Object object = obj; + String[] names = StringUtils.split(propertyName, "."); + for (int i = 0; i < names.length; i++) + { + if (i < names.length - 1) + { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); + object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); + } + else + { + String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); + invokeMethodByName(object, setterMethodName, new Object[] { value }); + } + } + } + + /** + * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数. + */ + @SuppressWarnings("unchecked") + public static E getFieldValue(final Object obj, final String fieldName) + { + Field field = getAccessibleField(obj, fieldName); + if (field == null) + { + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + return null; + } + E result = null; + try + { + result = (E) field.get(obj); + } + catch (IllegalAccessException e) + { + logger.error("不可能抛出的异常{}", e.getMessage()); + } + return result; + } + + /** + * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数. + */ + public static void setFieldValue(final Object obj, final String fieldName, final E value) + { + Field field = getAccessibleField(obj, fieldName); + if (field == null) + { + // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + return; + } + try + { + field.set(obj, value); + } + catch (IllegalAccessException e) + { + logger.error("不可能抛出的异常: {}", e.getMessage()); + } + } + + /** + * 直接调用对象方法, 无视private/protected修饰符. + * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用. + * 同时匹配方法名+参数类型, + */ + @SuppressWarnings("unchecked") + public static E invokeMethod(final Object obj, final String methodName, final Class[] parameterTypes, + final Object[] args) + { + if (obj == null || methodName == null) + { + return null; + } + Method method = getAccessibleMethod(obj, methodName, parameterTypes); + if (method == null) + { + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 "); + return null; + } + try + { + return (E) method.invoke(obj, args); + } + catch (Exception e) + { + String msg = "method: " + method + ", obj: " + obj + ", args: " + args + ""; + throw convertReflectionExceptionToUnchecked(msg, e); + } + } + + /** + * 直接调用对象方法, 无视private/protected修饰符, + * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用. + * 只匹配函数名,如果有多个同名函数调用第一个。 + */ + @SuppressWarnings("unchecked") + public static E invokeMethodByName(final Object obj, final String methodName, final Object[] args) + { + Method method = getAccessibleMethodByName(obj, methodName, args.length); + if (method == null) + { + // 如果为空不报错,直接返回空。 + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 "); + return null; + } + try + { + // 类型转换(将参数数据类型转换为目标方法参数类型) + Class[] cs = method.getParameterTypes(); + for (int i = 0; i < cs.length; i++) + { + if (args[i] != null && !args[i].getClass().equals(cs[i])) + { + if (cs[i] == String.class) + { + args[i] = Convert.toStr(args[i]); + if (StringUtils.endsWith((String) args[i], ".0")) + { + args[i] = StringUtils.substringBefore((String) args[i], ".0"); + } + } + else if (cs[i] == Integer.class) + { + args[i] = Convert.toInt(args[i]); + } + else if (cs[i] == Long.class) + { + args[i] = Convert.toLong(args[i]); + } + else if (cs[i] == Double.class) + { + args[i] = Convert.toDouble(args[i]); + } + else if (cs[i] == Float.class) + { + args[i] = Convert.toFloat(args[i]); + } + else if (cs[i] == Date.class) + { + if (args[i] instanceof String) + { + args[i] = DateUtils.parseDate(args[i]); + } + else + { + args[i] = DateUtil.getJavaDate((Double) args[i]); + } + } + else if (cs[i] == boolean.class || cs[i] == Boolean.class) + { + args[i] = Convert.toBool(args[i]); + } + } + } + return (E) method.invoke(obj, args); + } + catch (Exception e) + { + String msg = "method: " + method + ", obj: " + obj + ", args: " + args + ""; + throw convertReflectionExceptionToUnchecked(msg, e); + } + } + + /** + * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + */ + public static Field getAccessibleField(final Object obj, final String fieldName) + { + // 为空不报错。直接返回 null + if (obj == null) + { + return null; + } + Validate.notBlank(fieldName, "fieldName can't be blank"); + for (Class superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) + { + try + { + Field field = superClass.getDeclaredField(fieldName); + makeAccessible(field); + return field; + } + catch (NoSuchFieldException e) + { + continue; + } + } + return null; + } + + /** + * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + * 匹配函数名+参数类型。 + * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) + */ + public static Method getAccessibleMethod(final Object obj, final String methodName, + final Class... parameterTypes) + { + // 为空不报错。直接返回 null + if (obj == null) + { + return null; + } + Validate.notBlank(methodName, "methodName can't be blank"); + for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) + { + try + { + Method method = searchType.getDeclaredMethod(methodName, parameterTypes); + makeAccessible(method); + return method; + } + catch (NoSuchMethodException e) + { + continue; + } + } + return null; + } + + /** + * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + * 只匹配函数名。 + * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) + */ + public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) + { + // 为空不报错。直接返回 null + if (obj == null) + { + return null; + } + Validate.notBlank(methodName, "methodName can't be blank"); + for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) + { + Method[] methods = searchType.getDeclaredMethods(); + for (Method method : methods) + { + if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) + { + makeAccessible(method); + return method; + } + } + } + return null; + } + + /** + * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 + */ + public static void makeAccessible(Method method) + { + if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) + && !method.canAccess(null)) + { + method.setAccessible(true); + } + } + + /** + * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 + */ + public static void makeAccessible(Field field) + { + if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) + || Modifier.isFinal(field.getModifiers())) && !field.canAccess(null)) + { + field.setAccessible(true); + } + } + + /** + * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处 + * 如无法找到, 返回Object.class. + */ + @SuppressWarnings("unchecked") + public static Class getClassGenricType(final Class clazz) + { + return getClassGenricType(clazz, 0); + } + + /** + * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. + * 如无法找到, 返回Object.class. + */ + public static Class getClassGenricType(final Class clazz, final int index) + { + Type genType = clazz.getGenericSuperclass(); + + if (!(genType instanceof ParameterizedType)) + { + logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType"); + return Object.class; + } + + Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); + + if (index >= params.length || index < 0) + { + logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + + params.length); + return Object.class; + } + if (!(params[index] instanceof Class)) + { + logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter"); + return Object.class; + } + + return (Class) params[index]; + } + + public static Class getUserClass(Object instance) + { + if (instance == null) + { + throw new RuntimeException("Instance must not be null"); + } + Class clazz = instance.getClass(); + if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) + { + Class superClass = clazz.getSuperclass(); + if (superClass != null && !Object.class.equals(superClass)) + { + return superClass; + } + } + return clazz; + + } + + /** + * 将反射时的checked exception转换为unchecked exception. + */ + public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e) + { + if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException + || e instanceof NoSuchMethodException) + { + return new IllegalArgumentException(msg, e); + } + else if (e instanceof InvocationTargetException) + { + return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException()); + } + return new RuntimeException(msg, e); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/sign/Base64.java b/boyue-common/src/main/java/com/boyue/common/utils/sign/Base64.java new file mode 100644 index 0000000..6821ec2 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/sign/Base64.java @@ -0,0 +1,291 @@ +package com.boyue.common.utils.sign; + +/** + * Base64工具类 + * + * @author boyue + */ +public final class Base64 +{ + static private final int BASELENGTH = 128; + static private final int LOOKUPLENGTH = 64; + static private final int TWENTYFOURBITGROUP = 24; + static private final int EIGHTBIT = 8; + static private final int SIXTEENBIT = 16; + static private final int FOURBYTE = 4; + static private final int SIGN = -128; + static private final char PAD = '='; + static final private byte[] base64Alphabet = new byte[BASELENGTH]; + static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; + + static + { + for (int i = 0; i < BASELENGTH; ++i) + { + base64Alphabet[i] = -1; + } + for (int i = 'Z'; i >= 'A'; i--) + { + base64Alphabet[i] = (byte) (i - 'A'); + } + for (int i = 'z'; i >= 'a'; i--) + { + base64Alphabet[i] = (byte) (i - 'a' + 26); + } + + for (int i = '9'; i >= '0'; i--) + { + base64Alphabet[i] = (byte) (i - '0' + 52); + } + + base64Alphabet['+'] = 62; + base64Alphabet['/'] = 63; + + for (int i = 0; i <= 25; i++) + { + lookUpBase64Alphabet[i] = (char) ('A' + i); + } + + for (int i = 26, j = 0; i <= 51; i++, j++) + { + lookUpBase64Alphabet[i] = (char) ('a' + j); + } + + for (int i = 52, j = 0; i <= 61; i++, j++) + { + lookUpBase64Alphabet[i] = (char) ('0' + j); + } + lookUpBase64Alphabet[62] = (char) '+'; + lookUpBase64Alphabet[63] = (char) '/'; + } + + private static boolean isWhiteSpace(char octect) + { + return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); + } + + private static boolean isPad(char octect) + { + return (octect == PAD); + } + + private static boolean isData(char octect) + { + return (octect < BASELENGTH && base64Alphabet[octect] != -1); + } + + /** + * Encodes hex octects into Base64 + * + * @param binaryData Array containing binaryData + * @return Encoded Base64 array + */ + public static String encode(byte[] binaryData) + { + if (binaryData == null) + { + return null; + } + + int lengthDataBits = binaryData.length * EIGHTBIT; + if (lengthDataBits == 0) + { + return ""; + } + + int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; + int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; + int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets; + char encodedData[] = null; + + encodedData = new char[numberQuartet * 4]; + + byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; + + int encodedIndex = 0; + int dataIndex = 0; + + for (int i = 0; i < numberTriplets; i++) + { + b1 = binaryData[dataIndex++]; + b2 = binaryData[dataIndex++]; + b3 = binaryData[dataIndex++]; + + l = (byte) (b2 & 0x0f); + k = (byte) (b1 & 0x03); + + byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); + byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); + + encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f]; + } + + // form integral number of 6-bit groups + if (fewerThan24bits == EIGHTBIT) + { + b1 = binaryData[dataIndex]; + k = (byte) (b1 & 0x03); + byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4]; + encodedData[encodedIndex++] = PAD; + encodedData[encodedIndex++] = PAD; + } + else if (fewerThan24bits == SIXTEENBIT) + { + b1 = binaryData[dataIndex]; + b2 = binaryData[dataIndex + 1]; + l = (byte) (b2 & 0x0f); + k = (byte) (b1 & 0x03); + + byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); + + encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; + encodedData[encodedIndex++] = PAD; + } + return new String(encodedData); + } + + /** + * Decodes Base64 data into octects + * + * @param encoded string containing Base64 data + * @return Array containind decoded data. + */ + public static byte[] decode(String encoded) + { + if (encoded == null) + { + return null; + } + + char[] base64Data = encoded.toCharArray(); + // remove white spaces + int len = removeWhiteSpace(base64Data); + + if (len % FOURBYTE != 0) + { + return null;// should be divisible by four + } + + int numberQuadruple = (len / FOURBYTE); + + if (numberQuadruple == 0) + { + return new byte[0]; + } + + byte decodedData[] = null; + byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; + char d1 = 0, d2 = 0, d3 = 0, d4 = 0; + + int i = 0; + int encodedIndex = 0; + int dataIndex = 0; + decodedData = new byte[(numberQuadruple) * 3]; + + for (; i < numberQuadruple - 1; i++) + { + + if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])) + || !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++]))) + { + return null; + } // if found "no data" just return null + + b1 = base64Alphabet[d1]; + b2 = base64Alphabet[d2]; + b3 = base64Alphabet[d3]; + b4 = base64Alphabet[d4]; + + decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); + decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); + } + + if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) + { + return null;// if found "no data" just return null + } + + b1 = base64Alphabet[d1]; + b2 = base64Alphabet[d2]; + + d3 = base64Data[dataIndex++]; + d4 = base64Data[dataIndex++]; + if (!isData((d3)) || !isData((d4))) + {// Check if they are PAD characters + if (isPad(d3) && isPad(d4)) + { + if ((b2 & 0xf) != 0)// last 4 bits should be zero + { + return null; + } + byte[] tmp = new byte[i * 3 + 1]; + System.arraycopy(decodedData, 0, tmp, 0, i * 3); + tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); + return tmp; + } + else if (!isPad(d3) && isPad(d4)) + { + b3 = base64Alphabet[d3]; + if ((b3 & 0x3) != 0)// last 2 bits should be zero + { + return null; + } + byte[] tmp = new byte[i * 3 + 2]; + System.arraycopy(decodedData, 0, tmp, 0, i * 3); + tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); + tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + return tmp; + } + else + { + return null; + } + } + else + { // No PAD e.g 3cQl + b3 = base64Alphabet[d3]; + b4 = base64Alphabet[d4]; + decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); + decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); + + } + return decodedData; + } + + /** + * remove WhiteSpace from MIME containing encoded Base64 data. + * + * @param data the byte array of base64 data (with WS) + * @return the new length + */ + private static int removeWhiteSpace(char[] data) + { + if (data == null) + { + return 0; + } + + // count characters that's not whitespace + int newSize = 0; + int len = data.length; + for (int i = 0; i < len; i++) + { + if (!isWhiteSpace(data[i])) + { + data[newSize++] = data[i]; + } + } + return newSize; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/sign/Md5Utils.java b/boyue-common/src/main/java/com/boyue/common/utils/sign/Md5Utils.java new file mode 100644 index 0000000..2e87e38 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/sign/Md5Utils.java @@ -0,0 +1,166 @@ +package com.boyue.common.utils.sign; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.apache.commons.codec.digest.DigestUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.multipart.MultipartFile; + +/** + * Md5加密方法 + * + * @author boyue + */ +public class Md5Utils { + private static final Logger log = LoggerFactory.getLogger(Md5Utils.class); + + private static final ThreadLocal md5DigestThreadLocal = ThreadLocal.withInitial(() -> { + try { + return MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("MD5 algorithm not found", e); + } + }); + + private static byte[] md5(String s) { + MessageDigest algorithm; + try { + algorithm = MessageDigest.getInstance("MD5"); + algorithm.reset(); + algorithm.update(s.getBytes("UTF-8")); + byte[] messageDigest = algorithm.digest(); + return messageDigest; + } catch (Exception e) { + log.error("MD5 Error...", e); + } + return null; + } + + private static final String toHex(byte hash[]) { + if (hash == null) { + return null; + } + StringBuffer buf = new StringBuffer(hash.length * 2); + int i; + + for (i = 0; i < hash.length; i++) { + if ((hash[i] & 0xff) < 0x10) { + buf.append("0"); + } + buf.append(Long.toString(hash[i] & 0xff, 16)); + } + return buf.toString(); + } + + public static String hash(String s) { + try { + return new String(toHex(md5(s)).getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); + } catch (Exception e) { + log.error("not supported charset...{}", e); + return s; + } + } + + public static String encryptMd5(String string) throws UnsupportedEncodingException { + return encryptMd5(string, "UTF-8"); + } + + public static String encryptMd5(String string, String charSet) throws UnsupportedEncodingException { + return DigestUtils.md5Hex(string.getBytes(charSet)); + } + + /** + * 计算文件的md5 + * @param file 文件,可以是 MultipartFile 或 File + * @return + */ + public static String getMd5(Object file) { + try (InputStream inputStream = getInputStream(file)) { + long fileSize = getFileSize(file); + // 10MB作为分界点 + if (fileSize < 10 * 1024 * 1024) { + return getMd5ForSmallFile(inputStream); + } else { + return getMd5ForLargeFile(inputStream); + } + } catch (Exception e) { + log.error(e.getMessage()); + } + return null; + } + + private static InputStream getInputStream(Object file) throws IOException { + if (file instanceof MultipartFile) { + return ((MultipartFile) file).getInputStream(); + } else if (file instanceof File) { + return new FileInputStream((File) file); + } + throw new IllegalArgumentException("Unsupported file type"); + } + + private static long getFileSize(Object file) throws IOException { + if (file instanceof MultipartFile) { + return ((MultipartFile) file).getSize(); + } else if (file instanceof File) { + return ((File) file).length(); + } + throw new IllegalArgumentException("Unsupported file type"); + } + + /** + * 计算小文件的md5 + * + * @param inputStream 文件输入流 + * @return + */ + private static String getMd5ForSmallFile(InputStream inputStream) { + try { + byte[] uploadBytes = inputStream.readAllBytes(); + MessageDigest md5 = md5DigestThreadLocal.get(); + byte[] digest = md5.digest(uploadBytes); + String md5Hex = new BigInteger(1, digest).toString(16); + while (md5Hex.length() < 32) { + md5Hex = "0" + md5Hex; + } + return md5Hex; + } catch (Exception e) { + log.error(e.getMessage()); + } + return null; + } + + /** + * 计算大文件的md5 + * + * @param inputStream 文件输入流 + * @return + */ + private static String getMd5ForLargeFile(InputStream inputStream) { + try (InputStream is = inputStream) { + MessageDigest md = md5DigestThreadLocal.get(); + byte[] buffer = new byte[81920]; + int read; + while ((read = is.read(buffer)) != -1) { + md.update(buffer, 0, read); + } + byte[] digest = md.digest(); + StringBuilder sb = new StringBuilder(); + for (byte b : digest) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } catch (Exception e) { + log.error(e.getMessage()); + } + return null; + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/spring/SpringUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/spring/SpringUtils.java new file mode 100644 index 0000000..d718e6c --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/spring/SpringUtils.java @@ -0,0 +1,158 @@ +package com.boyue.common.utils.spring; + +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; +import com.boyue.common.utils.StringUtils; + +/** + * spring工具类 方便在非spring管理环境中获取bean + * + * @author boyue + */ +@Component +public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware +{ + /** Spring应用上下文环境 */ + private static ConfigurableListableBeanFactory beanFactory; + + private static ApplicationContext applicationContext; + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException + { + SpringUtils.beanFactory = beanFactory; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + SpringUtils.applicationContext = applicationContext; + } + + /** + * 获取对象 + * + * @param name + * @return Object 一个以所给名字注册的bean的实例 + * @throws org.springframework.beans.BeansException + * + */ + @SuppressWarnings("unchecked") + public static T getBean(String name) throws BeansException + { + return (T) beanFactory.getBean(name); + } + + /** + * 获取类型为requiredType的对象 + * + * @param clz + * @return + * @throws org.springframework.beans.BeansException + * + */ + public static T getBean(Class clz) throws BeansException + { + T result = (T) beanFactory.getBean(clz); + return result; + } + + /** + * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true + * + * @param name + * @return boolean + */ + public static boolean containsBean(String name) + { + return beanFactory.containsBean(name); + } + + /** + * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) + * + * @param name + * @return boolean + * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException + * + */ + public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException + { + return beanFactory.isSingleton(name); + } + + /** + * @param name + * @return Class 注册对象的类型 + * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException + * + */ + public static Class getType(String name) throws NoSuchBeanDefinitionException + { + return beanFactory.getType(name); + } + + /** + * 如果给定的bean名字在bean定义中有别名,则返回这些别名 + * + * @param name + * @return + * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException + * + */ + public static String[] getAliases(String name) throws NoSuchBeanDefinitionException + { + return beanFactory.getAliases(name); + } + + /** + * 获取aop代理对象 + * + * @param invoker + * @return + */ + @SuppressWarnings("unchecked") + public static T getAopProxy(T invoker) + { + return (T) AopContext.currentProxy(); + } + + /** + * 获取当前的环境配置,无配置返回null + * + * @return 当前的环境配置 + */ + public static String[] getActiveProfiles() + { + return applicationContext.getEnvironment().getActiveProfiles(); + } + + /** + * 获取当前的环境配置,当有多个环境配置时,只获取第一个 + * + * @return 当前的环境配置 + */ + public static String getActiveProfile() + { + final String[] activeProfiles = getActiveProfiles(); + return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null; + } + + /** + * 获取配置文件中的值 + * + * @param key 配置文件的key + * @return 当前的配置文件的值 + * + */ + public static String getRequiredProperty(String key) + { + return applicationContext.getEnvironment().getRequiredProperty(key); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/sql/SqlUtil.java b/boyue-common/src/main/java/com/boyue/common/utils/sql/SqlUtil.java new file mode 100644 index 0000000..b758920 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/sql/SqlUtil.java @@ -0,0 +1,66 @@ +package com.boyue.common.utils.sql; + +import java.io.StringReader; + +import com.boyue.common.exception.UtilException; +import com.boyue.common.utils.StringUtils; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserManager; +import net.sf.jsqlparser.statement.Statement; + +/** + * sql操作工具类 + * + * @author boyue + */ +public class SqlUtil { + + private static final CCJSqlParserManager parserManager = new CCJSqlParserManager(); + + /** + * 定义常用的 sql关键字 + */ + public static String SQL_REGEX = "and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()"; + + /** + * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) + */ + public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; + + /** + * 检查字符,防止注入绕过 + */ + public static String escapeOrderBySql(String value) { + if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) { + throw new UtilException("参数不符合规范,不能进行查询"); + } + return value; + } + + /** + * 验证 order by 语法是否符合规范 + */ + public static boolean isValidOrderBySql(String value) { + return value.matches(SQL_PATTERN); + } + + /** + * SQL关键字检查 + */ + public static void filterKeyword(String value) { + if (StringUtils.isEmpty(value)) { + return; + } + String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|"); + for (String sqlKeyword : sqlKeywords) { + if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) { + throw new UtilException("参数存在SQL注入风险"); + } + } + } + + public static Statement parseSql(String sql) throws JSQLParserException { + return parserManager.parse(new StringReader(sql)); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/uuid/IdUtils.java b/boyue-common/src/main/java/com/boyue/common/utils/uuid/IdUtils.java new file mode 100644 index 0000000..76b0a0a --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/uuid/IdUtils.java @@ -0,0 +1,49 @@ +package com.boyue.common.utils.uuid; + +/** + * ID生成器工具类 + * + * @author boyue + */ +public class IdUtils +{ + /** + * 获取随机UUID + * + * @return 随机UUID + */ + public static String randomUUID() + { + return UUID.randomUUID().toString(); + } + + /** + * 简化的UUID,去掉了横线 + * + * @return 简化的UUID,去掉了横线 + */ + public static String simpleUUID() + { + return UUID.randomUUID().toString(true); + } + + /** + * 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID + * + * @return 随机UUID + */ + public static String fastUUID() + { + return UUID.fastUUID().toString(); + } + + /** + * 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID + * + * @return 简化的UUID,去掉了横线 + */ + public static String fastSimpleUUID() + { + return UUID.fastUUID().toString(true); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/uuid/Seq.java b/boyue-common/src/main/java/com/boyue/common/utils/uuid/Seq.java new file mode 100644 index 0000000..de15768 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/uuid/Seq.java @@ -0,0 +1,86 @@ +package com.boyue.common.utils.uuid; + +import java.util.concurrent.atomic.AtomicInteger; +import com.boyue.common.utils.DateUtils; +import com.boyue.common.utils.StringUtils; + +/** + * @author boyue 序列生成类 + */ +public class Seq +{ + // 通用序列类型 + public static final String commSeqType = "COMMON"; + + // 上传序列类型 + public static final String uploadSeqType = "UPLOAD"; + + // 通用接口序列数 + private static AtomicInteger commSeq = new AtomicInteger(1); + + // 上传接口序列数 + private static AtomicInteger uploadSeq = new AtomicInteger(1); + + // 机器标识 + private static final String machineCode = "A"; + + /** + * 获取通用序列号 + * + * @return 序列值 + */ + public static String getId() + { + return getId(commSeqType); + } + + /** + * 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串 + * + * @return 序列值 + */ + public static String getId(String type) + { + AtomicInteger atomicInt = commSeq; + if (uploadSeqType.equals(type)) + { + atomicInt = uploadSeq; + } + return getId(atomicInt, 3); + } + + /** + * 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串 + * + * @param atomicInt 序列数 + * @param length 数值长度 + * @return 序列值 + */ + public static String getId(AtomicInteger atomicInt, int length) + { + String result = DateUtils.dateTimeNow(); + result += machineCode; + result += getSeq(atomicInt, length); + return result; + } + + /** + * 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数 + * + * @return 序列值 + */ + private synchronized static String getSeq(AtomicInteger atomicInt, int length) + { + // 先取值再+1 + int value = atomicInt.getAndIncrement(); + + // 如果更新后值>=10 的 (length)幂次方则重置为1 + int maxSeq = (int) Math.pow(10, length); + if (atomicInt.get() >= maxSeq) + { + atomicInt.set(1); + } + // 转字符串,用0左补齐 + return StringUtils.padl(value, length); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/utils/uuid/UUID.java b/boyue-common/src/main/java/com/boyue/common/utils/uuid/UUID.java new file mode 100644 index 0000000..1e53d95 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/utils/uuid/UUID.java @@ -0,0 +1,484 @@ +package com.boyue.common.utils.uuid; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; +import com.boyue.common.exception.UtilException; + +/** + * 提供通用唯一识别码(universally unique identifier)(UUID)实现 + * + * @author boyue + */ +public final class UUID implements java.io.Serializable, Comparable +{ + private static final long serialVersionUID = -1185015143654744140L; + + /** + * SecureRandom 的单例 + * + */ + private static class Holder + { + static final SecureRandom numberGenerator = getSecureRandom(); + } + + /** 此UUID的最高64有效位 */ + private final long mostSigBits; + + /** 此UUID的最低64有效位 */ + private final long leastSigBits; + + /** + * 私有构造 + * + * @param data 数据 + */ + private UUID(byte[] data) + { + long msb = 0; + long lsb = 0; + assert data.length == 16 : "data must be 16 bytes in length"; + for (int i = 0; i < 8; i++) + { + msb = (msb << 8) | (data[i] & 0xff); + } + for (int i = 8; i < 16; i++) + { + lsb = (lsb << 8) | (data[i] & 0xff); + } + this.mostSigBits = msb; + this.leastSigBits = lsb; + } + + /** + * 使用指定的数据构造新的 UUID。 + * + * @param mostSigBits 用于 {@code UUID} 的最高有效 64 位 + * @param leastSigBits 用于 {@code UUID} 的最低有效 64 位 + */ + public UUID(long mostSigBits, long leastSigBits) + { + this.mostSigBits = mostSigBits; + this.leastSigBits = leastSigBits; + } + + /** + * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的本地线程伪随机数生成器生成该 UUID。 + * + * @return 随机生成的 {@code UUID} + */ + public static UUID fastUUID() + { + return randomUUID(false); + } + + /** + * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。 + * + * @return 随机生成的 {@code UUID} + */ + public static UUID randomUUID() + { + return randomUUID(true); + } + + /** + * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。 + * + * @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码,否则可以得到更好的性能 + * @return 随机生成的 {@code UUID} + */ + public static UUID randomUUID(boolean isSecure) + { + final Random ng = isSecure ? Holder.numberGenerator : getRandom(); + + byte[] randomBytes = new byte[16]; + ng.nextBytes(randomBytes); + randomBytes[6] &= 0x0f; /* clear version */ + randomBytes[6] |= 0x40; /* set to version 4 */ + randomBytes[8] &= 0x3f; /* clear variant */ + randomBytes[8] |= 0x80; /* set to IETF variant */ + return new UUID(randomBytes); + } + + /** + * 根据指定的字节数组获取类型 3(基于名称的)UUID 的静态工厂。 + * + * @param name 用于构造 UUID 的字节数组。 + * + * @return 根据指定数组生成的 {@code UUID} + */ + public static UUID nameUUIDFromBytes(byte[] name) + { + MessageDigest md; + try + { + md = MessageDigest.getInstance("MD5"); + } + catch (NoSuchAlgorithmException nsae) + { + throw new InternalError("MD5 not supported"); + } + byte[] md5Bytes = md.digest(name); + md5Bytes[6] &= 0x0f; /* clear version */ + md5Bytes[6] |= 0x30; /* set to version 3 */ + md5Bytes[8] &= 0x3f; /* clear variant */ + md5Bytes[8] |= 0x80; /* set to IETF variant */ + return new UUID(md5Bytes); + } + + /** + * 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。 + * + * @param name 指定 {@code UUID} 字符串 + * @return 具有指定值的 {@code UUID} + * @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常 + * + */ + public static UUID fromString(String name) + { + String[] components = name.split("-"); + if (components.length != 5) + { + throw new IllegalArgumentException("Invalid UUID string: " + name); + } + for (int i = 0; i < 5; i++) + { + components[i] = "0x" + components[i]; + } + + long mostSigBits = Long.decode(components[0]).longValue(); + mostSigBits <<= 16; + mostSigBits |= Long.decode(components[1]).longValue(); + mostSigBits <<= 16; + mostSigBits |= Long.decode(components[2]).longValue(); + + long leastSigBits = Long.decode(components[3]).longValue(); + leastSigBits <<= 48; + leastSigBits |= Long.decode(components[4]).longValue(); + + return new UUID(mostSigBits, leastSigBits); + } + + /** + * 返回此 UUID 的 128 位值中的最低有效 64 位。 + * + * @return 此 UUID 的 128 位值中的最低有效 64 位。 + */ + public long getLeastSignificantBits() + { + return leastSigBits; + } + + /** + * 返回此 UUID 的 128 位值中的最高有效 64 位。 + * + * @return 此 UUID 的 128 位值中最高有效 64 位。 + */ + public long getMostSignificantBits() + { + return mostSigBits; + } + + /** + * 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。 + *

+ * 版本号具有以下含意: + *

    + *
  • 1 基于时间的 UUID + *
  • 2 DCE 安全 UUID + *
  • 3 基于名称的 UUID + *
  • 4 随机生成的 UUID + *
+ * + * @return 此 {@code UUID} 的版本号 + */ + public int version() + { + // Version is bits masked by 0x000000000000F000 in MS long + return (int) ((mostSigBits >> 12) & 0x0f); + } + + /** + * 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。 + *

+ * 变体号具有以下含意: + *

    + *
  • 0 为 NCS 向后兼容保留 + *
  • 2 IETF RFC 4122(Leach-Salz), 用于此类 + *
  • 6 保留,微软向后兼容 + *
  • 7 保留供以后定义使用 + *
+ * + * @return 此 {@code UUID} 相关联的变体号 + */ + public int variant() + { + // This field is composed of a varying number of bits. + // 0 - - Reserved for NCS backward compatibility + // 1 0 - The IETF aka Leach-Salz variant (used by this class) + // 1 1 0 Reserved, Microsoft backward compatibility + // 1 1 1 Reserved for future definition. + return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63)); + } + + /** + * 与此 UUID 相关联的时间戳值。 + * + *

+ * 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。
+ * 所得到的时间戳以 100 毫微秒为单位,从 UTC(通用协调时间) 1582 年 10 月 15 日零时开始。 + * + *

+ * 时间戳值仅在在基于时间的 UUID(其 version 类型为 1)中才有意义。
+ * 如果此 {@code UUID} 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。 + * + * @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。 + */ + public long timestamp() throws UnsupportedOperationException + { + checkTimeBase(); + return (mostSigBits & 0x0FFFL) << 48// + | ((mostSigBits >> 16) & 0x0FFFFL) << 32// + | mostSigBits >>> 32; + } + + /** + * 与此 UUID 相关联的时钟序列值。 + * + *

+ * 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。 + *

+ * {@code clockSequence} 值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。 如果此 UUID 不是基于时间的 UUID,则此方法抛出 + * UnsupportedOperationException。 + * + * @return 此 {@code UUID} 的时钟序列 + * + * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1 + */ + public int clockSequence() throws UnsupportedOperationException + { + checkTimeBase(); + return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48); + } + + /** + * 与此 UUID 相关的节点值。 + * + *

+ * 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址,该地址用于生成此 UUID 以保证空间唯一性。 + *

+ * 节点值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。
+ * 如果此 UUID 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。 + * + * @return 此 {@code UUID} 的节点值 + * + * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1 + */ + public long node() throws UnsupportedOperationException + { + checkTimeBase(); + return leastSigBits & 0x0000FFFFFFFFFFFFL; + } + + /** + * 返回此{@code UUID} 的字符串表现形式。 + * + *

+ * UUID 的字符串表示形式由此 BNF 描述: + * + *

+     * {@code
+     * UUID                   = ----
+     * time_low               = 4*
+     * time_mid               = 2*
+     * time_high_and_version  = 2*
+     * variant_and_sequence   = 2*
+     * node                   = 6*
+     * hexOctet               = 
+     * hexDigit               = [0-9a-fA-F]
+     * }
+     * 
+ * + * + * + * @return 此{@code UUID} 的字符串表现形式 + * @see #toString(boolean) + */ + @Override + public String toString() + { + return toString(false); + } + + /** + * 返回此{@code UUID} 的字符串表现形式。 + * + *

+ * UUID 的字符串表示形式由此 BNF 描述: + * + *

+     * {@code
+     * UUID                   = ----
+     * time_low               = 4*
+     * time_mid               = 2*
+     * time_high_and_version  = 2*
+     * variant_and_sequence   = 2*
+     * node                   = 6*
+     * hexOctet               = 
+     * hexDigit               = [0-9a-fA-F]
+     * }
+     * 
+ * + * + * + * @param isSimple 是否简单模式,简单模式为不带'-'的UUID字符串 + * @return 此{@code UUID} 的字符串表现形式 + */ + public String toString(boolean isSimple) + { + final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36); + // time_low + builder.append(digits(mostSigBits >> 32, 8)); + if (!isSimple) + { + builder.append('-'); + } + // time_mid + builder.append(digits(mostSigBits >> 16, 4)); + if (!isSimple) + { + builder.append('-'); + } + // time_high_and_version + builder.append(digits(mostSigBits, 4)); + if (!isSimple) + { + builder.append('-'); + } + // variant_and_sequence + builder.append(digits(leastSigBits >> 48, 4)); + if (!isSimple) + { + builder.append('-'); + } + // node + builder.append(digits(leastSigBits, 12)); + + return builder.toString(); + } + + /** + * 返回此 UUID 的哈希码。 + * + * @return UUID 的哈希码值。 + */ + @Override + public int hashCode() + { + long hilo = mostSigBits ^ leastSigBits; + return ((int) (hilo >> 32)) ^ (int) hilo; + } + + /** + * 将此对象与指定对象比较。 + *

+ * 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值(每一位均相同)时,结果才为 {@code true}。 + * + * @param obj 要与之比较的对象 + * + * @return 如果对象相同,则返回 {@code true};否则返回 {@code false} + */ + @Override + public boolean equals(Object obj) + { + if ((null == obj) || (obj.getClass() != UUID.class)) + { + return false; + } + UUID id = (UUID) obj; + return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits); + } + + // Comparison Operations + + /** + * 将此 UUID 与指定的 UUID 比较。 + * + *

+ * 如果两个 UUID 不同,且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段,则第一个 UUID 大于第二个 UUID。 + * + * @param val 与此 UUID 比较的 UUID + * + * @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。 + * + */ + @Override + public int compareTo(UUID val) + { + // The ordering is intentionally set up so that the UUIDs + // can simply be numerically compared as two numbers + return (this.mostSigBits < val.mostSigBits ? -1 : // + (this.mostSigBits > val.mostSigBits ? 1 : // + (this.leastSigBits < val.leastSigBits ? -1 : // + (this.leastSigBits > val.leastSigBits ? 1 : // + 0)))); + } + + // ------------------------------------------------------------------------------------------------------------------- + // Private method start + /** + * 返回指定数字对应的hex值 + * + * @param val 值 + * @param digits 位 + * @return 值 + */ + private static String digits(long val, int digits) + { + long hi = 1L << (digits * 4); + return Long.toHexString(hi | (val & (hi - 1))).substring(1); + } + + /** + * 检查是否为time-based版本UUID + */ + private void checkTimeBase() + { + if (version() != 1) + { + throw new UnsupportedOperationException("Not a time-based UUID"); + } + } + + /** + * 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG) + * + * @return {@link SecureRandom} + */ + public static SecureRandom getSecureRandom() + { + try + { + return SecureRandom.getInstance("SHA1PRNG"); + } + catch (NoSuchAlgorithmException e) + { + throw new UtilException(e); + } + } + + /** + * 获取随机数生成器对象
+ * ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。 + * + * @return {@link ThreadLocalRandom} + */ + public static ThreadLocalRandom getRandom() + { + return ThreadLocalRandom.current(); + } +} diff --git a/boyue-common/src/main/java/com/boyue/common/xss/Xss.java b/boyue-common/src/main/java/com/boyue/common/xss/Xss.java new file mode 100644 index 0000000..7f831ff --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/xss/Xss.java @@ -0,0 +1,27 @@ +package com.boyue.common.xss; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义xss校验注解 + * + * @author boyue + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value = { ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER }) +@Constraint(validatedBy = { XssValidator.class }) +public @interface Xss +{ + String message() + + default "不允许任何脚本运行"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/boyue-common/src/main/java/com/boyue/common/xss/XssValidator.java b/boyue-common/src/main/java/com/boyue/common/xss/XssValidator.java new file mode 100644 index 0000000..2dce621 --- /dev/null +++ b/boyue-common/src/main/java/com/boyue/common/xss/XssValidator.java @@ -0,0 +1,34 @@ +package com.boyue.common.xss; + +import com.boyue.common.utils.StringUtils; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 自定义xss校验注解实现 + * + * @author boyue + */ +public class XssValidator implements ConstraintValidator +{ + private static final String HTML_PATTERN = "<(\\S*?)[^>]*>.*?|<.*? />"; + + @Override + public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) + { + if (StringUtils.isBlank(value)) + { + return true; + } + return !containsHtml(value); + } + + public static boolean containsHtml(String value) + { + Pattern pattern = Pattern.compile(HTML_PATTERN); + Matcher matcher = pattern.matcher(value); + return matcher.matches(); + } +} \ No newline at end of file diff --git a/boyue-file/boyue-file-common/pom.xml b/boyue-file/boyue-file-common/pom.xml new file mode 100644 index 0000000..204f8bf --- /dev/null +++ b/boyue-file/boyue-file-common/pom.xml @@ -0,0 +1,24 @@ + + + + boyue-file + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-file-common + + + 文件模块公共依赖 + + + + + com.boyue + boyue-common + + + + \ No newline at end of file diff --git a/boyue-file/boyue-file-common/src/main/java/com/boyue/file/domain/SysFileInfo.java b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/domain/SysFileInfo.java new file mode 100644 index 0000000..bb5f95c --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/domain/SysFileInfo.java @@ -0,0 +1,60 @@ +package com.boyue.file.domain; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 文件信息对象 sys_file_info + * + * @author boyue + * @date 2025-04-25 + */ +@Schema(description = "文件信息对象") +@Data +@EqualsAndHashCode(callSuper = true) +public class SysFileInfo extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** 文件主键 */ + @Schema(title = "文件主键") + private Long fileId; + + /** 原始文件名 */ + @Schema(title = "原始文件名") + @Excel(name = "原始文件名") + private String fileName; + + /** 统一逻辑路径(/开头) */ + @Schema(title = "统一逻辑路径(/开头)") + @Excel(name = "统一逻辑路径", readConverterExp = "/=开头") + private String filePath; + + /** 存储类型(local/minio/oss) */ + @Schema(title = "存储类型(local/minio/oss)") + @Excel(name = "存储类型", readConverterExp = "l=ocal/minio/oss") + private String storageType; + + /** 文件类型/后缀 */ + @Schema(title = "文件类型/后缀") + @Excel(name = "文件类型/后缀") + private String fileType; + + /** 文件大小(字节) */ + @Schema(title = "文件大小(字节)") + @Excel(name = "文件大小", readConverterExp = "字=节") + private Long fileSize; + + /** 文件MD5 */ + @Schema(title = "文件MD5") + @Excel(name = "文件MD5") + private String md5; + + /** 删除标志(0代表存在 2代表删除) */ + @Schema(title = "删除标志(0代表存在 2代表删除)") + private String delFlag; + +} diff --git a/boyue-file/boyue-file-common/src/main/java/com/boyue/file/domain/SysFilePartETag.java b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/domain/SysFilePartETag.java new file mode 100644 index 0000000..9499888 --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/domain/SysFilePartETag.java @@ -0,0 +1,55 @@ +package com.boyue.file.domain; + +import java.io.Serializable; + +import lombok.Data; + +@Data +public class SysFilePartETag implements Serializable { + private static final long serialVersionUID = 2471854027355307627L; + private Integer partNumber; + private String eTag; + private Long partSize; + private Long partCRC; + + public void seteTag(String eTag) { + this.eTag = eTag; + } + + public SysFilePartETag() { + } + + public SysFilePartETag(Integer partNumber, String eTag) { + this.partNumber = partNumber; + this.eTag = eTag; + } + + public SysFilePartETag(Integer partNumber, String eTag, long partSize, Long partCRC) { + this.partNumber = partNumber; + this.eTag = eTag; + this.partSize = partSize; + this.partCRC = partCRC; + } + + public int hashCode() { + int result = 1; + result = 31 * result + (this.eTag == null ? 0 : this.eTag.hashCode()); + result = 31 * result + this.partNumber; + return result; + } + + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if (!(obj instanceof SysFilePartETag)) { + return false; + } else { + SysFilePartETag other = (SysFilePartETag) obj; + if (this.partNumber != other.partNumber) { + return false; + } else { + return this.eTag == null ? other.eTag == null : this.eTag.equals(other.eTag); + } + } + } +} diff --git a/boyue-file/boyue-file-common/src/main/java/com/boyue/file/local/config/LocalBucketProperties.java b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/local/config/LocalBucketProperties.java new file mode 100644 index 0000000..bc2ee59 --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/local/config/LocalBucketProperties.java @@ -0,0 +1,10 @@ +package com.boyue.file.local.config; + +import lombok.Data; + +@Data +public class LocalBucketProperties { + private String path; + private String permission; + private String api; +} diff --git a/boyue-file/boyue-file-common/src/main/java/com/boyue/file/local/config/LocalManagement.java b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/local/config/LocalManagement.java new file mode 100644 index 0000000..25ec2a1 --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/local/config/LocalManagement.java @@ -0,0 +1,81 @@ +package com.boyue.file.local.config; + +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import com.boyue.file.local.domain.LocalBucket; +import com.boyue.file.storage.StorageManagement; + +@Configuration("local") +@ConditionalOnProperty(prefix = "local", name = { "enable" }, havingValue = "true", matchIfMissing = false) +@ConfigurationProperties("local") +public class LocalManagement implements StorageManagement, WebMvcConfigurer { + private static final Logger logger = LoggerFactory.getLogger(LocalManagement.class); + private Map client; + private String primary; + private Map targetLocalBucket = new HashMap<>(); + private LocalBucket primaryBucket; + + @Override + public void afterPropertiesSet() throws Exception { + if (client == null || client.isEmpty()) { + throw new RuntimeException("Local client properties cannot be null or empty"); + } + client.forEach((name, props) -> { + targetLocalBucket.put(name, LocalBucket.builder() + .clientName(name) + .basePath(props.getPath()) + .permission(props.getPermission()) + .api(props.getApi()) + .build()); + logger.info("本地存储目录:{} - 配置成功,路径:{}", name, props.getPath()); + }); + if (targetLocalBucket.get(primary) == null) { + throw new RuntimeException("Primary local client " + primary + " does not exist"); + } + primaryBucket = targetLocalBucket.get(primary); + } + + @Override + public LocalBucket getBucket(String clientName) { + return targetLocalBucket.get(clientName); + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + client.forEach((name, props) -> { + if ("public".equals(props.getPermission())) { + registry.addResourceHandler(props.getApi() + "/**") + .addResourceLocations("file:" + props.getPath() + "/"); + } + }); + } + + public LocalBucket getPrimaryBucket() { + return this.primaryBucket; + } + + public Map getClient() { + return client; + } + + public void setClient(Map client) { + this.client = client; + } + + public String getPrimary() { + return primary; + } + + public void setPrimary(String primary) { + this.primary = primary; + } +} diff --git a/boyue-file/boyue-file-common/src/main/java/com/boyue/file/local/domain/LocalBucket.java b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/local/domain/LocalBucket.java new file mode 100644 index 0000000..5c042ed --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/local/domain/LocalBucket.java @@ -0,0 +1,218 @@ +package com.boyue.file.local.domain; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.channels.FileChannel; +import java.nio.channels.WritableByteChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.web.multipart.MultipartFile; + +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.ServletUtils; +import com.boyue.common.utils.sign.Md5Utils; +import com.boyue.common.utils.uuid.UUID; +import com.boyue.file.domain.SysFilePartETag; +import com.boyue.file.storage.StorageBucket; +import com.boyue.file.storage.StorageEntity; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.Builder; +import lombok.extern.slf4j.Slf4j; + +@Builder +@Slf4j +public class LocalBucket implements StorageBucket { + + private String clientName; + private String basePath; + private String permission; + private String api; + + @Override + public void put(String filePath, MultipartFile file) { + Path dest = Paths.get(basePath, filePath); + try (InputStream inputStream = file.getInputStream()) { + Files.createDirectories(dest.getParent()); + Files.copy(inputStream, dest); + } catch (Exception e) { + throw new ServiceException("Failed to upload file: " + e.getMessage()); + } + } + + @Override + public StorageEntity get(String filePath) throws IOException { + Path file = Paths.get(basePath, filePath); + StorageEntity fileEntity = new StorageEntity(); + fileEntity.setFilePath(filePath); + fileEntity.setInputStream(new FileInputStream(file.toFile())); + fileEntity.setByteCount(file.toFile().length()); + return fileEntity; + } + + @Override + public void remove(String filePath) throws IOException { + Path file = Paths.get(basePath, filePath); + Files.deleteIfExists(file); + } + + @Override + public URL generatePresignedUrl(String filePath, int expireTime) throws Exception { + HttpServletRequest request = ServletUtils.getRequest(); + StringBuffer url = request.getRequestURL(); + String contextPath = request.getSession().getServletContext().getContextPath(); + String toHex = Md5Utils.hash(filePath + expireTime); + StringBuilder sb = new StringBuilder(); + sb.append(url.delete(url.length() - request.getRequestURI().length(), url.length()) + .append(contextPath).toString()) + .append(getApi()).append("?") + .append("filePath=").append(URLEncoder.encode(filePath, "UTF-8")) + .append("&toHex=").append(toHex); + return URI.create(sb.toString()).toURL(); + } + + @Override + public URL generatePublicURL(String filePath) throws Exception { + HttpServletRequest request = ServletUtils.getRequest(); + StringBuffer url = request.getRequestURL(); + String contextPath = request.getSession().getServletContext().getContextPath(); + StringBuilder sb = new StringBuilder(); + sb.append(url.delete(url.length() - request.getRequestURI().length(), url.length()) + .append(contextPath).toString()) + .append(getApi()).append("/") + .append(filePath.replace("\\", "/")); + return new URI(sb.toString()).toURL(); + } + + // 存储分片上传的元数据 + private final ConcurrentHashMap>> uploadMetadata = new ConcurrentHashMap<>(); + + public String initMultipartUpload(String filePath) throws Exception { + try { + String uploadId = UUID.randomUUID().toString(); + uploadMetadata.put(uploadId, new ArrayList<>()); + + // 创建临时上传目录 + Path tempDir = Paths.get(basePath, "temp_uploads", uploadId); + Files.createDirectories(tempDir); + return uploadId; + } catch (Exception e) { + log.error("初始化失败: 文件={}, 错误={}", filePath, e.getMessage()); + throw new ServiceException("初始化分片上传失败: " + e.getMessage()); + } + } + + public SysFilePartETag uploadPart(String filePath, String uploadId, int partNumber, long partSize, + InputStream inputStream) + throws Exception { + if (!uploadMetadata.containsKey(uploadId)) { + throw new ServiceException("无效的 uploadId: " + uploadId); + } + Path tempDir = Paths.get(basePath, "temp_uploads", uploadId); + Path partPath = tempDir.resolve("part_" + partNumber); + try (OutputStream fos = Files.newOutputStream(partPath)) { + byte[] buffer = new byte[8192]; + int bytesRead; + long totalBytesWritten = 0; + while ((bytesRead = inputStream.read(buffer)) != -1 && totalBytesWritten < partSize) { + int writeSize = (int) Math.min(bytesRead, partSize - totalBytesWritten); + fos.write(buffer, 0, writeSize); + totalBytesWritten += writeSize; + } + if (totalBytesWritten != partSize) { + throw new ServiceException("分片大小不匹配: 预期=" + partSize + ", 实际=" + totalBytesWritten); + } + } + String etag = Md5Utils.getMd5(partPath.toFile()); + if (etag == null) { + throw new ServiceException("计算分片 MD5 失败"); + } + etag = etag.toUpperCase(); + Map partInfo = Map.of( + "partNumber", partNumber, + "etag", etag, + "size", partSize, + "path", partPath.toString()); + synchronized (uploadMetadata) { + List> parts = uploadMetadata.get(uploadId); + int insertPos = 0; + while (insertPos < parts.size() + && ((Number) parts.get(insertPos).get("partNumber")).intValue() < partNumber) { + insertPos++; + } + parts.add(insertPos, partInfo); + } + return new SysFilePartETag(partNumber, etag, partSize, null); + } + + public String completeMultipartUpload(String filePath, String uploadId, List partETags) + throws Exception { + List> storedParts = uploadMetadata.get(uploadId); + if (storedParts == null) { + throw new ServiceException("无效的 uploadId: " + uploadId); + } + if (partETags.size() != storedParts.size()) { + throw new ServiceException("分片数量不匹配: 预期=" + storedParts.size() + ", 实际=" + partETags.size()); + } + // 验证每个分片的 ETag + for (int i = 0; i < partETags.size(); i++) { + Map expected = storedParts.get(i); + SysFilePartETag actual = partETags.get(i); + + if (!expected.get("etag").equals(actual.getETag()) || + !expected.get("partNumber").equals(actual.getPartNumber())) { + throw new ServiceException("分片验证失败: 序号=" + actual.getPartNumber()); + } + } + Path destPath = Paths.get(basePath, filePath); + Files.createDirectories(destPath.getParent()); + try (WritableByteChannel outChannel = Files.newByteChannel( + destPath, + StandardOpenOption.CREATE, + StandardOpenOption.WRITE, + StandardOpenOption.TRUNCATE_EXISTING)) { + for (Map part : storedParts) { + Path partPath = Paths.get((String) part.get("path")); + try (FileChannel inChannel = FileChannel.open(partPath, StandardOpenOption.READ)) { + inChannel.transferTo(0, inChannel.size(), outChannel); + } + } + } + // 清理临时文件和元数据 + Path tempDir = Paths.get(basePath, "temp_uploads", uploadId); + Files.walk(tempDir).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); + uploadMetadata.remove(uploadId); + log.info("分片合并完成: 文件={}, uploadId={}, 分片数={}", filePath, uploadId, storedParts.size()); + return filePath; + } + + public String getClientName() { + return clientName; + } + + public String getBasePath() { + return basePath; + } + + public String getPermission() { + return permission; + } + + public String getApi() { + return api; + } +} diff --git a/boyue-file/boyue-file-common/src/main/java/com/boyue/file/local/service/LocalFileService.java b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/local/service/LocalFileService.java new file mode 100644 index 0000000..df72f1e --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/local/service/LocalFileService.java @@ -0,0 +1,82 @@ +package com.boyue.file.local.service; + +import java.io.InputStream; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import com.boyue.file.domain.SysFilePartETag; +import com.boyue.file.local.config.LocalManagement; +import com.boyue.file.local.domain.LocalBucket; +import com.boyue.file.storage.StorageEntity; +import com.boyue.file.storage.StorageService; + +/** + * 磁盘文件操作实现类 + */ +@Component("file:strategy:local") +@ConditionalOnProperty(prefix = "local", name = { "enable" }, havingValue = "true", matchIfMissing = false) +public class LocalFileService implements StorageService { + + @Autowired + LocalManagement localConfig; + + @Override + public String upload(String filePath, MultipartFile file) throws Exception { + LocalBucket primaryBucket = localConfig.getPrimaryBucket(); + primaryBucket.put(filePath, file); + return generateUrl(filePath); + } + + @Override + public InputStream downLoad(String filePath) throws Exception { + LocalBucket primaryBucket = localConfig.getPrimaryBucket(); + return primaryBucket.get(filePath).getInputStream(); + } + + @Override + public StorageEntity getFile(String filePath) throws Exception { + LocalBucket primaryBucket = localConfig.getPrimaryBucket(); + return primaryBucket.get(filePath); + } + + @Override + public boolean deleteFile(String filePath) throws Exception { + LocalBucket primaryBucket = localConfig.getPrimaryBucket(); + primaryBucket.remove(filePath); + return true; + } + + @Override + public String generateUrl(String filePath) throws Exception { + LocalBucket primaryBucket = localConfig.getPrimaryBucket(); + if ("public".equals(primaryBucket.getPermission())) { + return primaryBucket.generatePublicURL(filePath).toString(); + } else { + return primaryBucket.generatePresignedUrl(filePath, 3600).toString(); + } + } + + @Override + public String initMultipartUpload(String filePath) throws Exception { + LocalBucket primaryBucket = localConfig.getPrimaryBucket(); + return primaryBucket.initMultipartUpload(filePath); + } + + @Override + public String uploadPart(String filePath, String uploadId, int partNumber, long partSize, InputStream inputStream) + throws Exception { + LocalBucket primaryBucket = localConfig.getPrimaryBucket(); + return primaryBucket.uploadPart(filePath, uploadId, partNumber, partSize, inputStream).getETag(); + } + + @Override + public String completeMultipartUpload(String filePath, String uploadId, List partETags) + throws Exception { + LocalBucket primaryBucket = localConfig.getPrimaryBucket(); + return primaryBucket.completeMultipartUpload(filePath, uploadId, partETags); + } +} diff --git a/boyue-file/boyue-file-common/src/main/java/com/boyue/file/mapper/SysFileInfoMapper.java b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/mapper/SysFileInfoMapper.java new file mode 100644 index 0000000..4c6c1f7 --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/mapper/SysFileInfoMapper.java @@ -0,0 +1,61 @@ +package com.boyue.file.mapper; + +import java.util.List; +import com.boyue.file.domain.SysFileInfo; + +/** + * 文件信息Mapper接口 + * + * @author boyue + * @date 2025-04-25 + */ +public interface SysFileInfoMapper +{ + /** + * 查询文件信息 + * + * @param fileId 文件信息主键 + * @return 文件信息 + */ + public SysFileInfo selectSysFileInfoByFileId(Long fileId); + + /** + * 查询文件信息列表 + * + * @param sysFileInfo 文件信息 + * @return 文件信息集合 + */ + public List selectSysFileInfoList(SysFileInfo sysFileInfo); + + /** + * 新增文件信息 + * + * @param sysFileInfo 文件信息 + * @return 结果 + */ + public int insertSysFileInfo(SysFileInfo sysFileInfo); + + /** + * 修改文件信息 + * + * @param sysFileInfo 文件信息 + * @return 结果 + */ + public int updateSysFileInfo(SysFileInfo sysFileInfo); + + /** + * 删除文件信息 + * + * @param fileId 文件信息主键 + * @return 结果 + */ + public int deleteSysFileInfoByFileId(Long fileId); + + /** + * 批量删除文件信息 + * + * @param fileIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteSysFileInfoByFileIds(Long[] fileIds); +} diff --git a/boyue-file/boyue-file-common/src/main/java/com/boyue/file/service/ISysFileInfoService.java b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/service/ISysFileInfoService.java new file mode 100644 index 0000000..fa2e89e --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/service/ISysFileInfoService.java @@ -0,0 +1,61 @@ +package com.boyue.file.service; + +import java.util.List; +import com.boyue.file.domain.SysFileInfo; + +/** + * 文件信息Service接口 + * + * @author boyue + * @date 2025-04-25 + */ +public interface ISysFileInfoService +{ + /** + * 查询文件信息 + * + * @param fileId 文件信息主键 + * @return 文件信息 + */ + public SysFileInfo selectSysFileInfoByFileId(Long fileId); + + /** + * 查询文件信息列表 + * + * @param sysFileInfo 文件信息 + * @return 文件信息集合 + */ + public List selectSysFileInfoList(SysFileInfo sysFileInfo); + + /** + * 新增文件信息 + * + * @param sysFileInfo 文件信息 + * @return 结果 + */ + public int insertSysFileInfo(SysFileInfo sysFileInfo); + + /** + * 修改文件信息 + * + * @param sysFileInfo 文件信息 + * @return 结果 + */ + public int updateSysFileInfo(SysFileInfo sysFileInfo); + + /** + * 批量删除文件信息 + * + * @param fileIds 需要删除的文件信息主键集合 + * @return 结果 + */ + public int deleteSysFileInfoByFileIds(Long[] fileIds); + + /** + * 删除文件信息信息 + * + * @param fileId 文件信息主键 + * @return 结果 + */ + public int deleteSysFileInfoByFileId(Long fileId); +} diff --git a/boyue-file/boyue-file-common/src/main/java/com/boyue/file/service/impl/SysFileInfoServiceImpl.java b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/service/impl/SysFileInfoServiceImpl.java new file mode 100644 index 0000000..d81f4ac --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/service/impl/SysFileInfoServiceImpl.java @@ -0,0 +1,96 @@ +package com.boyue.file.service.impl; + +import java.util.List; +import com.boyue.common.utils.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.boyue.file.mapper.SysFileInfoMapper; +import com.boyue.file.domain.SysFileInfo; +import com.boyue.file.service.ISysFileInfoService; + +/** + * 文件信息Service业务层处理 + * + * @author boyue + * @date 2025-04-25 + */ +@Service +public class SysFileInfoServiceImpl implements ISysFileInfoService +{ + @Autowired + private SysFileInfoMapper sysFileInfoMapper; + + /** + * 查询文件信息 + * + * @param fileId 文件信息主键 + * @return 文件信息 + */ + @Override + public SysFileInfo selectSysFileInfoByFileId(Long fileId) + { + return sysFileInfoMapper.selectSysFileInfoByFileId(fileId); + } + + /** + * 查询文件信息列表 + * + * @param sysFileInfo 文件信息 + * @return 文件信息 + */ + @Override + public List selectSysFileInfoList(SysFileInfo sysFileInfo) + { + return sysFileInfoMapper.selectSysFileInfoList(sysFileInfo); + } + + /** + * 新增文件信息 + * + * @param sysFileInfo 文件信息 + * @return 结果 + */ + @Override + public int insertSysFileInfo(SysFileInfo sysFileInfo) + { + sysFileInfo.setCreateTime(DateUtils.getNowDate()); + return sysFileInfoMapper.insertSysFileInfo(sysFileInfo); + } + + /** + * 修改文件信息 + * + * @param sysFileInfo 文件信息 + * @return 结果 + */ + @Override + public int updateSysFileInfo(SysFileInfo sysFileInfo) + { + sysFileInfo.setUpdateTime(DateUtils.getNowDate()); + return sysFileInfoMapper.updateSysFileInfo(sysFileInfo); + } + + /** + * 批量删除文件信息 + * + * @param fileIds 需要删除的文件信息主键 + * @return 结果 + */ + @Override + public int deleteSysFileInfoByFileIds(Long[] fileIds) + { + return sysFileInfoMapper.deleteSysFileInfoByFileIds(fileIds); + } + + /** + * 删除文件信息信息 + * + * @param fileId 文件信息主键 + * @return 结果 + */ + @Override + public int deleteSysFileInfoByFileId(Long fileId) + { + return sysFileInfoMapper.deleteSysFileInfoByFileId(fileId); + } +} diff --git a/boyue-file/boyue-file-common/src/main/java/com/boyue/file/storage/StorageBucket.java b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/storage/StorageBucket.java new file mode 100644 index 0000000..7dd4b4e --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/storage/StorageBucket.java @@ -0,0 +1,109 @@ +package com.boyue.file.storage; + +import java.io.InputStream; +import java.net.URL; +import java.util.List; + +import org.springframework.web.multipart.MultipartFile; + +import com.boyue.file.domain.SysFilePartETag; + +public interface StorageBucket { + + /** + * 获取文件实例 + * + * @param filePath + * @return + * @throws Exception + */ + StorageEntity get(String filepath) throws Exception; + + /** + * 上传文件 + * + * @param filePath + * @param file + * @throws Exception + */ + void put(String filePath, MultipartFile file) throws Exception; + + /** + * 删除文件 + * + * @param filePath + * @throws Exception + */ + void remove(String filePath) throws Exception; + + /** + * 生成预签名URL + * + * @param filePath + * @return + * @throws Exception + */ + URL generatePresignedUrl(String filePath, int expireTime) throws Exception; + + /** + * 获取文件的公开访问方式的URL + * + * @param filePath 文件路径 + * @return 公开访问URL + */ + URL generatePublicURL(String filePath) throws Exception; + + /** + * 获取存储渠道权限 + * + * @return public/private + */ + String getPermission(); + + /** + * 获取文件的默认访问方式的URL + * + * @param filePath + * @return + * @throws Exception + */ + default URL getUrl(String filePath) throws Exception { + if ("public".equals(getPermission())) { + return generatePublicURL(filePath); + } else { + return generatePresignedUrl(filePath, 3600); + } + }; + + /** + * 初始化分片上传 + * + * @param filePath 文件路径 + * @return 返回uploadId + */ + public String initMultipartUpload(String filePath) throws Exception; + + /** + * 上传分片 + * + * @param filePath 文件路径 + * @param uploadId 上传ID + * @param partNumber 分片序号 + * @param partSize 分片大小 + * @param inputStream 分片数据流 + * @return 分片的ETag + */ + public SysFilePartETag uploadPart(String filePath, String uploadId, int partNumber, long partSize, + InputStream inputStream) + throws Exception; + + /** + * 完成分片上传 + * + * @param filePath 文件路径 + * @param uploadId 上传ID + * @return 文件的最终路径 + */ + public String completeMultipartUpload(String filePath, String uploadId, List partETags) + throws Exception; +} diff --git a/boyue-file/boyue-file-common/src/main/java/com/boyue/file/storage/StorageEntity.java b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/storage/StorageEntity.java new file mode 100644 index 0000000..14513f7 --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/storage/StorageEntity.java @@ -0,0 +1,12 @@ +package com.boyue.file.storage; + +import java.io.InputStream; + +import lombok.Data; + +@Data +public class StorageEntity { + private InputStream inputStream; + private Long byteCount; + private String filePath; +} diff --git a/boyue-file/boyue-file-common/src/main/java/com/boyue/file/storage/StorageManagement.java b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/storage/StorageManagement.java new file mode 100644 index 0000000..d1cdd3d --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/storage/StorageManagement.java @@ -0,0 +1,25 @@ +package com.boyue.file.storage; + +import java.util.Map; + +import org.springframework.beans.factory.InitializingBean; + +public interface StorageManagement extends InitializingBean { + /** + * 获取存储桶 + * + * @param clientName 客户端名称 + * @return 存储桶 + */ + StorageBucket getBucket(String clientName); + + /** + * 获取存储桶 + * + * @param clientName 客户端名称 + * @param bucketName 存储桶名称 + * @return 存储桶 + */ + public Map getClient(); + +} diff --git a/boyue-file/boyue-file-common/src/main/java/com/boyue/file/storage/StorageManagements.java b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/storage/StorageManagements.java new file mode 100644 index 0000000..cb5de46 --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/storage/StorageManagements.java @@ -0,0 +1,32 @@ +package com.boyue.file.storage; + +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class StorageManagements { + @Autowired + private Map storageConfigs; + + public StorageManagement getStorageConfig(String clientName) { + return storageConfigs.get(clientName); + } + + public StorageBucket getStorageBucket(String storage, String clientName) { + StorageManagement config = getStorageConfig(storage); + if (config != null) { + return config.getBucket(clientName); + } + return null; + } + + public Map getStorageTypes() { + return storageConfigs; + } + + public void setStorageTypes(Map storageConfigs) { + this.storageConfigs = storageConfigs; + } +} diff --git a/boyue-file/boyue-file-common/src/main/java/com/boyue/file/storage/StorageService.java b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/storage/StorageService.java new file mode 100644 index 0000000..7e9d589 --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/storage/StorageService.java @@ -0,0 +1,122 @@ +package com.boyue.file.storage; + +import java.io.File; +import java.io.InputStream; +import java.util.List; + +import org.springframework.web.multipart.MultipartFile; + +import com.boyue.common.utils.DateUtils; +import com.boyue.common.utils.file.FileUtils; +import com.boyue.file.domain.SysFilePartETag; + +/** + * 文件操作接口 + */ +public interface StorageService { + + /** + * 上传文件 + * + * @param file 上传的文件 + * @return + * @throws Exception 比如读写文件出错时 + * + */ + default public String upload(MultipartFile file) throws Exception { + return upload(FileUtils.fastFilePath(file), file); + }; + + /** + * 上传文件(指定文件名称) + * + * @param file 上传的文件 + * @param fileName 指定上传文件的名称 + * @return + * @throws Exception 比如读写文件出错时 + * + */ + default public String upload(MultipartFile file, String fileName) throws Exception { + return upload(DateUtils.datePath() + File.separator + fileName, file); + }; + + /** + * 上传文件(指定文件路径) + * + * @param filePath 指定上传文件的路径 + * @param file 上传的文件 + * @return + * @throws Exception 比如读写文件出错时 + * + */ + public String upload(String filePath, MultipartFile file) throws Exception; + + /** + * 下载文件 + * + * @param filePath 文件路径 + * @return 返回文件输入流 + * @throws Exception 比如读写文件出错时 + * + */ + public InputStream downLoad(String filePath) throws Exception; + + /** + * 获取文件实体对象 + * + * @param filePath 文件路径 + * @return 文件对象 + * @throws Exception + */ + public StorageEntity getFile(String filePath) throws Exception; + + /** + * 删除文件 + * + * @param filePath 文件路径 + * @return 返回是否删除成功 + * @throws Exception 比如读写文件出错时 + * + */ + public boolean deleteFile(String filePath) throws Exception; + + /** + * 生成文件访问链接 + * + * @param filePath 文件路径 + * @return 返回文件访问链接 + * @throws Exception 比如读写文件出错时 + * + */ + public String generateUrl(String filePath) throws Exception; + + /** + * 初始化分片上传 + * + * @param filePath 文件路径 + * @return 返回uploadId + */ + public String initMultipartUpload(String filePath) throws Exception; + + /** + * 上传分片 + * + * @param filePath 文件路径 + * @param uploadId 上传ID + * @param partNumber 分片序号 + * @param partSize 分片大小 + * @param inputStream 分片数据流 + * @return 分片的ETag + */ + public String uploadPart(String filePath, String uploadId, int partNumber, long partSize, InputStream inputStream) + throws Exception; + + /** + * 完成分片上传 + * @param filePath 文件路径 + * @param uploadId 上传ID + * @return 文件的最终路径 + */ + public String completeMultipartUpload(String filePath, String uploadId, List partETags) + throws Exception; +} diff --git a/boyue-file/boyue-file-common/src/main/java/com/boyue/file/utils/FileOperateUtils.java b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/utils/FileOperateUtils.java new file mode 100644 index 0000000..d781289 --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/java/com/boyue/file/utils/FileOperateUtils.java @@ -0,0 +1,255 @@ +package com.boyue.file.utils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; + +import org.springframework.http.MediaType; +import org.springframework.web.multipart.MultipartFile; + +import com.boyue.common.config.BoYueConfig; +import com.boyue.common.constant.CacheConstants; +import com.boyue.common.utils.CacheUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.file.FileUtils; +import com.boyue.common.utils.file.MimeTypeUtils; +import com.boyue.common.utils.sign.Md5Utils; +import com.boyue.common.utils.spring.SpringUtils; +import com.boyue.file.domain.SysFilePartETag; +import com.boyue.file.storage.StorageEntity; +import com.boyue.file.storage.StorageService; + +import jakarta.servlet.http.HttpServletResponse; + +/** + * 文件上传工具类 + * + * @author boyue + */ +public class FileOperateUtils { + + private static StorageService fileService = SpringUtils.getBean("file:strategy:" + BoYueConfig.getFileServer()); + + /** + * 以默认配置进行文件上传 + * + * @param file 上传的文件 + * @return 文件路径 + * @throws Exception + */ + public static final String upload(MultipartFile file) throws IOException { + return upload(file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); + } + + /** + * 以默认配置进行文件上传 + * + * @param file 上传的文件 + * @param allowedExtension 允许的扩展名 + * @return 文件路径 + * @throws Exception + */ + public static final String upload(MultipartFile file, String[] allowedExtension) + throws IOException { + try { + String md5 = Md5Utils.getMd5(file); + String pathForMd5 = getFilePathForMd5(md5); + if (StringUtils.isNotEmpty(pathForMd5)) { + return pathForMd5; + } + FileUtils.assertAllowed(file, allowedExtension); + String filePath = fileService.upload(file); + saveFilePathAndMd5(filePath, md5); + return filePath; + } catch (Exception e) { + throw new IOException(e.getMessage(), e); + } + } + + /** + * 根据文件路径上传 + * + * @param filePath 上传文件的路径 + * @param file 上传的文件 + * @return 文件名称 + * @throws IOException + */ + public static final String upload(String filePath, MultipartFile file) throws Exception { + return upload(filePath, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); + } + + /** + * 根据文件路径上传 + * + * @param filePath 上传文件的路径 + * @param file 上传的文件 + * @param allowedExtension 允许的扩展名 + * @return 访问链接 + * @throws IOException + */ + public static final String upload(String filePath, MultipartFile file, String[] allowedExtension) + throws IOException { + try { + String md5 = Md5Utils.getMd5(file); + String pathForMd5 = getFilePathForMd5(md5); + if (StringUtils.isNotEmpty(pathForMd5)) { + return pathForMd5; + } + FileUtils.assertAllowed(file, allowedExtension); + String url = fileService.upload(filePath, file); + saveFilePathAndMd5(url, md5); + return url; + } catch (Exception e) { + throw new IOException(e.getMessage(), e); + } + } + + /** + * 根据文件路径下载 + * + * @param fileUrl 下载文件路径 + * @param outputStream 需要输出到的输出流 + * @return 文件名称 + * @throws IOException + */ + public static final void downLoad(String filePath, OutputStream outputStream) throws Exception { + InputStream inputStream = fileService.downLoad(filePath); + FileUtils.writeBytes(inputStream, outputStream); + } + + /** + * 根据文件路径下载 + * + * @param filepath 下载文件路径 + * @param response 相应 + * @return 文件名称 + * @throws IOException + */ + public static final void downLoad(String filePath, HttpServletResponse response) throws Exception { + StorageEntity fileEntity = fileService.getFile(filePath); + InputStream inputStream = fileEntity.getInputStream(); + OutputStream outputStream = response.getOutputStream(); + FileUtils.setAttachmentResponseHeader(response, FileUtils.getName(fileEntity.getFilePath())); + response.setContentLengthLong(fileEntity.getByteCount()); + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + FileUtils.writeBytes(inputStream, outputStream); + } + + /** + * 根据文件路径删除 + * + * @param filePath 下载文件路径 + * @return 是否成功 + * @throws IOException + */ + public static final boolean deleteFile(String filePath) throws Exception { + deleteFileAndMd5ByFilePath(filePath); + return fileService.deleteFile(filePath); + } + + /** + * 根据md5获取文件的路径 + * + * @param md5 文件的md5 + * @return 文件路径 + */ + public static String getFilePathForMd5(String md5) { + return CacheUtils.get(CacheConstants.FILE_MD5_PATH_KEY, md5, String.class); + } + + /** + * 根据md5获取文件的路径 + * + * @param md5 文件的md5 + * @return 文件路径 + */ + public static String getMd5ForFilePath(String filePath) { + return CacheUtils.get(CacheConstants.FILE_PATH_MD5_KEY, filePath, String.class); + } + + /** + * 保存文件的md5 + * + * @param filePath 文件的路径 + * @param md5 文件的md5 + */ + public static void saveFilePathAndMd5(String filePath, String md5) { + CacheUtils.put(CacheConstants.FILE_MD5_PATH_KEY, md5, filePath); + CacheUtils.put(CacheConstants.FILE_PATH_MD5_KEY, filePath, md5); + } + + /** + * 根据md5删除文件的缓存信息 + * + * @param md5 文件的md5 + */ + public static void deleteFileAndMd5ByMd5(String md5) { + String filePathByMd5 = getFilePathForMd5(md5); + if (StringUtils.isNotEmpty(filePathByMd5)) { + CacheUtils.remove(CacheConstants.FILE_MD5_PATH_KEY, md5); + CacheUtils.remove(CacheConstants.FILE_PATH_MD5_KEY, filePathByMd5); + } + } + + /** + * 根据文件路径删除文件的缓存信息 + * + * @param filePath 文件的路径 + */ + public static void deleteFileAndMd5ByFilePath(String filePath) { + String md5ByFilePath = getMd5ForFilePath(filePath); + if (StringUtils.isNotEmpty(md5ByFilePath)) { + CacheUtils.remove(CacheConstants.FILE_PATH_MD5_KEY, filePath); + CacheUtils.remove(CacheConstants.FILE_MD5_PATH_KEY, md5ByFilePath); + } + } + + /** + * 获取文件的访问链接 + * + * @param filePath 文件路径 + * @return 访问链接 + * @throws Exception + */ + public static String getURL(String filePath) throws Exception { + return fileService.generateUrl(filePath); + } + + /** + * 初始化分片上传 + * + * @param filePath 文件路径 + * @return 返回uploadId + */ + public static String initMultipartUpload(String filePath) throws Exception { + return fileService.initMultipartUpload(filePath); + } + + /** + * 上传分片 + * + * @param filePath 文件路径 + * @param uploadId 上传ID + * @param partNumber 分片序号 + * @param partSize 分片大小 + * @param inputStream 分片数据流 + * @return 分片的ETag + */ + public static String uploadPart(String filePath, String uploadId, int partNumber, long partSize, + InputStream inputStream) throws Exception { + return fileService.uploadPart(filePath, uploadId, partNumber, partSize, inputStream); + } + + /** + * 完成分片上传 + * + * @param filePath 文件路径 + * @param uploadId 上传ID + * @return 文件的最终路径 + */ + public static String completeMultipartUpload(String filePath, String uploadId, List partETags) + throws Exception { + return fileService.completeMultipartUpload(filePath, uploadId, partETags); + } +} diff --git a/boyue-file/boyue-file-common/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/boyue-file/boyue-file-common/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000..c803b19 --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,19 @@ +{ + "properties": [ + { + "name": "local.enable", + "type": "java.lang.Boolean", + "description": "是否开启local" + }, + { + "name": "local.primary", + "type": "java.lang.String", + "description": "默认存储名称" + }, + { + "name": "local.client", + "type": "java.util.Map", + "description": "储存桶" + } + ] +} \ No newline at end of file diff --git a/boyue-file/boyue-file-common/src/main/resources/mapper/file/SysFileInfoMapper.xml b/boyue-file/boyue-file-common/src/main/resources/mapper/file/SysFileInfoMapper.xml new file mode 100644 index 0000000..990824c --- /dev/null +++ b/boyue-file/boyue-file-common/src/main/resources/mapper/file/SysFileInfoMapper.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + select + sfi.file_id, + sfi.file_name, + sfi.file_path, + sfi.storage_type, + sfi.file_type, + sfi.file_size, + sfi.md5, + sfi.create_by, + sfi.create_time, + sfi.update_by, + sfi.update_time, + sfi.remark, + sfi.del_flag + from sys_file_info sfi + + + + + + + + insert into sys_file_info + + file_name, + file_path, + storage_type, + file_type, + file_size, + md5, + create_by, + create_time, + update_by, + update_time, + remark, + del_flag, + + + #{fileName}, + #{filePath}, + #{storageType}, + #{fileType}, + #{fileSize}, + #{md5}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + #{delFlag}, + + + + + update sys_file_info + + file_name = #{fileName}, + file_path = #{filePath}, + storage_type = #{storageType}, + file_type = #{fileType}, + file_size = #{fileSize}, + md5 = #{md5}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + del_flag = #{delFlag}, + + where sys_file_info.file_id = #{fileId} + + + + delete from sys_file_info where file_id = #{fileId} + + + + delete from sys_file_info where file_id in + + #{fileId} + + + \ No newline at end of file diff --git a/boyue-file/boyue-file-minio/pom.xml b/boyue-file/boyue-file-minio/pom.xml new file mode 100644 index 0000000..a0ee039 --- /dev/null +++ b/boyue-file/boyue-file-minio/pom.xml @@ -0,0 +1,33 @@ + + + + boyue-file + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-file-minio + + + 中间件 + + + + + + + com.boyue + boyue-file-common + + + + + io.minio + minio + + + + + diff --git a/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/config/MinioBucketProperties.java b/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/config/MinioBucketProperties.java new file mode 100644 index 0000000..ad81155 --- /dev/null +++ b/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/config/MinioBucketProperties.java @@ -0,0 +1,12 @@ +package com.boyue.file.minio.config; + +import lombok.Data; + +@Data +public class MinioBucketProperties { + private String permission; + private String url; + private String accessKey; + private String secretKey; + private String bucketName; +} diff --git a/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/config/MinioManagement.java b/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/config/MinioManagement.java new file mode 100644 index 0000000..edcd566 --- /dev/null +++ b/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/config/MinioManagement.java @@ -0,0 +1,117 @@ +package com.boyue.file.minio.config; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.http.impl.io.EmptyInputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import com.boyue.common.config.BoYueConfig; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.file.FileUtils; +import com.boyue.file.minio.domain.MinioBucket; +import com.boyue.file.storage.StorageManagement; + +import io.minio.BucketExistsArgs; +import io.minio.MinioClient; +import io.minio.PutObjectArgs; + +@Configuration("minio") +@ConditionalOnProperty(prefix = "minio", name = { "enable" }, havingValue = "true", matchIfMissing = false) +@ConfigurationProperties("minio") +public class MinioManagement implements StorageManagement { + private static final Logger logger = LoggerFactory.getLogger(MinioManagement.class); + private Map client; + private String primary; + private Map targetMinioBucket = new HashMap<>(); + private MinioBucket primaryBucket; + + @Override + public void afterPropertiesSet() throws Exception { + if (client == null || client.isEmpty()) { + throw new RuntimeException("Client properties cannot be null or empty"); + } + client.forEach((name, props) -> { + try { + targetMinioBucket.put(name, createMinioClient(name, props)); + } catch (Exception e) { + logger.error("Failed to create MinIO client for {}: {}", name, e.getMessage(), e); + } + }); + + if (targetMinioBucket.get(primary) == null) { + throw new RuntimeException("Primary client " + primary + " does not exist"); + } + primaryBucket = targetMinioBucket.get(primary); + } + + private void validateMinioBucket(MinioBucket minioBucket) { + BucketExistsArgs bucketExistArgs = BucketExistsArgs.builder().bucket(minioBucket.getBucketName()).build(); + boolean b = false; + try { + b = minioBucket.getClient().bucketExists(bucketExistArgs); + PutObjectArgs putObjectArgs = PutObjectArgs.builder() + .object(FileUtils.getRelativePath(BoYueConfig.getProfile()) + "/") + .stream(EmptyInputStream.nullInputStream(), 0, -1).bucket(minioBucket.getBucketName()).build(); + minioBucket.getClient().putObject(putObjectArgs); + } catch (Exception e) { + logger.error("数据桶:{} - 链接失败", minioBucket.getName()); + throw new RuntimeException(e.getMessage()); + } + if (!b) { + throw new RuntimeException("Bucket " + minioBucket.getBucketName() + " does not exist"); + } + } + + private MinioBucket createMinioClient(String name, MinioBucketProperties props) { + MinioClient client; + if (StringUtils.isEmpty(props.getAccessKey())) { + client = MinioClient.builder() + .endpoint(props.getUrl()) + .build(); + } else { + client = MinioClient.builder() + .endpoint(props.getUrl()) + .credentials(props.getAccessKey(), props.getSecretKey()) + .build(); + } + MinioBucket minioBucket = MinioBucket.builder() + .client(client) + .bucketName(props.getBucketName()) + .permission(props.getPermission()) + .url(props.getUrl()) + .build(); + validateMinioBucket(minioBucket); + logger.info("数据桶:{} - 链接成功", name); + return minioBucket; + } + + @Override + public MinioBucket getBucket(String clent) { + return targetMinioBucket.get(clent); + } + + public MinioBucket getPrimaryBucket() { + return this.primaryBucket; + } + + public Map getClient() { + return client; + } + + public void setClient(Map client) { + this.client = client; + } + + public String getPrimary() { + return primary; + } + + public void setPrimary(String primary) { + this.primary = primary; + } +} diff --git a/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/domain/MinioBucket.java b/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/domain/MinioBucket.java new file mode 100644 index 0000000..880acae --- /dev/null +++ b/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/domain/MinioBucket.java @@ -0,0 +1,224 @@ +package com.boyue.file.minio.domain; + +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.util.Comparator; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; + +import org.springframework.web.multipart.MultipartFile; + +import com.boyue.common.core.text.Convert; +import com.boyue.file.domain.SysFilePartETag; +import com.boyue.file.minio.exception.MinioClientErrorException; +import com.boyue.file.storage.StorageBucket; + +import io.minio.ComposeObjectArgs; +import io.minio.ComposeSource; +import io.minio.GetObjectArgs; +import io.minio.GetObjectResponse; +import io.minio.GetPresignedObjectUrlArgs; +import io.minio.MinioClient; +import io.minio.PutObjectArgs; +import io.minio.RemoveObjectArgs; +import io.minio.http.Method; +import lombok.Builder; +import lombok.extern.slf4j.Slf4j; + +@Builder +@Slf4j +public class MinioBucket implements StorageBucket { + + private String url; + private String permission; + private MinioClient client; + private String bucketName; + + private static final ConcurrentHashMap uploadingParts = new ConcurrentHashMap<>(); + + @Override + public void put(String filePath, MultipartFile file) { + try (InputStream inputStream = file.getInputStream()) { + PutObjectArgs putObjectArgs = PutObjectArgs.builder() + .contentType(file.getContentType()) + .stream(inputStream, file.getSize(), -1) + .bucket(bucketName) + .object(filePath) + .build(); + client.putObject(putObjectArgs); + } catch (Exception e) { + throw new MinioClientErrorException(e.getMessage()); + } + } + + @Override + public void remove(String filePath) throws Exception { + RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder() + .object(filePath) + .bucket(bucketName) + .build(); + client.removeObject(removeObjectArgs); + } + + @Override + public MinioEntityVO get(String filePath) throws Exception { + GetObjectArgs getObjectArgs = GetObjectArgs.builder() + .object(filePath) + .bucket(bucketName) + .build(); + GetObjectResponse response = client.getObject(getObjectArgs); + MinioEntityVO minioFileVO = new MinioEntityVO(); + minioFileVO.setInputStream(response); + minioFileVO.setByteCount(Convert.toLong(response.headers().get("Content-Length"), null)); + minioFileVO.setFilePath(filePath); + minioFileVO.setObject(response.object()); + minioFileVO.setRegion(response.region()); + minioFileVO.setBuket(response.bucket()); + minioFileVO.setHeaders(response.headers()); + return minioFileVO; + } + + @Override + public URL generatePresignedUrl(String filePath, int expireTime) throws Exception { + GetPresignedObjectUrlArgs request = GetPresignedObjectUrlArgs.builder() + .method(Method.GET) + .bucket(bucketName) + .object(filePath) + .expiry(expireTime, TimeUnit.SECONDS) + .build(); + String urlString = client.getPresignedObjectUrl(request); + return URI.create(urlString).toURL(); + } + + @Override + public URL generatePublicURL(String filePath) throws Exception { + StringBuilder sb = new StringBuilder(); + sb.append(getUrl()) + .append("/").append(getBucketName()) + .append("/").append(filePath.replace("\\", "/")); + return URI.create(sb.toString()).toURL(); + } + + /** + * 初始化分片上传 + */ + public String initMultipartUpload(String filePath) throws Exception { + try { + String uploadId = UUID.randomUUID().toString().replace("-", "").toUpperCase(); + return uploadId; + } catch (Exception e) { + log.error("初始化失败: 文件={}, 错误={}", filePath, e.getMessage()); + throw new MinioClientErrorException("初始化失败", e); + } + } + + /** + * 上传单个分片 + */ + public SysFilePartETag uploadPart(String filePath, String uploadId, int partNumber, long partSize, + InputStream inputStream) + throws Exception { + // 生成唯一的上传键 + String uploadKey = String.format("%s-%s-%d", filePath, uploadId, partNumber); + AtomicBoolean isUploading = uploadingParts.computeIfAbsent(uploadKey, k -> new AtomicBoolean(false)); + // 使用 CAS 检查是否已经在上传中 + if (!isUploading.compareAndSet(false, true)) { + throw new MinioClientErrorException("分片正在上传中: " + uploadKey); + } + try { + // 构建分片存储路径 + String partPath = String.format("%s.%s.part.%d", filePath, uploadId, partNumber); + // 构造上传请求参数 + PutObjectArgs args = PutObjectArgs.builder() + .bucket(bucketName) + .object(partPath) + .stream(inputStream, partSize, -1) + .build(); + // 执行上传操作并获取 ETag + String etag = client.putObject(args).etag().replace("\"", "").toUpperCase(); + return new SysFilePartETag(partNumber, etag); + } catch (Exception e) { + log.error("分片上传失败: 文件={}, 分片={}, 错误={}", filePath, partNumber, e.getMessage()); + throw new MinioClientErrorException("上传分片失败", e); + } finally { + isUploading.set(false);// 标记为上传完成,并清理状态 + uploadingParts.remove(uploadKey); + } + } + + /** + * 完成分片上传并合并文件 + */ + public String completeMultipartUpload(String filePath, String uploadId, List filePartETags) + throws Exception { + if (filePartETags == null || filePartETags.isEmpty()) { + throw new IllegalArgumentException("分片信息不能为空"); + } + + // 按分片序号排序 + List partPaths = filePartETags.stream() + .sorted(Comparator.comparingInt(p -> p.getPartNumber())) + .map(part -> String.format("%s.%s.part.%d", filePath, uploadId, part.getPartNumber())) + .collect(Collectors.toList()); + + List sources = partPaths.stream() + .map(path -> ComposeSource.builder() + .bucket(bucketName) + .object(path) + .build()) + .toList(); + + client.composeObject(ComposeObjectArgs.builder() + .bucket(bucketName) + .object(filePath) + .sources(sources) + .build()); + + for (String partPath : partPaths) { + try { + client.removeObject(RemoveObjectArgs.builder() + .bucket(bucketName) + .object(partPath) + .build()); + } catch (Exception e) { + log.warn("清理分片失败: {}", e.getMessage()); + } + } + log.info("分片合并完成: 文件={}, uploadId={}, 分片数={}", filePath, uploadId, filePartETags.size()); + return filePath; + } + + public String getName() { + return bucketName; + } + + public MinioClient getClient() { + return client; + } + + public String getBucketName() { + return bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } + + public void setClient(MinioClient client) { + this.client = client; + } + + public String getPermission() { + return permission; + } + + public String getUrl() { + return url; + } + +} diff --git a/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/domain/MinioEntityVO.java b/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/domain/MinioEntityVO.java new file mode 100644 index 0000000..76e0c6d --- /dev/null +++ b/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/domain/MinioEntityVO.java @@ -0,0 +1,45 @@ +package com.boyue.file.minio.domain; + +import com.boyue.file.storage.StorageEntity; + +import okhttp3.Headers; + +public class MinioEntityVO extends StorageEntity { + private String object; + private Headers headers; + private String buket; + private String region; + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public Headers getHeaders() { + return headers; + } + + public void setHeaders(Headers headers) { + this.headers = headers; + } + + public String getBuket() { + return buket; + } + + public void setBuket(String buket) { + this.buket = buket; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + +} diff --git a/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/exception/MinioClientErrorException.java b/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/exception/MinioClientErrorException.java new file mode 100644 index 0000000..4907f39 --- /dev/null +++ b/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/exception/MinioClientErrorException.java @@ -0,0 +1,16 @@ +package com.boyue.file.minio.exception; + +/** + * 当与MinIO客户端交互过程中发生错误时抛出此异常。 + */ +public class MinioClientErrorException extends RuntimeException { + + public MinioClientErrorException(String msg) { + super(msg); + } + + public MinioClientErrorException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/exception/MinioClientNotFundException.java b/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/exception/MinioClientNotFundException.java new file mode 100644 index 0000000..096d617 --- /dev/null +++ b/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/exception/MinioClientNotFundException.java @@ -0,0 +1,15 @@ +package com.boyue.file.minio.exception; + +/** + * 当尝试获取MinIO客户端实例但未能找到相应的配置或客户端实例时抛出此异常。 + */ +public class MinioClientNotFundException extends RuntimeException { + + public MinioClientNotFundException(String msg) { + super(msg); + } + + public MinioClientNotFundException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/service/MinioFileService.java b/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/service/MinioFileService.java new file mode 100644 index 0000000..65e6d78 --- /dev/null +++ b/boyue-file/boyue-file-minio/src/main/java/com/boyue/file/minio/service/MinioFileService.java @@ -0,0 +1,87 @@ +package com.boyue.file.minio.service; + +import java.io.InputStream; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import com.boyue.file.domain.SysFilePartETag; +import com.boyue.file.minio.config.MinioManagement; +import com.boyue.file.minio.domain.MinioBucket; +import com.boyue.file.storage.StorageEntity; +import com.boyue.file.storage.StorageService; + +/** + * Minio文件操作实现类 + */ +@Component("file:strategy:minio") +@ConditionalOnProperty(prefix = "minio", name = { "enable" }, havingValue = "true", matchIfMissing = false) +public class MinioFileService implements StorageService { + + @Autowired + private MinioManagement minioConfig; + + @Override + public String upload(String filePath, MultipartFile file) throws Exception { + MinioBucket minioBucket = minioConfig.getPrimaryBucket(); + minioBucket.put(filePath, file); + return generateUrl(filePath); + } + + @Override + public InputStream downLoad(String filePath) throws Exception { + MinioBucket minioBucket = minioConfig.getPrimaryBucket(); + return minioBucket.get(filePath).getInputStream(); + } + + @Override + public StorageEntity getFile(String filePath) throws Exception { + MinioBucket minioBucket = minioConfig.getPrimaryBucket(); + return minioBucket.get(filePath); + } + + @Override + public boolean deleteFile(String filePath) throws Exception { + MinioBucket minioBucket = minioConfig.getPrimaryBucket(); + minioBucket.remove(filePath); + return true; + } + + @Override + public String generateUrl(String filePath) throws Exception { + MinioBucket minioBucket = minioConfig.getPrimaryBucket(); + if ("public".equals(minioBucket.getPermission())) { + return minioBucket.generatePublicURL(filePath).toString(); + } else { + return minioBucket.generatePresignedUrl(filePath, 3600).toString(); + } + } + + @Override + public String initMultipartUpload(String filePath) throws Exception { + MinioBucket minioBucket = minioConfig.getPrimaryBucket(); + return minioBucket.initMultipartUpload(filePath); + } + + @Override + public String uploadPart(String filePath, String uploadId, int partNumber, long partSize, InputStream inputStream) + throws Exception { + MinioBucket minioBucket = minioConfig.getPrimaryBucket(); + return minioBucket.uploadPart(filePath, uploadId, partNumber, partSize, inputStream).getETag(); + } + + @Override + public String completeMultipartUpload(String filePath, String uploadId, List partETags) + throws Exception { + if (partETags == null || partETags.isEmpty()) { + throw new IllegalArgumentException("分片标识列表不能为空"); + } + + MinioBucket minioBucket = minioConfig.getPrimaryBucket(); + return minioBucket.completeMultipartUpload(filePath, uploadId, partETags); + } + +} \ No newline at end of file diff --git a/boyue-file/boyue-file-minio/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/boyue-file/boyue-file-minio/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000..445dcfa --- /dev/null +++ b/boyue-file/boyue-file-minio/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,19 @@ +{ + "properties": [ + { + "name": "minio.enable", + "type": "java.lang.Boolean", + "description": "是否开启minio" + }, + { + "name": "minio.primary", + "type": "java.lang.String", + "description": "默认存储名称" + }, + { + "name": "minio.client", + "type": "java.util.Map", + "description": "储存桶" + } + ] +} \ No newline at end of file diff --git a/boyue-file/boyue-file-oss-alibaba/pom.xml b/boyue-file/boyue-file-oss-alibaba/pom.xml new file mode 100644 index 0000000..cf5b12c --- /dev/null +++ b/boyue-file/boyue-file-oss-alibaba/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + boyue-file + com.boyue + 3.8.9-G + + com.boyue + boyue-file-oss-alibaba + oss中间件 + + + + + + com.boyue + boyue-file-common + + + + + com.aliyun.oss + aliyun-sdk-oss + + + diff --git a/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/config/AliOssBucketProperties.java b/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/config/AliOssBucketProperties.java new file mode 100644 index 0000000..4bfefc3 --- /dev/null +++ b/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/config/AliOssBucketProperties.java @@ -0,0 +1,12 @@ +package com.boyue.file.oss.alibaba.config; + +import lombok.Data; + +@Data +public class AliOssBucketProperties { + private String permission; + private String endpoint; + private String accessKeyId; + private String accessKeySecret; + private String bucketName; +} \ No newline at end of file diff --git a/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/config/AliOssManagement.java b/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/config/AliOssManagement.java new file mode 100644 index 0000000..919f618 --- /dev/null +++ b/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/config/AliOssManagement.java @@ -0,0 +1,113 @@ +package com.boyue.file.oss.alibaba.config; + +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import com.aliyun.oss.ClientException; +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import com.aliyun.oss.OSSException; +import com.boyue.file.oss.alibaba.domain.AliOssBucket; +import com.boyue.file.storage.StorageManagement; + +/** + * 配置类用于管理阿里云OSS客户端实例及其相关属性。 + */ +@Configuration("oss") +@ConditionalOnProperty(prefix = "oss", name = "enable", havingValue = "true", matchIfMissing = false) +@ConfigurationProperties(prefix = "oss") +public class AliOssManagement implements StorageManagement { + private static final Logger logger = LoggerFactory.getLogger(AliOssManagement.class); + private Map client; + private String primary; + private Map targetAliOssBucket = new HashMap<>(); + private AliOssBucket primaryBucket; + + @Override + public void afterPropertiesSet() throws Exception { + if (client == null || client.isEmpty()) { + throw new RuntimeException("Client properties cannot be null or empty"); + } + + client.forEach((name, props) -> { + try { + AliOssBucket aliOssBucket = createOssClient(name, props); + targetAliOssBucket.put(name, aliOssBucket); + } catch (Exception e) { + logger.error("Failed to create OSS client for {}: {}", name, e.getMessage(), e); + } + }); + + if (targetAliOssBucket.get(primary) == null) { + throw new RuntimeException("Primary client " + primary + " does not exist"); + } + primaryBucket = targetAliOssBucket.get(primary); + } + + private void validateOssBucket(AliOssBucket aliOssBucket) { + OSS ossClient = aliOssBucket.getOssClient(); + String bucketName = aliOssBucket.getBucketName(); + try { + if (!ossClient.doesBucketExist(bucketName)) { + throw new RuntimeException("Bucket " + bucketName + " does not exist"); + } + } catch (OSSException oe) { + logger.error("OSSException: " + oe.getMessage(), oe); + throw new RuntimeException("OSS error: " + oe.getMessage()); + } catch (ClientException ce) { + logger.error("ClientException: " + ce.getMessage(), ce); + throw new RuntimeException("Client error: " + ce.getMessage()); + } catch (Exception e) { + logger.error("Exception: " + e.getMessage(), e); + throw new RuntimeException("Error validating OSS bucket: " + e.getMessage()); + } + } + + private AliOssBucket createOssClient(String name, AliOssBucketProperties props) { + if (props == null || props.getEndpoint() == null || props.getAccessKeyId() == null || + props.getAccessKeySecret() == null || props.getBucketName() == null) { + throw new IllegalArgumentException("AliOssProperties or its required fields cannot be null"); + } + + OSS client = new OSSClientBuilder().build(props.getEndpoint(), props.getAccessKeyId(), + props.getAccessKeySecret()); + AliOssBucket ossBucket = AliOssBucket.builder() + .ossClient(client) + .bucketName(props.getBucketName()) + .build(); + validateOssBucket(ossBucket); + logger.info("数据桶:{} - 链接成功", name); + return ossBucket; + } + + public AliOssBucket getPrimaryBucket() { + return this.primaryBucket; + } + + @Override + public AliOssBucket getBucket(String client) { + return targetAliOssBucket.get(client); + } + + public Map getClient() { + return client; + } + + public void setClient(Map client) { + this.client = client; + } + + public String getPrimary() { + return primary; + } + + public void setPrimary(String primary) { + this.primary = primary; + } +} diff --git a/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/domain/AliOssBucket.java b/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/domain/AliOssBucket.java new file mode 100644 index 0000000..f7be07d --- /dev/null +++ b/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/domain/AliOssBucket.java @@ -0,0 +1,176 @@ +package com.boyue.file.oss.alibaba.domain; + +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.util.Comparator; +import java.util.Date; +import java.util.List; + +import org.springframework.web.multipart.MultipartFile; + +import com.aliyun.oss.OSS; +import com.aliyun.oss.ServiceException; +import com.aliyun.oss.model.AbortMultipartUploadRequest; +import com.aliyun.oss.model.CompleteMultipartUploadRequest; +import com.aliyun.oss.model.GeneratePresignedUrlRequest; +import com.aliyun.oss.model.GetObjectRequest; +import com.aliyun.oss.model.InitiateMultipartUploadRequest; +import com.aliyun.oss.model.OSSObject; +import com.aliyun.oss.model.ObjectMetadata; +import com.aliyun.oss.model.PartETag; +import com.aliyun.oss.model.PutObjectRequest; +import com.aliyun.oss.model.UploadPartRequest; +import com.boyue.file.domain.SysFilePartETag; +import com.boyue.file.oss.alibaba.exception.AliOssClientErrorException; +import com.boyue.file.storage.StorageBucket; + +import lombok.Builder; +import lombok.extern.slf4j.Slf4j; + +@Builder +@Slf4j +public class AliOssBucket implements StorageBucket { + + private String bucketName; + private OSS ossClient; + private String permission; + private String endpoint; + + @Override + public void put(String filePath, MultipartFile file) throws Exception { + try { + InputStream inputStream = file.getInputStream(); + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentType(file.getContentType()); + metadata.setContentLength(inputStream.available()); + PutObjectRequest putRequest = new PutObjectRequest(bucketName, filePath, inputStream, metadata); + this.ossClient.putObject(putRequest); + } catch (Exception e) { + log.error("Error uploading file to OSS: {}", e.getMessage(), e); + throw new AliOssClientErrorException("Error uploading file to OSS: " + e.getMessage(), e); + } + } + + @Override + public void remove(String filePath) throws Exception { + ossClient.deleteObject(bucketName, filePath); + } + + @Override + public AliOssEntityVO get(String filePath) throws Exception { + GetObjectRequest request = new GetObjectRequest(this.bucketName, filePath); + OSSObject ossObject = this.ossClient.getObject(request); + if (ossObject == null) { + throw new Exception("Failed to retrieve object from OSS."); + } + AliOssEntityVO fileVO = new AliOssEntityVO(); + fileVO.setInputStream(ossObject.getObjectContent()); + fileVO.setKey(ossObject.getKey()); + fileVO.setBucketName(ossObject.getBucketName()); + fileVO.setByteCount(ossObject.getObjectMetadata().getContentLength()); + fileVO.setFilePath(filePath); + return fileVO; + } + + @Override + public URL generatePresignedUrl(String filePath, int expireTime) { + GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, filePath); + Date expiration = new Date(System.currentTimeMillis() + expireTime * 1000); // 设置过期时间为1小时 + request.setExpiration(expiration); + return ossClient.generatePresignedUrl(request); + } + + @Override + public URL generatePublicURL(String filePath) throws Exception { + StringBuilder sb = new StringBuilder(); + sb.append("https://").append(getBucketName()) + .append(".").append(getEndpoint()) + .append("/").append(filePath.replace("\\", "/")); + return URI.create(sb.toString()).toURL(); + } + + /** + * 初始化分片上传 + */ + public String initMultipartUpload(String filePath) throws Exception { + InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucketName, filePath); + String uploadId = ossClient.initiateMultipartUpload(initRequest).getUploadId(); + return uploadId; + } + + /** + * 上传单个分片 + */ + public SysFilePartETag uploadPart(String filePath, String uploadId, int partNumber, long partSize, + InputStream inputStream) + throws Exception { + UploadPartRequest uploadPartRequest = new UploadPartRequest(); + uploadPartRequest.setBucketName(bucketName); + uploadPartRequest.setKey(filePath); + uploadPartRequest.setUploadId(uploadId); + uploadPartRequest.setInputStream(inputStream); + uploadPartRequest.setPartSize(partSize); + uploadPartRequest.setPartNumber(partNumber); + PartETag partETag = ossClient.uploadPart(uploadPartRequest).getPartETag(); + return new SysFilePartETag(partETag.getPartNumber(), partETag.getETag(), partETag.getPartSize(), + partETag.getPartCRC()); + } + + /** + * 完成分片上传 + */ + public String completeMultipartUpload(String filePath, String uploadId, List sysFilePartETags) + throws Exception { + if (sysFilePartETags == null || sysFilePartETags.isEmpty()) { + throw new ServiceException("分片ETag列表不能为空"); + } + List partETags = sysFilePartETags.stream() + .map(part -> new PartETag(part.getPartNumber(), part.getETag(), part.getPartSize(), part.getPartCRC())) + .toList(); + // 确保分片按顺序排列 + partETags.sort(Comparator.comparingInt(PartETag::getPartNumber)); + try { + CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest(bucketName, filePath, + uploadId, partETags); + ossClient.completeMultipartUpload(completeRequest); + log.info("分片上传已完成并合并: 文件={}, uploadId={}, 分片数={}", + filePath, uploadId, partETags.size()); + return filePath; + } catch (Exception e) { + log.error("合并分片失败: 文件={}, uploadId={}, 错误={}", + filePath, uploadId, e.getMessage()); + try { + ossClient.abortMultipartUpload(new AbortMultipartUploadRequest(bucketName, filePath, uploadId)); + } catch (Exception abortEx) { + log.error("取消分片上传失败: {}", abortEx.getMessage()); + } + throw new AliOssClientErrorException("合并分片失败: " + e.getMessage(), e); + } + } + + public OSS getOssClient() { + return ossClient; + } + + public void setOssClient(OSS ossClient) { + this.ossClient = ossClient; + } + + public String getBucketName() { + return bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } + + public String getPermission() { + return permission; + } + + public String getEndpoint() { + return endpoint; + } + +} \ No newline at end of file diff --git a/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/domain/AliOssEntityVO.java b/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/domain/AliOssEntityVO.java new file mode 100644 index 0000000..c3a9faa --- /dev/null +++ b/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/domain/AliOssEntityVO.java @@ -0,0 +1,34 @@ +package com.boyue.file.oss.alibaba.domain; + +import com.aliyun.oss.model.ObjectMetadata; +import com.boyue.file.storage.StorageEntity; + +public class AliOssEntityVO extends StorageEntity { + private String key; + private String bucketName; + private ObjectMetadata metadata; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getBucketName() { + return bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } + + public ObjectMetadata getMetadata() { + return metadata; + } + + public void setMetadata(ObjectMetadata metadata) { + this.metadata = metadata; + } +} \ No newline at end of file diff --git a/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/exception/AliOssClientErrorException.java b/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/exception/AliOssClientErrorException.java new file mode 100644 index 0000000..18918c9 --- /dev/null +++ b/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/exception/AliOssClientErrorException.java @@ -0,0 +1,11 @@ +package com.boyue.file.oss.alibaba.exception; + +public class AliOssClientErrorException extends RuntimeException{ + public AliOssClientErrorException(String msg){ + super(msg); + } + + public AliOssClientErrorException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/exception/AliOssClientNotFundException.java b/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/exception/AliOssClientNotFundException.java new file mode 100644 index 0000000..35764fb --- /dev/null +++ b/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/exception/AliOssClientNotFundException.java @@ -0,0 +1,27 @@ +package com.boyue.file.oss.alibaba.exception; + +/** + * 当尝试获取阿里云OSS客户端实例但未能找到相应的配置或客户端实例时抛出此异常。 + * 此异常表明系统中存在配置问题或者客户端初始化失败的问题。 + */ +public class AliOssClientNotFundException extends RuntimeException { + + /** + * 使用指定的详细信息创建一个新的 {@code AliOssClientNotFundException} 实例。 + * + * @param msg 描述异常原因的信息。 + */ + public AliOssClientNotFundException(String msg) { + super(msg); + } + + /** + * 使用指定的详细信息和导致此异常的原因创建一个新的 {@code AliOssClientNotFundException} 实例。 + * + * @param message 描述异常原因的信息。 + * @param cause 导致此异常的根本原因。 + */ + public AliOssClientNotFundException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/service/AliOssFileService.java b/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/service/AliOssFileService.java new file mode 100644 index 0000000..7c9fb61 --- /dev/null +++ b/boyue-file/boyue-file-oss-alibaba/src/main/java/com/boyue/file/oss/alibaba/service/AliOssFileService.java @@ -0,0 +1,93 @@ +package com.boyue.file.oss.alibaba.service; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import com.boyue.file.domain.SysFilePartETag; +import com.boyue.file.oss.alibaba.config.AliOssManagement; +import com.boyue.file.oss.alibaba.domain.AliOssBucket; +import com.boyue.file.storage.StorageEntity; +import com.boyue.file.storage.StorageService; + +/** + * oss文件操作实现类 + */ +@Component("file:strategy:oss") +@ConditionalOnProperty(prefix = "oss", name = { "enable" }, havingValue = "true", matchIfMissing = false) +public class AliOssFileService implements StorageService { + + @Autowired + private AliOssManagement aliOssConfig; + + @Override + public String upload(String filePath, MultipartFile file) throws Exception { + AliOssBucket aliOssBucket = aliOssConfig.getPrimaryBucket(); + aliOssBucket.put(filePath, file); + return generateUrl(filePath); + } + + @Override + public InputStream downLoad(String filePath) throws Exception { + AliOssBucket aliOssBucket = aliOssConfig.getPrimaryBucket(); + return aliOssBucket.get(filePath).getInputStream(); + } + + @Override + public StorageEntity getFile(String filePath) throws Exception { + AliOssBucket aliOssBucket = aliOssConfig.getPrimaryBucket(); + return aliOssBucket.get(filePath); + }; + + @Override + public boolean deleteFile(String filePath) throws Exception { + AliOssBucket aliOssBucket = aliOssConfig.getPrimaryBucket(); + aliOssBucket.remove(filePath); + return true; + } + + @Override + public String generateUrl(String filePath) throws Exception { + AliOssBucket aliOssBucket = aliOssConfig.getPrimaryBucket(); + if ("public".equals(aliOssBucket.getPermission())) { + return aliOssBucket.generatePublicURL(filePath).toString(); + } else { + return aliOssBucket.generatePresignedUrl(filePath, 3600).toString(); + } + } + + @Override + public String initMultipartUpload(String filePath) throws Exception { + return aliOssConfig.getPrimaryBucket().initMultipartUpload(filePath); + } + + @Override + public String uploadPart(String filePath, String uploadId, int partNumber, long partSize, InputStream inputStream) + throws Exception { + AliOssBucket bucket = aliOssConfig.getPrimaryBucket(); + return bucket.uploadPart(filePath, uploadId, partNumber, partSize, inputStream).getETag(); + } + + @Override + public String completeMultipartUpload(String filePath, String uploadId, List partETags) + throws Exception { + if (partETags == null || partETags.isEmpty()) { + throw new IllegalArgumentException("分片ETag列表不能为空"); + } + + // 将Map转换为PartETag对象 + List ossPartETags = new ArrayList<>(); + for (SysFilePartETag part : partETags) { + int partNumber = ((Number) part.getPartNumber()).intValue(); + String etag = part.getETag(); + ossPartETags.add(new SysFilePartETag(partNumber, etag)); + } + return aliOssConfig.getPrimaryBucket().completeMultipartUpload(filePath, uploadId, ossPartETags); + } + +} \ No newline at end of file diff --git a/boyue-file/boyue-file-oss-alibaba/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/boyue-file/boyue-file-oss-alibaba/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000..c75c3b4 --- /dev/null +++ b/boyue-file/boyue-file-oss-alibaba/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,19 @@ +{ + "properties": [ + { + "name": "oss.enable", + "type": "java.lang.Boolean", + "description": "是否开启oss" + }, + { + "name": "oss.primary", + "type": "java.lang.String", + "description": "默认存储名称" + }, + { + "name": "oss.client", + "type": "java.util.Map", + "description": "储存桶" + } + ] +} \ No newline at end of file diff --git a/boyue-file/boyue-file-starter/pom.xml b/boyue-file/boyue-file-starter/pom.xml new file mode 100644 index 0000000..3ac117f --- /dev/null +++ b/boyue-file/boyue-file-starter/pom.xml @@ -0,0 +1,29 @@ + + + + boyue-file + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-file-starter + + + 文件 + + + + + com.boyue + boyue-file-oss-alibaba + + + + com.boyue + boyue-file-minio + + + + diff --git a/boyue-file/boyue-file-starter/src/main/java/com/boyue/file/controller/FileController.java b/boyue-file/boyue-file-starter/src/main/java/com/boyue/file/controller/FileController.java new file mode 100644 index 0000000..1163a2f --- /dev/null +++ b/boyue-file/boyue-file-starter/src/main/java/com/boyue/file/controller/FileController.java @@ -0,0 +1,314 @@ +package com.boyue.file.controller; + +import java.io.OutputStream; +import java.net.URLConnection; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import com.boyue.common.annotation.Anonymous; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.file.FileUtils; +import com.boyue.common.utils.sign.Md5Utils; +import com.boyue.file.domain.SysFileInfo; +import com.boyue.file.domain.SysFilePartETag; +import com.boyue.file.service.ISysFileInfoService; +import com.boyue.file.storage.StorageBucket; +import com.boyue.file.storage.StorageEntity; +import com.boyue.file.storage.StorageManagement; +import com.boyue.file.storage.StorageManagements; +import com.boyue.file.utils.FileOperateUtils; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Tag(name = "默认文件存储") +@RestController +@RequestMapping("/file") +public class FileController { + + @Autowired + private ISysFileInfoService sysFileInfoService; + + @Autowired + StorageManagements storageManagement; + + /** + * 获取所有可用存储渠道及其client列表 + */ + @GetMapping("/client-list") + public AjaxResult getClientList() { + Map> result = new HashMap<>(); + Map configs = storageManagement.getStorageTypes(); + for (String storageType : configs.keySet()) { + StorageManagement config = configs.get(storageType); + result.put(storageType, new ArrayList<>(config.getClient().keySet())); + } + return AjaxResult.success(result); + } + + /** + * 统一上传接口:/file/{storageType}/{clientName}/upload + */ + @PostMapping("/{storageType}/{clientName}/upload") + public AjaxResult uploadUnified( + @PathVariable("storageType") String storageType, + @PathVariable("clientName") String clientName, + @RequestParam("file") MultipartFile file) { + try { + String md5 = Md5Utils.getMd5(file); + String fileType = null; + if (file.getOriginalFilename() != null && file.getOriginalFilename().contains(".")) { + fileType = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.') + 1); + } + String filePath = "upload/" + System.currentTimeMillis() + "_" + file.getOriginalFilename(); + StorageBucket storageBucket = storageManagement.getStorageBucket(storageType, clientName); + storageBucket.put(filePath, file); + String url = storageBucket.getUrl(filePath).toString(); + SysFileInfo info = new SysFileInfo(); + info.setFileName(file.getOriginalFilename()); + info.setFilePath(filePath); + info.setStorageType(storageType); + info.setFileType(fileType); + info.setFileSize(file.getSize()); + info.setMd5(md5); + sysFileInfoService.insertSysFileInfo(info); + AjaxResult ajax = AjaxResult.success(); + ajax.put("url", url); + ajax.put("info", info); + return ajax; + } catch (Exception e) { + return AjaxResult.error(e.getMessage()); + } + } + + /** + * 统一下载接口:/file/{storageType}/{clientName}/download?filePath=xxx + */ + @GetMapping("/{storageType}/{clientName}/download") + public void downloadUnified( + @PathVariable("storageType") String storageType, + @PathVariable("clientName") String clientName, + @RequestParam("filePath") String filePath, + HttpServletResponse response) throws Exception { + try { + StorageBucket storageBucket = storageManagement.getStorageBucket(storageType, clientName); + StorageEntity fileEntity = storageBucket.get(filePath); + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition", + "attachment; filename=" + URLEncoder.encode(filePath, "UTF-8")); + IOUtils.copy(fileEntity.getInputStream(), response.getOutputStream()); + } catch (Exception e) { + response.setContentType("text/plain;charset=UTF-8"); + response.getWriter().write("下载失败: " + e.getMessage()); + } + } + + /** + * 统一预览接口:/file/{storageType}/{clientName}/preview?filePath=xxx + */ + @Anonymous + @GetMapping("/{storageType}/{clientName}/preview") + public void preview( + @PathVariable("storageType") String storageType, + @PathVariable("clientName") String clientName, + @RequestParam("filePath") String filePath, + HttpServletResponse response) throws Exception { + try { + filePath = URLDecoder.decode(filePath, "UTF-8"); + StorageBucket storageBucket = storageManagement.getStorageBucket(storageType, clientName); + StorageEntity fileEntity = storageBucket.get(filePath); + String contentType = URLConnection.guessContentTypeFromName(FileUtils.getName(filePath)); + if (contentType == null) { + contentType = "application/octet-stream"; + } + response.setContentType(contentType); + IOUtils.copy(fileEntity.getInputStream(), response.getOutputStream()); + response.flushBuffer(); + } catch (Exception e) { + response.setContentType("text/plain;charset=UTF-8"); + response.getWriter().write("预览失败: " + e.getMessage()); + } + } + + /** + * 本地资源通用下载 + */ + @Operation(summary = "本地资源通用下载") + @GetMapping("/resource") + @Anonymous + public void resourceDownload(@RequestParam String filePath, + HttpServletRequest request, HttpServletResponse response) + throws Exception { + OutputStream outputStream = response.getOutputStream(); + try { + if (!FileUtils.checkAllowDownload(filePath)) { + throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", filePath)); + } + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + FileUtils.setAttachmentResponseHeader(response, filePath); + FileOperateUtils.downLoad(filePath, outputStream); + } catch (Exception e) { + response.reset(); + response.setContentType(MediaType.TEXT_HTML_VALUE); + response.setCharacterEncoding("UTF-8"); + String errorMessage = "下载文件失败: " + e.getMessage(); + outputStream.write(errorMessage.getBytes("UTF-8")); + outputStream.flush(); + } finally { + outputStream.close(); + } + } + + private static final long MAX_FILE_SIZE = 500 * 1024 * 1024; // 500MB + // 存储上传会话ID与文件名的映射,用于通过uploadId查找原始文件名。 + private final ConcurrentHashMap uploadIdToFileName = new ConcurrentHashMap<>(); + // 存储上传会话ID与文件大小(字节)的映射,记录分片上传任务对应的文件总大小。 + private final ConcurrentHashMap uploadIdToFileSize = new ConcurrentHashMap<>(); + // 存储上传会话ID与文件路径的映射,标识该上传任务在存储系统中的具体位置。 + private final ConcurrentHashMap uploadIdToFilePath = new ConcurrentHashMap<>(); + // 存储上传会话ID与存储桶名称的映射,确定文件最终上传到哪个存储桶中。 + private Map uploadIdToBucketName = new ConcurrentHashMap<>(); + + /** + * 初始化分片上传 + */ + @PostMapping("/initUpload") + public AjaxResult initMultipartUpload(@RequestParam("fileName") String fileName, + @RequestParam("fileSize") Long fileSize, + @RequestParam(value = "fileType", required = false) String fileType, + @RequestParam("bucketName") String bucketName) { + try { + if (fileName == null || fileName.isEmpty() || fileSize == null || fileSize <= 0) { + throw new ServiceException("文件名或文件大小不能为空"); + } + if (fileSize > MAX_FILE_SIZE) + throw new ServiceException("文件不能超过500MB"); + String currentDate = new SimpleDateFormat("yyyy/MM/dd").format(new Date()); + String timestamp = String.valueOf(System.currentTimeMillis()); + String objectName = String.format("%s/%s/%s_%s", "/upload", currentDate, timestamp, fileName); + String uploadId = FileOperateUtils.initMultipartUpload(objectName); + // 存储上传会话信息 + uploadIdToFileName.put(uploadId, fileName); + uploadIdToFileSize.put(uploadId, fileSize); + uploadIdToFilePath.put(uploadId, objectName); + uploadIdToBucketName.put(uploadId, bucketName); + return AjaxResult.success(Map.of("uploadId", uploadId, "filePath", objectName, + "fileName", fileName, "bucketName", bucketName)); + } catch (Exception e) { + return AjaxResult.error(e.getMessage()); + } + } + + /** + * 上传文件分片 + */ + @PostMapping("/uploadChunk") + public AjaxResult uploadFileChunk(@RequestParam("uploadId") String uploadId, + @RequestParam("filePath") String filePath, @RequestParam("chunkIndex") int chunkIndex, + @RequestParam("chunk") MultipartFile chunk) { + try { + if (chunk == null || chunk.isEmpty()) + throw new ServiceException("分片数据不能为空"); + // 检查上传会话是否存在 + String fileName = uploadIdToFileName.get(uploadId); + Long fileSize = uploadIdToFileSize.get(uploadId); + if (fileName == null || fileSize == null) + throw new ServiceException("文件上传会话不存在或已过期"); + // 上传分片 + String etag = FileOperateUtils.uploadPart(filePath, uploadId, chunkIndex + 1, chunk.getSize(), + chunk.getInputStream()); + if (etag == null || etag.isEmpty()) + throw new ServiceException("上传分片失败:未获取到ETag"); + return AjaxResult.success(Map.of("etag", etag, "chunkIndex", + chunkIndex, "partNumber", chunkIndex + 1)); + } catch (Exception e) { + return AjaxResult.error(e.getMessage()); + } + } + + /** + * 完成分片上传并合并文件 + */ + @PostMapping("/completeUpload") + public AjaxResult completeMultipartUpload(@RequestParam("uploadId") String uploadId, + @RequestParam("filePath") String filePath, @RequestBody List partETags) { + try { + String bucketName = uploadIdToBucketName.get(uploadId); + if (bucketName == null || bucketName.trim().isEmpty()) + throw new ServiceException("无法获取存储桶"); + if (partETags == null || partETags.isEmpty()) + throw new ServiceException("分片信息不能为空"); + String fileName = uploadIdToFileName.get(uploadId); + Long fileSize = uploadIdToFileSize.get(uploadId); + if (fileName == null || fileSize == null) + throw new ServiceException("文件上传会话不存在或已过期"); + // 验证并排序分片信息 + List validParts = partETags.stream() + .filter(part -> part != null && part.getPartNumber() != null && part.getETag() != null) + .peek(part -> { + if (part.getPartNumber() <= 0 || StringUtils.isEmpty(part.getETag())) { + throw new ServiceException("分片序号或ETag无效"); + } + }) + .collect(Collectors.toList()); + if (validParts.size() != partETags.size()) { + throw new ServiceException("分片信息格式不正确"); + } + validParts.sort(Comparator.comparingInt(p -> p.getPartNumber())); + // 完成分片上传并合并文件 + String finalPath = FileOperateUtils.completeMultipartUpload(filePath, uploadId, validParts); + if (finalPath == null || finalPath.isEmpty()) { + throw new ServiceException("合并分片失败:未获取到最终文件路径"); + } + // 创建文件信息记录 + SysFileInfo fileInfo = new SysFileInfo(); + fileInfo.setFileName(fileName); + fileInfo.setFilePath(finalPath); + fileInfo.setFileSize(fileSize); + int dotIndex = fileName.lastIndexOf('.'); + fileInfo.setFileType(dotIndex >= 0 ? fileName.substring(dotIndex + 1) : ""); + fileInfo.setStorageType(bucketName); + fileInfo.setCreateBy(SecurityUtils.getUsername()); + fileInfo.setCreateTime(new Date()); + fileInfo.setUpdateBy(SecurityUtils.getUsername()); + fileInfo.setUpdateTime(new Date()); + fileInfo.setDelFlag("0"); + sysFileInfoService.insertSysFileInfo(fileInfo); + // 清理上传会话信息 + uploadIdToFileName.remove(uploadId); + uploadIdToFileSize.remove(uploadId); + uploadIdToFilePath.remove(uploadId); + uploadIdToBucketName.remove(uploadId); + return AjaxResult.success(Map.of("fileId", fileInfo.getFileId(), "fileName", fileName, + "filePath", finalPath, "fileSize", fileSize, "storageType", bucketName)); + } catch (Exception e) { + return AjaxResult.error(e.getMessage()); + } + } +} diff --git a/boyue-file/boyue-file-starter/src/main/java/com/boyue/file/controller/SysFileInfoController.java b/boyue-file/boyue-file-starter/src/main/java/com/boyue/file/controller/SysFileInfoController.java new file mode 100644 index 0000000..147afbb --- /dev/null +++ b/boyue-file/boyue-file-starter/src/main/java/com/boyue/file/controller/SysFileInfoController.java @@ -0,0 +1,113 @@ +package com.boyue.file.controller; + +import java.util.List; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.enums.BusinessType; +import com.boyue.file.domain.SysFileInfo; +import com.boyue.file.service.ISysFileInfoService; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.common.core.page.TableDataInfo; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; + +/** + * 文件信息Controller + * + * @author boyue + * @date 2025-04-25 + */ +@RestController +@RequestMapping("/file/info") +@Tag(name = "【文件信息】管理") +public class SysFileInfoController extends BaseController +{ + @Autowired + private ISysFileInfoService sysFileInfoService; + + /** + * 查询文件信息列表 + */ + @Operation(summary = "查询文件信息列表") + @PreAuthorize("@ss.hasPermi('file:info:list')") + @GetMapping("/list") + public TableDataInfo list(SysFileInfo sysFileInfo) + { + startPage(); + List list = sysFileInfoService.selectSysFileInfoList(sysFileInfo); + return getDataTable(list); + } + + /** + * 导出文件信息列表 + */ + @Operation(summary = "导出文件信息列表") + @PreAuthorize("@ss.hasPermi('file:info:export')") + @Log(title = "文件信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, SysFileInfo sysFileInfo) + { + List list = sysFileInfoService.selectSysFileInfoList(sysFileInfo); + ExcelUtil util = new ExcelUtil(SysFileInfo.class); + util.exportExcel(response, list, "文件信息数据"); + } + + /** + * 获取文件信息详细信息 + */ + @Operation(summary = "获取文件信息详细信息") + @PreAuthorize("@ss.hasPermi('file:info:query')") + @GetMapping(value = "/{fileId}") + public AjaxResult getInfo(@PathVariable("fileId") Long fileId) + { + return success(sysFileInfoService.selectSysFileInfoByFileId(fileId)); + } + + /** + * 新增文件信息 + */ + @Operation(summary = "新增文件信息") + @PreAuthorize("@ss.hasPermi('file:info:add')") + @Log(title = "文件信息", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody SysFileInfo sysFileInfo) + { + return toAjax(sysFileInfoService.insertSysFileInfo(sysFileInfo)); + } + + /** + * 修改文件信息 + */ + @Operation(summary = "修改文件信息") + @PreAuthorize("@ss.hasPermi('file:info:edit')") + @Log(title = "文件信息", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody SysFileInfo sysFileInfo) + { + return toAjax(sysFileInfoService.updateSysFileInfo(sysFileInfo)); + } + + /** + * 删除文件信息 + */ + @Operation(summary = "删除文件信息") + @PreAuthorize("@ss.hasPermi('file:info:remove')") + @Log(title = "文件信息", businessType = BusinessType.DELETE) + @DeleteMapping("/{fileIds}") + public AjaxResult remove(@PathVariable( name = "fileIds" ) Long[] fileIds) + { + return toAjax(sysFileInfoService.deleteSysFileInfoByFileIds(fileIds)); + } +} diff --git a/boyue-file/pom.xml b/boyue-file/pom.xml new file mode 100644 index 0000000..70971d7 --- /dev/null +++ b/boyue-file/pom.xml @@ -0,0 +1,65 @@ + + + + boyuehasfj-java + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-file + + + 3.18.1 + 8.2.1 + + + + 文件模块 + + + + + com.boyue + boyue-file-common + ${boyue.version} + + + + io.minio + minio + ${minio.version} + + + + + com.aliyun.oss + aliyun-sdk-oss + ${aliyunoss.version} + + + + com.boyue + boyue-file-oss-alibaba + ${boyue.version} + + + + com.boyue + boyue-file-minio + ${boyue.version} + + + + + + + + boyue-file-common + boyue-file-minio + boyue-file-oss-alibaba + boyue-file-starter + + pom + \ No newline at end of file diff --git a/boyue-framework/pom.xml b/boyue-framework/pom.xml new file mode 100644 index 0000000..2593b01 --- /dev/null +++ b/boyue-framework/pom.xml @@ -0,0 +1,74 @@ + + + + boyuehasfj-java + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-framework + + + framework框架核心 + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + com.alibaba + druid-spring-boot-3-starter + + + + javax.transaction + jta + + + + + pro.fessional + kaptcha + + + jakarta.servlet-api + jakarta.servlet + + + + + + + com.github.oshi + oshi-core + + + + + + com.boyue + boyue-system + + + + com.boyue + boyue-plugins-starter + + + + + diff --git a/boyue-framework/src/main/java/com/boyue/framework/aspectj/DataScopeAspect.java b/boyue-framework/src/main/java/com/boyue/framework/aspectj/DataScopeAspect.java new file mode 100644 index 0000000..c311dc1 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/aspectj/DataScopeAspect.java @@ -0,0 +1,165 @@ +package com.boyue.framework.aspectj; + +import java.util.ArrayList; +import java.util.List; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.stereotype.Component; + +import com.boyue.common.annotation.DataScope; +import com.boyue.common.constant.UserConstants; +import com.boyue.common.core.domain.BaseEntity; +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.core.text.Convert; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.framework.security.context.PermissionContextHolder; + +/** + * 数据过滤处理 + * + * @author boyue + */ +@Aspect +@Component +public class DataScopeAspect { + /** + * 全部数据权限 + */ + public static final String DATA_SCOPE_ALL = "1"; + + /** + * 自定数据权限 + */ + public static final String DATA_SCOPE_CUSTOM = "2"; + + /** + * 部门数据权限 + */ + public static final String DATA_SCOPE_DEPT = "3"; + + /** + * 部门及以下数据权限 + */ + public static final String DATA_SCOPE_DEPT_AND_CHILD = "4"; + + /** + * 仅本人数据权限 + */ + public static final String DATA_SCOPE_SELF = "5"; + + /** + * 数据权限过滤关键字 + */ + public static final String DATA_SCOPE = "dataScope"; + + @Before("@annotation(controllerDataScope)") + public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable { + clearDataScope(point); + handleDataScope(point, controllerDataScope); + } + + protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope) { + // 获取当前的用户 + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (StringUtils.isNotNull(loginUser)) { + SysUser currentUser = loginUser.getUser(); + // 如果是超级管理员,则不过滤数据 + if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) { + String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), + PermissionContextHolder.getContext()); + dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), + controllerDataScope.userAlias(), permission); + } + } + } + + /** + * 数据范围过滤 + * + * @param joinPoint 切点 + * @param user 用户 + * @param deptAlias 部门别名 + * @param userAlias 用户别名 + * @param permission 权限字符 + */ + public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias, + String permission) { + StringBuilder sqlString = new StringBuilder(); + List conditions = new ArrayList(); + List scopeCustomIds = new ArrayList(); + user.getRoles().forEach(role -> { + if (DATA_SCOPE_CUSTOM.equals(role.getDataScope()) && StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL) && StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))){ + scopeCustomIds.add(Convert.toStr(role.getRoleId())); + } + }); + + for (SysRole role : user.getRoles()) { + String dataScope = role.getDataScope(); + if (conditions.contains(dataScope) || StringUtils.equals(role.getStatus(), UserConstants.ROLE_DISABLE)) { + continue; + } + if (StringUtils.isNotEmpty(permission) && !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))) { + continue; + } + if (DATA_SCOPE_ALL.equals(dataScope)) { + sqlString = new StringBuilder(); + conditions.add(dataScope); + break; + } else if (DATA_SCOPE_CUSTOM.equals(dataScope)) { + if (scopeCustomIds.size() > 1) { + // 多个自定数据权限使用in查询,避免多次拼接。 + sqlString.append(StringUtils.format( + " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id in ({}) ) ", deptAlias, + String.join(",", scopeCustomIds))); + } else { + sqlString.append(StringUtils.format( + " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, + role.getRoleId())); + } + } else if (DATA_SCOPE_DEPT.equals(dataScope)) { + sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId())); + } else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) { + sqlString.append(StringUtils.format( + " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", + deptAlias, user.getDeptId(), user.getDeptId())); + } else if (DATA_SCOPE_SELF.equals(dataScope)) { + if (StringUtils.isNotBlank(userAlias)) { + sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId())); + } else { + // 数据权限为仅本人且没有userAlias别名不查询任何数据 + sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias)); + } + } + conditions.add(dataScope); + } + + // 多角色情况下,所有角色都不包含传递过来的权限字符,这个时候sqlString也会为空,所以要限制一下,不查询任何数据 + if (StringUtils.isEmpty(conditions)) { + sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias)); + } + + if (StringUtils.isNotBlank(sqlString.toString())) { + Object params = joinPoint.getArgs()[0]; + if (StringUtils.isNotNull(params) && params instanceof BaseEntity) { + BaseEntity baseEntity = (BaseEntity) params; + baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")"); + } + } + } + + /** + * 拼接权限sql前先清空params.dataScope参数防止注入 + */ + private void clearDataScope(final JoinPoint joinPoint) { + Object params = joinPoint.getArgs()[0]; + if (StringUtils.isNotNull(params) && params instanceof BaseEntity) { + BaseEntity baseEntity = (BaseEntity) params; + baseEntity.getParams().put(DATA_SCOPE, ""); + } + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/aspectj/DataSourceAspect.java b/boyue-framework/src/main/java/com/boyue/framework/aspectj/DataSourceAspect.java new file mode 100644 index 0000000..0c2784b --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/aspectj/DataSourceAspect.java @@ -0,0 +1,70 @@ +package com.boyue.framework.aspectj; + +import java.util.Objects; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import com.boyue.common.annotation.DataSource; +import com.boyue.common.utils.StringUtils; +import com.boyue.framework.datasource.DynamicDataSourceContextHolder; + +/** + * 多数据源处理 + * + * @author boyue + */ +@Aspect +@Order(1) +@Component +public class DataSourceAspect { + protected Logger logger = LoggerFactory.getLogger(getClass()); + + @Pointcut("@annotation(com.boyue.common.annotation.DataSource)" + + "|| @within(com.boyue.common.annotation.DataSource)") + public void dsPointCut() { + + } + + @Around("dsPointCut()") + public Object around(ProceedingJoinPoint point) throws Throwable { + DataSource dataSource = getDataSource(point); + + if (StringUtils.isNotNull(dataSource)) { + if ("".equals(dataSource.name())) { + DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name()); + } else { + DynamicDataSourceContextHolder.setDataSourceType(dataSource.name()); + } + + } + + try { + return point.proceed(); + } finally { + // 销毁数据源 在执行方法之后 + DynamicDataSourceContextHolder.clearDataSourceType(); + } + } + + /** + * 获取需要切换的数据源 + */ + public DataSource getDataSource(ProceedingJoinPoint point) { + MethodSignature signature = (MethodSignature) point.getSignature(); + DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class); + if (Objects.nonNull(dataSource)) { + return dataSource; + } + + return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/aspectj/LogAspect.java b/boyue-framework/src/main/java/com/boyue/framework/aspectj/LogAspect.java new file mode 100644 index 0000000..421fcd3 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/aspectj/LogAspect.java @@ -0,0 +1,226 @@ +package com.boyue.framework.aspectj; + +import java.util.Collection; +import java.util.Map; + +import org.apache.commons.lang3.ArrayUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.NamedThreadLocal; +import org.springframework.stereotype.Component; +import org.springframework.validation.BindingResult; +import org.springframework.web.multipart.MultipartFile; + +import com.alibaba.fastjson2.JSON; +import com.boyue.common.annotation.Log; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.core.text.Convert; +import com.boyue.common.enums.BusinessStatus; +import com.boyue.common.enums.HttpMethod; +import com.boyue.common.filter.PropertyPreExcludeFilter; +import com.boyue.common.utils.ExceptionUtil; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.ServletUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.ip.IpUtils; +import com.boyue.framework.manager.AsyncManager; +import com.boyue.framework.manager.factory.AsyncFactory; +import com.boyue.system.domain.SysOperLog; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 操作日志记录处理 + * + * @author boyue + */ +@Aspect +@Component +public class LogAspect { + private static final Logger log = LoggerFactory.getLogger(LogAspect.class); + + /** 排除敏感属性字段 */ + public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; + + /** 计算操作消耗时间 */ + private static final ThreadLocal TIME_THREADLOCAL = new NamedThreadLocal("Cost Time"); + + /** + * 处理请求前执行 + */ + @Before(value = "@annotation(controllerLog)") + public void boBefore(JoinPoint joinPoint, Log controllerLog) { + TIME_THREADLOCAL.set(System.currentTimeMillis()); + } + + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult") + public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) { + handleLog(joinPoint, controllerLog, null, jsonResult); + } + + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) { + handleLog(joinPoint, controllerLog, e, null); + } + + protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) { + try { + // 获取当前的用户 + LoginUser loginUser = SecurityUtils.getLoginUser(); + + // *========数据库日志=========*// + SysOperLog operLog = new SysOperLog(); + operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); + // 请求的地址 + String ip = IpUtils.getIpAddr(); + operLog.setOperIp(ip); + operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255)); + if (loginUser != null) { + operLog.setOperName(loginUser.getUsername()); + SysUser currentUser = loginUser.getUser(); + if (StringUtils.isNotNull(currentUser) && StringUtils.isNotNull(currentUser.getDept())) { + operLog.setDeptName(currentUser.getDept().getDeptName()); + } + } + + if (e != null) { + operLog.setStatus(BusinessStatus.FAIL.ordinal()); + operLog.setErrorMsg(StringUtils.substring(Convert.toStr(e.getMessage(), ExceptionUtil.getExceptionMessage(e)), 0, 2000)); + } + // 设置方法名称 + String className = joinPoint.getTarget().getClass().getName(); + String methodName = joinPoint.getSignature().getName(); + operLog.setMethod(className + "." + methodName + "()"); + // 设置请求方式 + operLog.setRequestMethod(ServletUtils.getRequest().getMethod()); + // 处理设置注解上的参数 + getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult); + // 设置消耗时间 + operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get()); + // 保存数据库 + AsyncManager.me().execute(AsyncFactory.recordOper(operLog)); + } catch (Exception exp) { + // 记录本地异常日志 + log.error("异常信息:{}", exp.getMessage()); + exp.printStackTrace(); + } finally { + TIME_THREADLOCAL.remove(); + } + } + + /** + * 获取注解中对方法的描述信息 用于Controller层注解 + * + * @param log 日志 + * @param operLog 操作日志 + * @throws Exception + */ + public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) + throws Exception { + // 设置action动作 + operLog.setBusinessType(log.businessType().ordinal()); + // 设置标题 + operLog.setTitle(log.title()); + // 设置操作人类别 + operLog.setOperatorType(log.operatorType().ordinal()); + // 是否需要保存request,参数和值 + if (log.isSaveRequestData()) { + // 获取参数的信息,传入到数据库中。 + setRequestValue(joinPoint, operLog, log.excludeParamNames()); + } + // 是否需要保存response,参数和值 + if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult)) { + operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000)); + } + } + + /** + * 获取请求的参数,放到log中 + * + * @param operLog 操作日志 + * @throws Exception 异常 + */ + private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception { + Map paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest()); + String requestMethod = operLog.getRequestMethod(); + if (StringUtils.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), + HttpMethod.POST.name(), HttpMethod.DELETE.name())) { + String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames); + operLog.setOperParam(StringUtils.substring(params, 0, 2000)); + } else { + operLog.setOperParam(StringUtils + .substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter(excludeParamNames)), 0, 2000)); + } + } + + /** + * 参数拼装 + */ + private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) { + String params = ""; + if (paramsArray != null && paramsArray.length > 0) { + for (Object o : paramsArray) { + if (StringUtils.isNotNull(o) && !isFilterObject(o)) { + try { + String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter(excludeParamNames)); + params += jsonObj.toString() + " "; + } catch (Exception e) { + } + } + } + } + return params.trim(); + } + + /** + * 忽略敏感属性 + */ + public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames) { + return new PropertyPreExcludeFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames)); + } + + /** + * 判断是否需要过滤的对象。 + * + * @param o 对象信息。 + * @return 如果是需要过滤的对象,则返回true;否则返回false。 + */ + @SuppressWarnings("rawtypes") + public boolean isFilterObject(final Object o) { + Class clazz = o.getClass(); + if (clazz.isArray()) { + return clazz.getComponentType().isAssignableFrom(MultipartFile.class); + } else if (Collection.class.isAssignableFrom(clazz)) { + Collection collection = (Collection) o; + for (Object value : collection) { + return value instanceof MultipartFile; + } + } else if (Map.class.isAssignableFrom(clazz)) { + Map map = (Map) o; + for (Object value : map.entrySet()) { + Map.Entry entry = (Map.Entry) value; + return entry.getValue() instanceof MultipartFile; + } + } + return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse + || o instanceof BindingResult; + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/config/ApplicationConfig.java b/boyue-framework/src/main/java/com/boyue/framework/config/ApplicationConfig.java new file mode 100644 index 0000000..2a694cb --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/config/ApplicationConfig.java @@ -0,0 +1,31 @@ +package com.boyue.framework.config; + +import java.util.TimeZone; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; + +/** + * 程序注解配置 + * + * @author boyue + */ +@Configuration +// 表示通过aop框架暴露该代理对象,AopContext能够访问 +@EnableAspectJAutoProxy(exposeProxy = true) +// 指定要扫描的Mapper类的包的路径 +@MapperScan(basePackages = "com.boyue.**.mapper", sqlSessionTemplateRef = "sqlSessionTemplate") +public class ApplicationConfig +{ + /** + * 时区配置 + */ + @Bean + public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() + { + return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault()); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/config/CaptchaConfig.java b/boyue-framework/src/main/java/com/boyue/framework/config/CaptchaConfig.java new file mode 100644 index 0000000..a4081c9 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/config/CaptchaConfig.java @@ -0,0 +1,83 @@ +package com.boyue.framework.config; + +import java.util.Properties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import com.google.code.kaptcha.impl.DefaultKaptcha; +import com.google.code.kaptcha.util.Config; +import static com.google.code.kaptcha.Constants.*; + +/** + * 验证码配置 + * + * @author boyue + */ +@Configuration +public class CaptchaConfig +{ + @Bean(name = "captchaProducer") + public DefaultKaptcha getKaptchaBean() + { + DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); + Properties properties = new Properties(); + // 是否有边框 默认为true 我们可以自己设置yes,no + properties.setProperty(KAPTCHA_BORDER, "yes"); + // 验证码文本字符颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black"); + // 验证码图片宽度 默认为200 + properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); + // 验证码图片高度 默认为50 + properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); + // 验证码文本字符大小 默认为40 + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38"); + // KAPTCHA_SESSION_KEY + properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode"); + // 验证码文本字符长度 默认为5 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4"); + // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); + // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy + properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); + Config config = new Config(properties); + defaultKaptcha.setConfig(config); + return defaultKaptcha; + } + + @Bean(name = "captchaProducerMath") + public DefaultKaptcha getKaptchaBeanMath() + { + DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); + Properties properties = new Properties(); + // 是否有边框 默认为true 我们可以自己设置yes,no + properties.setProperty(KAPTCHA_BORDER, "yes"); + // 边框颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90"); + // 验证码文本字符颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue"); + // 验证码图片宽度 默认为200 + properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); + // 验证码图片高度 默认为50 + properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); + // 验证码文本字符大小 默认为40 + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35"); + // KAPTCHA_SESSION_KEY + properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath"); + // 验证码文本生成器 + properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.boyue.framework.config.KaptchaTextCreator"); + // 验证码文本字符间距 默认为2 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3"); + // 验证码文本字符长度 默认为5 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6"); + // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); + // 验证码噪点颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_NOISE_COLOR, "white"); + // 干扰实现类 + properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise"); + // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy + properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); + Config config = new Config(properties); + defaultKaptcha.setConfig(config); + return defaultKaptcha; + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/config/DruidConfig.java b/boyue-framework/src/main/java/com/boyue/framework/config/DruidConfig.java new file mode 100644 index 0000000..941915b --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/config/DruidConfig.java @@ -0,0 +1,94 @@ +package com.boyue.framework.config; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties; +import com.alibaba.druid.util.Utils; + +import jakarta.annotation.PreDestroy; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; + +/** + * druid 配置多数据源 + * + * @author boyue + */ +@Configuration +public class DruidConfig { + + @Autowired + DynamicDataSourceProperties dataSourceProperties; + + private List druidDataSources = new ArrayList<>(); + + Logger logger = LoggerFactory.getLogger(DruidConfig.class); + + /** + * 去除监控页面底部的广告 + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Bean + @ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true") + FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) { + // 获取web监控页面的参数 + DruidStatProperties.StatViewServlet config = properties.getStatViewServlet(); + // 提取common.js的配置路径 + String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*"; + String commonJsPattern = pattern.replaceAll("\\*", "js/common.js"); + final String filePath = "support/http/resources/js/common.js"; + // 创建filter进行过滤 + Filter filter = new Filter() { + @Override + public void init(jakarta.servlet.FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + chain.doFilter(request, response); + // 重置缓冲区,响应头不会被重置 + response.resetBuffer(); + // 获取common.js + String text = Utils.readFromResource(filePath); + // 正则替换banner, 除去底部的广告信息 + text = text.replaceAll("
", ""); + text = text.replaceAll("powered.*?shrek.wang", ""); + response.getWriter().write(text); + } + + @Override + public void destroy() { + } + }; + FilterRegistrationBean registrationBean = new FilterRegistrationBean(); + registrationBean.setFilter(filter); + registrationBean.addUrlPatterns(commonJsPattern); + return registrationBean; + } + + public List getDruidDataSources() { + return druidDataSources; + } + + @PreDestroy + public void destroy() { + for (DruidDataSource druidDataSource : druidDataSources) { + druidDataSource.close(); + } + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/config/DynamicDataSourceProperties.java b/boyue-framework/src/main/java/com/boyue/framework/config/DynamicDataSourceProperties.java new file mode 100644 index 0000000..26c1df1 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/config/DynamicDataSourceProperties.java @@ -0,0 +1,115 @@ +package com.boyue.framework.config; + +import java.util.ArrayList; +import java.util.Map; +import java.util.Properties; + +import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import com.alibaba.druid.pool.DruidDataSource; +import com.boyue.common.utils.spring.SpringUtils; +import com.boyue.framework.config.properties.DruidProperties; + +@Configuration +@ConfigurationProperties(prefix = "spring.datasource.dynamic") +public class DynamicDataSourceProperties { + + private Map datasource; + private String primary; + + public Properties build(DataSourceProperties dataSourceProperties) { + Properties prop = new Properties(); + DruidProperties druidProperties = SpringUtils.getBean(DruidProperties.class); + prop.setProperty("url", dataSourceProperties.getUrl()); + prop.setProperty("username", dataSourceProperties.getUsername()); + prop.setProperty("password", dataSourceProperties.getPassword()); + prop.setProperty("initialSize", String.valueOf(druidProperties.getInitialSize())); + prop.setProperty("minIdle", String.valueOf(druidProperties.getMinIdle())); + prop.setProperty("maxActive", String.valueOf(druidProperties.getMaxActive())); + prop.setProperty("maxWait", String.valueOf(druidProperties.getMaxWait())); + prop.setProperty("timeBetweenEvictionRunsMillis", + String.valueOf(druidProperties.getTimeBetweenEvictionRunsMillis())); + prop.setProperty("minEvictableIdleTimeMillis", String.valueOf(druidProperties.getMinEvictableIdleTimeMillis())); + prop.setProperty("maxEvictableIdleTimeMillis", String.valueOf(druidProperties.getMaxEvictableIdleTimeMillis())); + prop.setProperty("validationQuery", druidProperties.getValidationQuery()); + prop.setProperty("testWhileIdle", String.valueOf(druidProperties.isTestWhileIdle())); + prop.setProperty("testOnBorrow", String.valueOf(druidProperties.isTestOnBorrow())); + prop.setProperty("testOnReturn", String.valueOf(druidProperties.isTestOnReturn())); + // 修改filters配置,确保spring在最前面 + prop.setProperty("filters", SpringUtils.getRequiredProperty("spring.datasource.druid.filters")); + prop.setProperty("connectionProperties", SpringUtils.getRequiredProperty("spring.datasource.druid.connectionProperties")); + return prop; + } + + public void setProperties(DruidDataSource dataSource, Properties prop) { + dataSource.setUrl(prop.getProperty("url")); + dataSource.setUsername(prop.getProperty("username")); + dataSource.setPassword(prop.getProperty("password")); + if (prop.getProperty("initialSize") != null) { + dataSource.setInitialSize(Integer.parseInt(prop.getProperty("initialSize"))); + } + if (prop.getProperty("minIdle") != null) { + dataSource.setMinIdle(Integer.parseInt(prop.getProperty("minIdle"))); + } + if (prop.getProperty("maxActive") != null) { + dataSource.setMaxActive(Integer.parseInt(prop.getProperty("maxActive"))); + } + if (prop.getProperty("maxWait") != null) { + dataSource.setMaxWait(Long.parseLong(prop.getProperty("maxWait"))); + } + if (prop.getProperty("timeBetweenEvictionRunsMillis") != null) { + dataSource.setTimeBetweenEvictionRunsMillis( + Long.parseLong(prop.getProperty("timeBetweenEvictionRunsMillis"))); + } + if (prop.getProperty("minEvictableIdleTimeMillis") != null) { + dataSource.setMinEvictableIdleTimeMillis(Long.parseLong(prop.getProperty("minEvictableIdleTimeMillis"))); + } + if (prop.getProperty("maxEvictableIdleTimeMillis") != null) { + dataSource.setMaxEvictableIdleTimeMillis(Long.parseLong(prop.getProperty("maxEvictableIdleTimeMillis"))); + } + if (prop.getProperty("validationQuery") != null) { + dataSource.setValidationQuery(prop.getProperty("validationQuery")); + } + if (prop.getProperty("testWhileIdle") != null) { + dataSource.setTestWhileIdle(Boolean.parseBoolean(prop.getProperty("testWhileIdle"))); + } + if (prop.getProperty("testOnBorrow") != null) { + dataSource.setTestOnBorrow(Boolean.parseBoolean(prop.getProperty("testOnBorrow"))); + } + if (prop.getProperty("testOnReturn") != null) { + dataSource.setTestOnReturn(Boolean.parseBoolean(prop.getProperty("testOnReturn"))); + } + // 确保过滤器配置生效 + try { + if (prop.getProperty("filters") != null) { + dataSource.setFilters(prop.getProperty("filters")); + } + if (prop.getProperty("connectionProperties") != null) { + dataSource.setConnectionProperties(prop.getProperty("connectionProperties")); + } + // 启用防火墙功能 + dataSource.setProxyFilters(new ArrayList<>()); + } catch (Exception e) { + throw new RuntimeException("配置Druid过滤器失败", e); + } + } + + public Map getDatasource() { + return datasource; + } + + public void setDatasource(Map datasource) { + this.datasource = datasource; + } + + public String getPrimary() { + return primary; + } + + public void setPrimary(String primary) { + this.primary = primary; + } + +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/config/FilterConfig.java b/boyue-framework/src/main/java/com/boyue/framework/config/FilterConfig.java new file mode 100644 index 0000000..0029e16 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/config/FilterConfig.java @@ -0,0 +1,58 @@ +package com.boyue.framework.config; + +import java.util.HashMap; +import java.util.Map; +import jakarta.servlet.DispatcherType; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import com.boyue.common.filter.RepeatableFilter; +import com.boyue.common.filter.XssFilter; +import com.boyue.common.utils.StringUtils; + +/** + * Filter配置 + * + * @author boyue + */ +@Configuration +public class FilterConfig +{ + @Value("${xss.excludes}") + private String excludes; + + @Value("${xss.urlPatterns}") + private String urlPatterns; + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Bean + @ConditionalOnProperty(value = "xss.enabled", havingValue = "true") + public FilterRegistrationBean xssFilterRegistration() + { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setDispatcherTypes(DispatcherType.REQUEST); + registration.setFilter(new XssFilter()); + registration.addUrlPatterns(StringUtils.split(urlPatterns, ",")); + registration.setName("xssFilter"); + registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); + Map initParameters = new HashMap(); + initParameters.put("excludes", excludes); + registration.setInitParameters(initParameters); + return registration; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Bean + public FilterRegistrationBean someFilterRegistration() + { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(new RepeatableFilter()); + registration.addUrlPatterns("/*"); + registration.setName("repeatableFilter"); + registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE); + return registration; + } + +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/config/I18nConfig.java b/boyue-framework/src/main/java/com/boyue/framework/config/I18nConfig.java new file mode 100644 index 0000000..ca2ec65 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/config/I18nConfig.java @@ -0,0 +1,44 @@ +package com.boyue.framework.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; +import org.springframework.web.servlet.i18n.SessionLocaleResolver; + +import com.boyue.common.constant.Constants; + +/** + * 资源文件配置加载 + * + * @author boyue + */ +@Configuration +public class I18nConfig implements WebMvcConfigurer +{ + @Bean + public LocaleResolver localeResolver() + { + SessionLocaleResolver slr = new SessionLocaleResolver(); + // 默认语言 + slr.setDefaultLocale(Constants.DEFAULT_LOCALE); + return slr; + } + + @Bean + public LocaleChangeInterceptor localeChangeInterceptor() + { + LocaleChangeInterceptor lci = new LocaleChangeInterceptor(); + // 参数名 + lci.setParamName("lang"); + return lci; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) + { + registry.addInterceptor(localeChangeInterceptor()); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/config/KaptchaTextCreator.java b/boyue-framework/src/main/java/com/boyue/framework/config/KaptchaTextCreator.java new file mode 100644 index 0000000..7229641 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/config/KaptchaTextCreator.java @@ -0,0 +1,69 @@ +package com.boyue.framework.config; + +import java.security.SecureRandom; + +import com.google.code.kaptcha.text.impl.DefaultTextCreator; + +/** + * 验证码文本生成器 + * + * @author boyue + */ +public class KaptchaTextCreator extends DefaultTextCreator +{ + private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(","); + + @Override + public String getText() + { + Integer result = 0; + SecureRandom random = new SecureRandom(); + int x = random.nextInt(10); + int y = random.nextInt(10); + StringBuilder suChinese = new StringBuilder(); + int randomoperands = random.nextInt(3); + if (randomoperands == 0) + { + result = x * y; + suChinese.append(CNUMBERS[x]); + suChinese.append("*"); + suChinese.append(CNUMBERS[y]); + } + else if (randomoperands == 1) + { + if ((x != 0) && y % x == 0) + { + result = y / x; + suChinese.append(CNUMBERS[y]); + suChinese.append("/"); + suChinese.append(CNUMBERS[x]); + } + else + { + result = x + y; + suChinese.append(CNUMBERS[x]); + suChinese.append("+"); + suChinese.append(CNUMBERS[y]); + } + } + else + { + if (x >= y) + { + result = x - y; + suChinese.append(CNUMBERS[x]); + suChinese.append("-"); + suChinese.append(CNUMBERS[y]); + } + else + { + result = y - x; + suChinese.append(CNUMBERS[y]); + suChinese.append("-"); + suChinese.append(CNUMBERS[x]); + } + } + suChinese.append("=?@" + result); + return suChinese.toString(); + } +} \ No newline at end of file diff --git a/boyue-framework/src/main/java/com/boyue/framework/config/MyBatisConfig.java b/boyue-framework/src/main/java/com/boyue/framework/config/MyBatisConfig.java new file mode 100644 index 0000000..51e40b9 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/config/MyBatisConfig.java @@ -0,0 +1,58 @@ +package com.boyue.framework.config; + +import javax.sql.DataSource; + +import org.apache.ibatis.io.VFS; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.boot.autoconfigure.SpringBootVFS; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.core.io.DefaultResourceLoader; + +import com.github.pagehelper.PageInterceptor; +import com.github.pagehelper.autoconfigure.PageHelperStandardProperties; +import com.boyue.common.service.mybatis.CreateSqlSessionFactory; +import com.boyue.common.utils.MybatisUtils; +import com.boyue.common.utils.StringUtils; + +/** + * Mybatis支持*匹配扫描包 + * + * @author boyue + */ +@Configuration +public class MyBatisConfig { + + Logger logger = LoggerFactory.getLogger(MyBatisConfig.class); + + @Bean + @ConditionalOnProperty(prefix = "createSqlSessionFactory", name = "use", havingValue = "mybatis") + public CreateSqlSessionFactory createSqlSessionFactory(PageHelperStandardProperties packageHelperStandardProperties) { + return new CreateSqlSessionFactory() { + public SqlSessionFactory createSqlSessionFactory(Environment env, DataSource dataSource) throws Exception { + String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage"); + String mapperLocations = env.getProperty("mybatis.mapperLocations"); + String configLocation = env.getProperty("mybatis.configLocation"); + typeAliasesPackage = MybatisUtils.setTypeAliasesPackage(typeAliasesPackage); + VFS.addImplClass(SpringBootVFS.class); + + final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); + sessionFactory.setDataSource(dataSource); + sessionFactory.setTypeAliasesPackage(typeAliasesPackage); + sessionFactory.setMapperLocations( + MybatisUtils.resolveMapperLocations(StringUtils.split(mapperLocations, ","))); + sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation)); + PageInterceptor interceptor = new PageInterceptor(); + interceptor.setProperties(packageHelperStandardProperties.getProperties()); + sessionFactory.addPlugins(interceptor); + return sessionFactory.getObject(); + } + }; + } + +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/config/ResourcesConfig.java b/boyue-framework/src/main/java/com/boyue/framework/config/ResourcesConfig.java new file mode 100644 index 0000000..8d423c2 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/config/ResourcesConfig.java @@ -0,0 +1,77 @@ +package com.boyue.framework.config; + +import java.util.concurrent.TimeUnit; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.CacheControl; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import com.boyue.common.config.BoYueConfig; +import com.boyue.common.constant.Constants; +import com.boyue.framework.interceptor.RepeatSubmitInterceptor; + +/** + * 通用配置 + * + * @author boyue + */ +@Configuration +public class ResourcesConfig implements WebMvcConfigurer { + @Autowired + private RepeatSubmitInterceptor repeatSubmitInterceptor; + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + /** 本地文件上传路径 */ + registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**") + .addResourceLocations("file:" + BoYueConfig.getProfile() + "/"); + + /** swagger配置 */ + registry.addResourceHandler("/swagger-ui/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/") + .setCacheControl(CacheControl.maxAge(5, TimeUnit.HOURS).cachePublic()); + registry.addResourceHandler("/**") + .addResourceLocations("classpath:/static/"); + registry.addResourceHandler("swagger-ui.html", "doc.html") + .addResourceLocations("classpath:/META-INF/resources/"); + registry.addResourceHandler("/webjars/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/"); + } + + /** + * 自定义拦截规则 + */ + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**"); + } + + /** + * 跨域配置 + */ + @Bean + public CorsFilter corsFilter() { + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + // 设置访问源地址 + config.addAllowedOriginPattern("*"); + // 设置访问源请求头 + config.addAllowedHeader("*"); + // 设置访问源请求方法 + config.addAllowedMethod("*"); + // 有效期 1800秒 + config.setMaxAge(1800L); + // 添加映射路径,拦截一切请求 + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", config); + // 返回新的CorsFilter + return new CorsFilter(source); + } +} \ No newline at end of file diff --git a/boyue-framework/src/main/java/com/boyue/framework/config/SecurityConfig.java b/boyue-framework/src/main/java/com/boyue/framework/config/SecurityConfig.java new file mode 100644 index 0000000..5873eb9 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/config/SecurityConfig.java @@ -0,0 +1,146 @@ +package com.boyue.framework.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.logout.LogoutFilter; +import org.springframework.web.filter.CorsFilter; + +import com.boyue.framework.config.properties.PermitAllUrlProperties; +import com.boyue.framework.security.filter.JwtAuthenticationTokenFilter; +import com.boyue.framework.security.handle.AuthenticationEntryPointImpl; +import com.boyue.framework.security.handle.LogoutSuccessHandlerImpl; + +/** + * spring security配置 + * + * @author Dftre + */ +@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true) +@Configuration +public class SecurityConfig { + /** + * 自定义用户认证逻辑 + */ + @Autowired + private UserDetailsService userDetailsService; + + /** + * 认证失败处理类 + */ + @Autowired + private AuthenticationEntryPointImpl unauthorizedHandler; + + /** + * 退出处理类 + */ + @Autowired + private LogoutSuccessHandlerImpl logoutSuccessHandler; + + /** + * token认证过滤器 + */ + @Autowired + private JwtAuthenticationTokenFilter authenticationTokenFilter; + + /** + * 跨域过滤器 + */ + @Autowired + private CorsFilter corsFilter; + + /** + * 允许匿名访问的地址 + */ + @Autowired + private PermitAllUrlProperties permitAllUrl; + + /** + * @return + * @throws Exception + */ + @Bean + AuthenticationManager authenticationManager() { + DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(userDetailsService); + daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder()); + return new ProviderManager(daoAuthenticationProvider); + } + + /** + * anyRequest | 匹配所有请求路径 + * access | SpringEl表达式结果为true时可以访问 + * anonymous | 匿名可以访问 + * denyAll | 用户不能访问 + * fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录) + * hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问 + * hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问 + * hasAuthority | 如果有参数,参数表示权限,则其权限可以访问 + * hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问 + * hasRole | 如果有参数,参数表示角色,则其角色可以访问 + * permitAll | 用户可以任意访问 + * rememberMe | 允许通过remember-me登录的用户访问 + * authenticated | 用户登录后可访问 + */ + @Bean + SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { + return httpSecurity + // CSRF禁用,因为不使用session + .csrf(csrf -> csrf.disable()) + // 禁用HTTP响应标头 + .headers((headersCustomizer) -> { + headersCustomizer.cacheControl(cache -> cache.disable()) + .frameOptions(options -> options.sameOrigin()); + }) + // 认证失败处理类 + .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler)) + // 基于token,所以不需要session + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + // 注解标记允许匿名访问的url + .authorizeHttpRequests((requests) -> { + permitAllUrl.getUrls().forEach(url -> requests.requestMatchers(url).permitAll()); + // 对于登录login 注册register 验证码captchaImage 允许匿名访问 + requests.requestMatchers("/login", "/register", "/captchaImage").permitAll() + // 静态资源,可匿名访问 + .requestMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", + "/profile/**") + .permitAll() + .requestMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", + "/druid/**", "/*/api-docs/**") + .permitAll() + .requestMatchers("/websocket/**").permitAll() + // 淮安市司法局页面访问路径,允许匿名访问 + .requestMatchers("/hasfj/**", "/hasfjlaw", "/hasfjcase", "/hasfjform", + "/show.html**", "/showcase.html**", "/table.html**", "/api/hasfj/**", "/api/pages**") + .permitAll() + // 除上面外的所有请求全部需要鉴权认证 + .anyRequest().authenticated(); + }) + // 添加Logout filter + .logout(logout -> logout.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler)) + // 添加JWT filter + .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class) + // 添加CORS filter + .addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class) + .addFilterBefore(corsFilter, LogoutFilter.class) + .build(); + } + + /** + * 强散列哈希加密实现 + */ + @Bean + public BCryptPasswordEncoder bCryptPasswordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/config/ServerConfig.java b/boyue-framework/src/main/java/com/boyue/framework/config/ServerConfig.java new file mode 100644 index 0000000..65c2ea2 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/config/ServerConfig.java @@ -0,0 +1,32 @@ +package com.boyue.framework.config; + +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.stereotype.Component; +import com.boyue.common.utils.ServletUtils; + +/** + * 服务相关配置 + * + * @author boyue + */ +@Component +public class ServerConfig +{ + /** + * 获取完整的请求路径,包括:域名,端口,上下文访问路径 + * + * @return 服务地址 + */ + public String getUrl() + { + HttpServletRequest request = ServletUtils.getRequest(); + return getDomain(request); + } + + public static String getDomain(HttpServletRequest request) + { + StringBuffer url = request.getRequestURL(); + String contextPath = request.getSession().getServletContext().getContextPath(); + return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString(); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/config/SqlSessionFactoryConfig.java b/boyue-framework/src/main/java/com/boyue/framework/config/SqlSessionFactoryConfig.java new file mode 100644 index 0000000..205cd80 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/config/SqlSessionFactoryConfig.java @@ -0,0 +1,46 @@ +package com.boyue.framework.config; + +import java.util.HashMap; +import java.util.Map; + +import javax.sql.DataSource; + +import org.apache.ibatis.session.SqlSessionFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +import com.boyue.common.service.mybatis.CreateSqlSessionFactory; +import com.boyue.framework.datasource.DataSourceManagement; +import com.boyue.framework.datasource.DynamicSqlSessionTemplate; + +@Configuration +public class SqlSessionFactoryConfig { + + @Autowired + CreateSqlSessionFactory createSqlSessionFactory; + + @Autowired + DynamicDataSourceProperties dataSourceProperties; + + @Autowired + DataSourceManagement dataSourceManagement; + + @Bean(name = "sqlSessionTemplate") + public DynamicSqlSessionTemplate sqlSessionTemplate(Environment env) throws Exception { + Map sqlSessionFactoryMap = new HashMap<>(); + Map targetDataSources = dataSourceManagement.getDataSourcesMap(); + for (Map.Entry entry : targetDataSources.entrySet()) { + SqlSessionFactory sessionFactory = createSqlSessionFactory.createSqlSessionFactory(env, entry.getValue()); + sqlSessionFactoryMap.put(entry.getKey(), sessionFactory); + } + SqlSessionFactory factoryMaster = sqlSessionFactoryMap.get(dataSourceProperties.getPrimary()); + if (factoryMaster == null) { + throw new RuntimeException("找不到主库配置" + dataSourceProperties.getPrimary()); + } + DynamicSqlSessionTemplate customSqlSessionTemplate = new DynamicSqlSessionTemplate(factoryMaster); + customSqlSessionTemplate.setTargetSqlSessionFactorys(sqlSessionFactoryMap); + return customSqlSessionTemplate; + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/config/ThreadPoolConfig.java b/boyue-framework/src/main/java/com/boyue/framework/config/ThreadPoolConfig.java new file mode 100644 index 0000000..6ba27bc --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/config/ThreadPoolConfig.java @@ -0,0 +1,65 @@ +package com.boyue.framework.config; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; + +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import com.boyue.common.utils.Threads; + +/** + * 线程池配置 + * + * @author boyue + **/ +@Configuration +public class ThreadPoolConfig +{ + // 核心线程池大小 + private int corePoolSize = 50; + + // 最大可创建的线程数 + private int maxPoolSize = 200; + + // 队列最大长度 + private int queueCapacity = 1000; + + // 线程池维护线程所允许的空闲时间 + private int keepAliveSeconds = 300; + + @Bean(name = "threadPoolTaskExecutor") + public ThreadPoolTaskExecutor threadPoolTaskExecutor() + { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setMaxPoolSize(maxPoolSize); + executor.setCorePoolSize(corePoolSize); + executor.setQueueCapacity(queueCapacity); + executor.setKeepAliveSeconds(keepAliveSeconds); + // 线程池对拒绝任务(无线程可用)的处理策略 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + return executor; + } + + /** + * 执行周期性或定时任务 + */ + @Bean(name = "scheduledExecutorService") + protected ScheduledExecutorService scheduledExecutorService() + { + return new ScheduledThreadPoolExecutor(corePoolSize, + new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(), + new ThreadPoolExecutor.CallerRunsPolicy()) + { + @Override + protected void afterExecute(Runnable r, Throwable t) + { + super.afterExecute(r, t); + Threads.printException(r, t); + } + }; + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/config/properties/DruidProperties.java b/boyue-framework/src/main/java/com/boyue/framework/config/properties/DruidProperties.java new file mode 100644 index 0000000..02977b3 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/config/properties/DruidProperties.java @@ -0,0 +1,195 @@ +package com.boyue.framework.config.properties; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +import com.alibaba.druid.pool.DruidDataSource; + +/** + * druid 配置属性 + * + * @author boyue + */ +@Configuration +public class DruidProperties { + @Value("${spring.datasource.druid.initialSize}") + private int initialSize; + + @Value("${spring.datasource.druid.minIdle}") + private int minIdle; + + @Value("${spring.datasource.druid.maxActive}") + private int maxActive; + + @Value("${spring.datasource.druid.maxWait}") + private int maxWait; + + @Value("${spring.datasource.druid.connectTimeout}") + private int connectTimeout; + + @Value("${spring.datasource.druid.socketTimeout}") + private int socketTimeout; + + @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}") + private int timeBetweenEvictionRunsMillis; + + @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}") + private int minEvictableIdleTimeMillis; + + @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}") + private int maxEvictableIdleTimeMillis; + + @Value("${spring.datasource.druid.validationQuery}") + private String validationQuery; + + @Value("${spring.datasource.druid.testWhileIdle}") + private boolean testWhileIdle; + + @Value("${spring.datasource.druid.testOnBorrow}") + private boolean testOnBorrow; + + @Value("${spring.datasource.druid.testOnReturn}") + private boolean testOnReturn; + + public DruidDataSource dataSource(DruidDataSource datasource) { + /** 配置初始化大小、最小、最大 */ + datasource.setInitialSize(initialSize); + datasource.setMaxActive(maxActive); + datasource.setMinIdle(minIdle); + + /** 配置获取连接等待超时的时间 */ + datasource.setMaxWait(maxWait); + + /** 配置驱动连接超时时间,检测数据库建立连接的超时时间,单位是毫秒 */ + datasource.setConnectTimeout(connectTimeout); + + /** 配置网络超时时间,等待数据库操作完成的网络超时时间,单位是毫秒 */ + datasource.setSocketTimeout(socketTimeout); + + /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */ + datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); + + /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */ + datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); + datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis); + + /** + * 用来检测连接是否有效的sql,要求是一个查询语句,常用select + * 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。 + */ + datasource.setValidationQuery(validationQuery); + /** + * 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 + */ + datasource.setTestWhileIdle(testWhileIdle); + /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ + datasource.setTestOnBorrow(testOnBorrow); + /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ + datasource.setTestOnReturn(testOnReturn); + return datasource; + } + + public int getInitialSize() { + return initialSize; + } + + public void setInitialSize(int initialSize) { + this.initialSize = initialSize; + } + + public int getMinIdle() { + return minIdle; + } + + public void setMinIdle(int minIdle) { + this.minIdle = minIdle; + } + + public int getMaxActive() { + return maxActive; + } + + public void setMaxActive(int maxActive) { + this.maxActive = maxActive; + } + + public int getMaxWait() { + return maxWait; + } + + public void setMaxWait(int maxWait) { + this.maxWait = maxWait; + } + + public int getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public int getSocketTimeout() { + return socketTimeout; + } + + public void setSocketTimeout(int socketTimeout) { + this.socketTimeout = socketTimeout; + } + + public int getTimeBetweenEvictionRunsMillis() { + return timeBetweenEvictionRunsMillis; + } + + public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) { + this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; + } + + public int getMinEvictableIdleTimeMillis() { + return minEvictableIdleTimeMillis; + } + + public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) { + this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; + } + + public int getMaxEvictableIdleTimeMillis() { + return maxEvictableIdleTimeMillis; + } + + public void setMaxEvictableIdleTimeMillis(int maxEvictableIdleTimeMillis) { + this.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis; + } + + public String getValidationQuery() { + return validationQuery; + } + + public void setValidationQuery(String validationQuery) { + this.validationQuery = validationQuery; + } + + public boolean isTestWhileIdle() { + return testWhileIdle; + } + + public void setTestWhileIdle(boolean testWhileIdle) { + this.testWhileIdle = testWhileIdle; + } + + public boolean isTestOnBorrow() { + return testOnBorrow; + } + + public void setTestOnBorrow(boolean testOnBorrow) { + this.testOnBorrow = testOnBorrow; + } + + public boolean isTestOnReturn() { + return testOnReturn; + } + + public void setTestOnReturn(boolean testOnReturn) { + this.testOnReturn = testOnReturn; + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/config/properties/PermitAllUrlProperties.java b/boyue-framework/src/main/java/com/boyue/framework/config/properties/PermitAllUrlProperties.java new file mode 100644 index 0000000..480e0a7 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/config/properties/PermitAllUrlProperties.java @@ -0,0 +1,89 @@ +package com.boyue.framework.config.properties; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.RegExUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; + +import com.boyue.common.annotation.Anonymous; +import com.boyue.common.utils.spring.SpringUtils; + +/** + * 设置Anonymous注解允许匿名访问的url + * + * @author boyue + */ +@Configuration +public class PermitAllUrlProperties implements InitializingBean, ApplicationContextAware { + private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}"); + + private ApplicationContext applicationContext; + + private List urls = new ArrayList<>(); + + public String ASTERISK = "*"; + + static class Pair { + public RequestMappingInfo first; + public Anonymous second; + + public Pair(RequestMappingInfo first, Anonymous second) { + this.first = first; + this.second = second; + } + } + + @Override + public void afterPropertiesSet() { + RequestMappingHandlerMapping mapping = applicationContext.getBean("requestMappingHandlerMapping",RequestMappingHandlerMapping.class); + Map map = mapping.getHandlerMethods(); + String matching = SpringUtils.getRequiredProperty("spring.mvc.pathmatch.matching-strategy").toLowerCase(); + map.keySet() + .stream() + .flatMap(info -> { + HandlerMethod handlerMethod = map.get(info); + // 获取方法上边的注解 替代path variable 为 * + Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class); + // 获取类上边的注解, 替代path variable 为 * + Anonymous controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class); + return Arrays.stream(new Pair[] { new Pair(info, method), new Pair(info, controller) }); + }) + .filter(pair -> pair.second != null) + .flatMap(pair -> switch (matching) { + case "ant_path_matcher" -> + Objects.requireNonNull(pair.first.getPatternsCondition().getPatterns()).stream(); + case "path_pattern_parser" -> + Objects.requireNonNull(pair.first.getPathPatternsCondition().getPatternValues()) + .stream(); + default -> Objects.requireNonNull(pair.first.getPatternsCondition().getPatterns()).stream(); + }) + .map(url -> RegExUtils.replaceAll(url, PATTERN, ASTERISK)) + .forEach(urls::add); + } + + @Override + public void setApplicationContext(ApplicationContext context) throws BeansException { + this.applicationContext = context; + } + + public List getUrls() { + return urls; + } + + public void setUrls(List urls) { + this.urls = urls; + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/datasource/DataSourceCreate.java b/boyue-framework/src/main/java/com/boyue/framework/datasource/DataSourceCreate.java new file mode 100644 index 0000000..1d941d7 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/datasource/DataSourceCreate.java @@ -0,0 +1,43 @@ +package com.boyue.framework.datasource; + +import java.util.Properties; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.xa.DruidXADataSource; +// import com.alibaba.druid.pool.xa.DruidXADataSource; +import com.boyue.common.service.datasource.CreateDataSource; +import com.boyue.framework.config.DruidConfig; +import com.boyue.framework.config.DynamicDataSourceProperties; + +@Configuration +public class DataSourceCreate implements CreateDataSource { + + @Autowired + private DynamicDataSourceProperties properties; + + @Autowired + private DruidConfig druidConfig; + + @Value("${spring.datasource.dynamic.xa}") + private boolean xa; + + public DataSource createDataSource(String name, Properties prop) { + DruidDataSource dataSource = null; + if (xa) { + dataSource = new DruidXADataSource(); + } else { + dataSource = new DruidDataSource(); + } + druidConfig.getDruidDataSources().add(dataSource); + dataSource.setConnectProperties(prop); + properties.setProperties(dataSource, prop); + return dataSource; + } + +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/datasource/DataSourceManagement.java b/boyue-framework/src/main/java/com/boyue/framework/datasource/DataSourceManagement.java new file mode 100644 index 0000000..afa18f9 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/datasource/DataSourceManagement.java @@ -0,0 +1,104 @@ +package com.boyue.framework.datasource; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.sql.CommonDataSource; +import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +import com.boyue.common.service.datasource.AfterCreateDataSource; +import com.boyue.common.service.datasource.CreateDataSource; +import com.boyue.framework.config.DynamicDataSourceProperties; + +@Configuration +public class DataSourceManagement implements InitializingBean { + protected final Logger logger = LoggerFactory.getLogger(DataSourceManagement.class); + private Map targetDataSources = new HashMap<>(); + + @Autowired + private DynamicDataSourceProperties dataSourceProperties; + + @Autowired + private CreateDataSource c; + + @Autowired(required = false) + private AfterCreateDataSource afterCreateDataSource; + + @Bean(name = "dynamicDataSource") + @Primary + public DynamicDataSource dataSource() { + Map objectMap = new HashMap<>(); + Map targetDataSources = this.getDataSourcesMap(); + for (Map.Entry entry : targetDataSources.entrySet()) { + objectMap.put(entry.getKey(), entry.getValue()); + } + return new DynamicDataSource(targetDataSources.get(dataSourceProperties.getPrimary()), objectMap); + } + + public void validateDataSource(DataSource dataSource) { + try (Connection conn = dataSource.getConnection()) { + String validationQuery = "SELECT 1"; + try (Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(validationQuery)) { + if (!(rs.next() && rs.getInt(1) == 1)) { + throw new RuntimeException("数据源连接验证失败:查询结果不正确"); + } + } + } catch (SQLException e) { + throw new RuntimeException("数据源连接验证失败", e); + } + } + + @Override + public void afterPropertiesSet() throws Exception { + dataSourceProperties.getDatasource() + .forEach((name, props) -> { + Properties properties = dataSourceProperties.build(props); + CommonDataSource commonDataSource = c.createDataSource(name, properties); + if (afterCreateDataSource != null) { + afterCreateDataSource.afterCreateDataSource(name, properties, commonDataSource); + } + DataSource dataSource = (DataSource) commonDataSource; + logger.info("数据源:{} 校验中.......", name); + // 计时 + long start = System.currentTimeMillis(); + validateDataSource(dataSource); + logger.info("数据源:{} 链接成功,耗时:{}ms", name, System.currentTimeMillis() - start); + this.putDataSource(name, dataSource); + }); + } + + public DataSource getPrimaryDataSource(){ + return targetDataSources.get(dataSourceProperties.getPrimary()); + } + + public DataSource getDataSource(String name) { + return targetDataSources.get(name); + } + + public Collection getDataSources() { + return targetDataSources.values(); + } + + public Map getDataSourcesMap() { + return targetDataSources; + } + + public void putDataSource(String name, DataSource dataSource) { + targetDataSources.put(name, dataSource); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/datasource/DynamicDataSource.java b/boyue-framework/src/main/java/com/boyue/framework/datasource/DynamicDataSource.java new file mode 100644 index 0000000..479ad8b --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/datasource/DynamicDataSource.java @@ -0,0 +1,28 @@ +package com.boyue.framework.datasource; + +import java.util.Map; + +import javax.sql.CommonDataSource; + +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; + +/** + * 动态数据源 + * + * @author boyue + */ +public class DynamicDataSource extends AbstractRoutingDataSource +{ + public DynamicDataSource(CommonDataSource defaultTargetDataSource, Map targetDataSources) + { + super.setDefaultTargetDataSource(defaultTargetDataSource); + super.setTargetDataSources(targetDataSources); + super.afterPropertiesSet(); + } + + @Override + protected Object determineCurrentLookupKey() + { + return DynamicDataSourceContextHolder.getDataSourceType(); + } +} \ No newline at end of file diff --git a/boyue-framework/src/main/java/com/boyue/framework/datasource/DynamicDataSourceContextHolder.java b/boyue-framework/src/main/java/com/boyue/framework/datasource/DynamicDataSourceContextHolder.java new file mode 100644 index 0000000..c47b3a8 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/datasource/DynamicDataSourceContextHolder.java @@ -0,0 +1,60 @@ +package com.boyue.framework.datasource; + +import java.util.Objects; +import java.util.Stack; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 数据源切换处理 + * + * @author boyue + */ +public class DynamicDataSourceContextHolder { + public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class); + + /** + * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本, + * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 + */ + private static final ThreadLocal> CONTEXT_HOLDER = new ThreadLocal<>(); + + /** + * 设置数据源的变量 + */ + public static void setDataSourceType(String dsType) { + log.info("切换到{}数据源", dsType); + Stack stack = CONTEXT_HOLDER.get(); + if (Objects.isNull(stack)) { + stack = new Stack<>(); + CONTEXT_HOLDER.set(stack); + } + stack.push(dsType); + } + + /** + * 获得数据源的变量 + */ + public static String getDataSourceType() { + Stack stack = CONTEXT_HOLDER.get(); + if (Objects.isNull(stack)) { + return null; + } else { + return stack.peek(); + } + } + + /** + * 清空数据源变量 + */ + public static void clearDataSourceType() { + Stack stack = CONTEXT_HOLDER.get(); + if (Objects.nonNull(stack) && !stack.isEmpty()) { + stack.pop(); + if (stack.isEmpty()) { + CONTEXT_HOLDER.remove(); + } + } + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/datasource/DynamicSqlSessionTemplate.java b/boyue-framework/src/main/java/com/boyue/framework/datasource/DynamicSqlSessionTemplate.java new file mode 100644 index 0000000..8aa016e --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/datasource/DynamicSqlSessionTemplate.java @@ -0,0 +1,311 @@ +package com.boyue.framework.datasource; + +import static java.lang.reflect.Proxy.*; +import static org.apache.ibatis.reflection.ExceptionUtil.*; +import static org.mybatis.spring.SqlSessionUtils.*; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.sql.Connection; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.exceptions.PersistenceException; +import org.apache.ibatis.executor.BatchResult; +import org.apache.ibatis.session.Configuration; +import org.apache.ibatis.session.ExecutorType; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.MyBatisExceptionTranslator; +import org.mybatis.spring.SqlSessionTemplate; +import org.springframework.dao.support.PersistenceExceptionTranslator; + +/** + * 自定义SqlSessionTemplate,动态切换数据源 + * + * @author boyue + */ +public class DynamicSqlSessionTemplate extends SqlSessionTemplate { + private final SqlSessionFactory sqlSessionFactory; + private final ExecutorType executorType; + private final SqlSession sqlSessionProxy; + private final PersistenceExceptionTranslator exceptionTranslator; + private Map targetSqlSessionFactorys; + private SqlSessionFactory defaultTargetSqlSessionFactory; + + public DynamicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { + this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType()); + } + + public DynamicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) { + this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator( + sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true)); + } + + public DynamicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, + PersistenceExceptionTranslator exceptionTranslator) { + super(sqlSessionFactory, executorType, exceptionTranslator); + this.sqlSessionFactory = sqlSessionFactory; + this.executorType = executorType; + this.exceptionTranslator = exceptionTranslator; + this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(), + new Class[] { SqlSession.class }, new SqlSessionInterceptor()); + this.defaultTargetSqlSessionFactory = sqlSessionFactory; + } + + public void setTargetSqlSessionFactorys(Map targetSqlSessionFactorys) { + this.targetSqlSessionFactorys = targetSqlSessionFactorys; + } + + public void setDefaultTargetSqlSessionFactory(SqlSessionFactory defaultTargetSqlSessionFactory) { + this.defaultTargetSqlSessionFactory = defaultTargetSqlSessionFactory; + } + + @Override + public SqlSessionFactory getSqlSessionFactory() { + SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys + .get(DynamicDataSourceContextHolder.getDataSourceType()); + if (targetSqlSessionFactory != null) { + return targetSqlSessionFactory; + } else if (defaultTargetSqlSessionFactory != null) { + return defaultTargetSqlSessionFactory; + } + return this.sqlSessionFactory; + } + + @Override + public Configuration getConfiguration() { + return this.getSqlSessionFactory().getConfiguration(); + } + + public ExecutorType getExecutorType() { + return this.executorType; + } + + public PersistenceExceptionTranslator getPersistenceExceptionTranslator() { + return this.exceptionTranslator; + } + + /** + * {@inheritDoc} + */ + public T selectOne(String statement) { + return this.sqlSessionProxy.selectOne(statement); + } + + /** + * {@inheritDoc} + */ + public T selectOne(String statement, Object parameter) { + return this.sqlSessionProxy.selectOne(statement, parameter); + } + + /** + * {@inheritDoc} + */ + public Map selectMap(String statement, String mapKey) { + return this.sqlSessionProxy.selectMap(statement, mapKey); + } + + /** + * {@inheritDoc} + */ + public Map selectMap(String statement, Object parameter, String mapKey) { + return this.sqlSessionProxy.selectMap(statement, parameter, mapKey); + } + + /** + * {@inheritDoc} + */ + public Map selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) { + return this.sqlSessionProxy.selectMap(statement, parameter, mapKey, rowBounds); + } + + /** + * {@inheritDoc} + */ + public List selectList(String statement) { + return this.sqlSessionProxy.selectList(statement); + } + + /** + * {@inheritDoc} + */ + public List selectList(String statement, Object parameter) { + return this.sqlSessionProxy.selectList(statement, parameter); + } + + /** + * {@inheritDoc} + */ + public List selectList(String statement, Object parameter, RowBounds rowBounds) { + return this.sqlSessionProxy.selectList(statement, parameter, rowBounds); + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("rawtypes") + public void select(String statement, ResultHandler handler) { + this.sqlSessionProxy.select(statement, handler); + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("rawtypes") + public void select(String statement, Object parameter, ResultHandler handler) { + this.sqlSessionProxy.select(statement, parameter, handler); + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("rawtypes") + public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { + this.sqlSessionProxy.select(statement, parameter, rowBounds, handler); + } + + /** + * {@inheritDoc} + */ + public int insert(String statement) { + return this.sqlSessionProxy.insert(statement); + } + + /** + * {@inheritDoc} + */ + public int insert(String statement, Object parameter) { + return this.sqlSessionProxy.insert(statement, parameter); + } + + /** + * {@inheritDoc} + */ + public int update(String statement) { + return this.sqlSessionProxy.update(statement); + } + + /** + * {@inheritDoc} + */ + public int update(String statement, Object parameter) { + return this.sqlSessionProxy.update(statement, parameter); + } + + /** + * {@inheritDoc} + */ + public int delete(String statement) { + return this.sqlSessionProxy.delete(statement); + } + + /** + * {@inheritDoc} + */ + public int delete(String statement, Object parameter) { + return this.sqlSessionProxy.delete(statement, parameter); + } + + /** + * {@inheritDoc} + */ + public T getMapper(Class type) { + return getConfiguration().getMapper(type, this); + } + + /** + * {@inheritDoc} + */ + public void commit() { + throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession"); + } + + /** + * {@inheritDoc} + */ + public void commit(boolean force) { + throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession"); + } + + /** + * {@inheritDoc} + */ + public void rollback() { + throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession"); + } + + /** + * {@inheritDoc} + */ + public void rollback(boolean force) { + throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession"); + } + + /** + * {@inheritDoc} + */ + public void close() { + throw new UnsupportedOperationException("Manual close is not allowed over a Spring managed SqlSession"); + } + + /** + * {@inheritDoc} + */ + public void clearCache() { + this.sqlSessionProxy.clearCache(); + } + + /** + * {@inheritDoc} + */ + public Connection getConnection() { + return this.sqlSessionProxy.getConnection(); + } + + /** + * {@inheritDoc} + * + * @since 1.0.2 + */ + public List flushStatements() { + return this.sqlSessionProxy.flushStatements(); + } + + /** + * Proxy needed to route MyBatis method calls to the proper SqlSession got from + * Spring's Transaction Manager It also + * unwraps exceptions thrown by {@code Method#invoke(Object, Object...)} to pass + * a {@code PersistenceException} to + * the {@code PersistenceExceptionTranslator}. + */ + private class SqlSessionInterceptor implements InvocationHandler { + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + final SqlSession sqlSession = getSqlSession(DynamicSqlSessionTemplate.this.getSqlSessionFactory(), + DynamicSqlSessionTemplate.this.executorType, DynamicSqlSessionTemplate.this.exceptionTranslator); + try { + Object result = method.invoke(sqlSession, args); + if (!isSqlSessionTransactional(sqlSession, DynamicSqlSessionTemplate.this.getSqlSessionFactory())) { + sqlSession.commit(true); + } + return result; + } catch (Throwable t) { + Throwable unwrapped = unwrapThrowable(t); + if (DynamicSqlSessionTemplate.this.exceptionTranslator != null + && unwrapped instanceof PersistenceException) { + Throwable translated = DynamicSqlSessionTemplate.this.exceptionTranslator + .translateExceptionIfPossible((PersistenceException) unwrapped); + if (translated != null) { + unwrapped = translated; + } + } + throw unwrapped; + } finally { + closeSqlSession(sqlSession, DynamicSqlSessionTemplate.this.getSqlSessionFactory()); + } + } + } +} \ No newline at end of file diff --git a/boyue-framework/src/main/java/com/boyue/framework/datasource/DynamicTransactionManager.java b/boyue-framework/src/main/java/com/boyue/framework/datasource/DynamicTransactionManager.java new file mode 100644 index 0000000..37e7278 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/datasource/DynamicTransactionManager.java @@ -0,0 +1,28 @@ +package com.boyue.framework.datasource; + +import java.util.Objects; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.support.JdbcTransactionManager; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Component +@EnableTransactionManagement(proxyTargetClass = true) +public class DynamicTransactionManager extends JdbcTransactionManager { + + @Autowired + DataSourceManagement dataSourceManagement; + + @Override + public DataSource getDataSource() { + DataSource dataSource = dataSourceManagement.getDataSource(DynamicDataSourceContextHolder.getDataSourceType()); + if (!Objects.isNull(dataSource)) { + return dataSource; + } else { + return dataSourceManagement.getPrimaryDataSource(); + } + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/interceptor/RepeatSubmitInterceptor.java b/boyue-framework/src/main/java/com/boyue/framework/interceptor/RepeatSubmitInterceptor.java new file mode 100644 index 0000000..bca94ba --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/interceptor/RepeatSubmitInterceptor.java @@ -0,0 +1,55 @@ +package com.boyue.framework.interceptor; + +import java.lang.reflect.Method; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; +import com.alibaba.fastjson2.JSON; +import com.boyue.common.annotation.RepeatSubmit; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.utils.ServletUtils; + +/** + * 防止重复提交拦截器 + * + * @author boyue + */ +@Component +public abstract class RepeatSubmitInterceptor implements HandlerInterceptor +{ + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception + { + if (handler instanceof HandlerMethod) + { + HandlerMethod handlerMethod = (HandlerMethod) handler; + Method method = handlerMethod.getMethod(); + RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); + if (annotation != null) + { + if (this.isRepeatSubmit(request, annotation)) + { + AjaxResult ajaxResult = AjaxResult.error(annotation.message()); + ServletUtils.renderString(response, JSON.toJSONString(ajaxResult)); + return false; + } + } + return true; + } + else + { + return true; + } + } + + /** + * 验证是否重复提交由子类实现具体的防重复提交的规则 + * + * @param request + * @return + * @throws Exception + */ + public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation); +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/interceptor/impl/SameUrlDataInterceptor.java b/boyue-framework/src/main/java/com/boyue/framework/interceptor/impl/SameUrlDataInterceptor.java new file mode 100644 index 0000000..5460fa4 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/interceptor/impl/SameUrlDataInterceptor.java @@ -0,0 +1,104 @@ +package com.boyue.framework.interceptor.impl; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import com.alibaba.fastjson2.JSON; +import com.boyue.common.annotation.RepeatSubmit; +import com.boyue.common.constant.CacheConstants; +import com.boyue.common.filter.RepeatedlyRequestWrapper; +import com.boyue.common.utils.CacheUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.http.HttpHelper; +import com.boyue.framework.interceptor.RepeatSubmitInterceptor; + +import jakarta.servlet.http.HttpServletRequest; + +/** + * 判断请求url和数据是否和上一次相同, + * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。 + * + * @author boyue + */ +@Component +public class SameUrlDataInterceptor extends RepeatSubmitInterceptor +{ + public final String REPEAT_PARAMS = "repeatParams"; + + public final String REPEAT_TIME = "repeatTime"; + + // 令牌自定义标识 + @Value("${token.header}") + private String header; + + @SuppressWarnings("unchecked") + @Override + public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation) + { + String nowParams = ""; + if (request instanceof RepeatedlyRequestWrapper) + { + RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request; + nowParams = HttpHelper.getBodyString(repeatedlyRequest); + } + // body参数为空,获取Parameter的数据 + if (StringUtils.isEmpty(nowParams)) + { + nowParams = JSON.toJSONString(request.getParameterMap()); + } + Map nowDataMap = new HashMap(); + nowDataMap.put(REPEAT_PARAMS, nowParams); + nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); + // 请求地址(作为存放cache的key值) + String url = request.getRequestURI(); + // 唯一值(没有消息头则使用请求地址) + String submitKey = StringUtils.trimToEmpty(request.getHeader(header)); + // 唯一标识(指定key + url + 消息头) + String cacheRepeatKey = url + submitKey; + Object sessionObj = CacheUtils.get(CacheConstants.REPEAT_SUBMIT_KEY, cacheRepeatKey); + if (sessionObj != null) + { + Map sessionMap = (Map) sessionObj; + if (sessionMap.containsKey(url)) + { + Map preDataMap = (Map) sessionMap.get(url); + if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval())) + { + return true; + } + } + } + Map cacheMap = new HashMap(); + cacheMap.put(url, nowDataMap); + CacheUtils.put(CacheConstants.REPEAT_SUBMIT_KEY, cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS); + return false; + } + + /** + * 判断参数是否相同 + */ + private boolean compareParams(Map nowMap, Map preMap) + { + String nowParams = (String) nowMap.get(REPEAT_PARAMS); + String preParams = (String) preMap.get(REPEAT_PARAMS); + return nowParams.equals(preParams); + } + + /** + * 判断两次间隔时间 + */ + private boolean compareTime(Map nowMap, Map preMap, int interval) + { + long time1 = (Long) nowMap.get(REPEAT_TIME); + long time2 = (Long) preMap.get(REPEAT_TIME); + if ((time1 - time2) < interval) + { + return true; + } + return false; + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/manager/AsyncManager.java b/boyue-framework/src/main/java/com/boyue/framework/manager/AsyncManager.java new file mode 100644 index 0000000..d69760f --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/manager/AsyncManager.java @@ -0,0 +1,55 @@ +package com.boyue.framework.manager; + +import java.util.TimerTask; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import com.boyue.common.utils.Threads; +import com.boyue.common.utils.spring.SpringUtils; + +/** + * 异步任务管理器 + * + * @author boyue + */ +public class AsyncManager +{ + /** + * 操作延迟10毫秒 + */ + private final int OPERATE_DELAY_TIME = 10; + + /** + * 异步操作任务调度线程池 + */ + private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService"); + + /** + * 单例模式 + */ + private AsyncManager(){} + + private static AsyncManager me = new AsyncManager(); + + public static AsyncManager me() + { + return me; + } + + /** + * 执行任务 + * + * @param task 任务 + */ + public void execute(TimerTask task) + { + executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS); + } + + /** + * 停止任务线程池 + */ + public void shutdown() + { + Threads.shutdownAndAwaitTermination(executor); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/manager/ShutdownManager.java b/boyue-framework/src/main/java/com/boyue/framework/manager/ShutdownManager.java new file mode 100644 index 0000000..8195691 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/manager/ShutdownManager.java @@ -0,0 +1,43 @@ +package com.boyue.framework.manager; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import com.boyue.common.utils.http.HttpUtils; + +import jakarta.annotation.PreDestroy; + +/** + * 确保应用退出时能关闭后台线程 + * + * @author boyue + */ +@Component +public class ShutdownManager +{ + private static final Logger logger = LoggerFactory.getLogger("sys-user"); + + @PreDestroy + public void destroy() + { + shutdownAsyncManager(); + HttpUtils.shutdown(); + } + + /** + * 停止异步执行任务 + */ + private void shutdownAsyncManager() + { + try + { + logger.info("====关闭后台任务任务线程池===="); + AsyncManager.me().shutdown(); + } + catch (Exception e) + { + logger.error(e.getMessage(), e); + } + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/manager/factory/AsyncFactory.java b/boyue-framework/src/main/java/com/boyue/framework/manager/factory/AsyncFactory.java new file mode 100644 index 0000000..7156026 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/manager/factory/AsyncFactory.java @@ -0,0 +1,102 @@ +package com.boyue.framework.manager.factory; + +import java.util.TimerTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.boyue.common.constant.Constants; +import com.boyue.common.utils.LogUtils; +import com.boyue.common.utils.ServletUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.ip.AddressUtils; +import com.boyue.common.utils.ip.IpUtils; +import com.boyue.common.utils.spring.SpringUtils; +import com.boyue.system.domain.SysLogininfor; +import com.boyue.system.domain.SysOperLog; +import com.boyue.system.service.ISysLogininforService; +import com.boyue.system.service.ISysOperLogService; +import eu.bitwalker.useragentutils.UserAgent; + +/** + * 异步工厂(产生任务用) + * + * @author boyue + */ +public class AsyncFactory +{ + private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user"); + + /** + * 记录登录信息 + * + * @param username 用户名 + * @param status 状态 + * @param message 消息 + * @param args 列表 + * @return 任务task + */ + public static TimerTask recordLogininfor(final String username, final String status, final String message, + final Object... args) + { + final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); + final String ip = IpUtils.getIpAddr(); + return new TimerTask() + { + @Override + public void run() + { + String address = AddressUtils.getRealAddressByIP(ip); + StringBuilder s = new StringBuilder(); + s.append(LogUtils.getBlock(ip)); + s.append(address); + s.append(LogUtils.getBlock(username)); + s.append(LogUtils.getBlock(status)); + s.append(LogUtils.getBlock(message)); + // 打印信息到日志 + sys_user_logger.info(s.toString(), args); + // 获取客户端操作系统 + String os = userAgent.getOperatingSystem().getName(); + // 获取客户端浏览器 + String browser = userAgent.getBrowser().getName(); + // 封装对象 + SysLogininfor logininfor = new SysLogininfor(); + logininfor.setUserName(username); + logininfor.setIpaddr(ip); + logininfor.setLoginLocation(address); + logininfor.setBrowser(browser); + logininfor.setOs(os); + logininfor.setMsg(message); + // 日志状态 + if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) + { + logininfor.setStatus(Constants.SUCCESS); + } + else if (Constants.LOGIN_FAIL.equals(status)) + { + logininfor.setStatus(Constants.FAIL); + } + // 插入数据 + SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor); + } + }; + } + + /** + * 操作日志记录 + * + * @param operLog 操作日志信息 + * @return 任务task + */ + public static TimerTask recordOper(final SysOperLog operLog) + { + return new TimerTask() + { + @Override + public void run() + { + // 远程查询操作地点 + operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp())); + SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog); + } + }; + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/security/context/AuthenticationContextHolder.java b/boyue-framework/src/main/java/com/boyue/framework/security/context/AuthenticationContextHolder.java new file mode 100644 index 0000000..95d7e92 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/security/context/AuthenticationContextHolder.java @@ -0,0 +1,28 @@ +package com.boyue.framework.security.context; + +import org.springframework.security.core.Authentication; + +/** + * 身份验证信息 + * + * @author boyue + */ +public class AuthenticationContextHolder +{ + private static final ThreadLocal contextHolder = new ThreadLocal<>(); + + public static Authentication getContext() + { + return contextHolder.get(); + } + + public static void setContext(Authentication context) + { + contextHolder.set(context); + } + + public static void clearContext() + { + contextHolder.remove(); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/security/context/PermissionContextHolder.java b/boyue-framework/src/main/java/com/boyue/framework/security/context/PermissionContextHolder.java new file mode 100644 index 0000000..4afadf1 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/security/context/PermissionContextHolder.java @@ -0,0 +1,27 @@ +package com.boyue.framework.security.context; + +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import com.boyue.common.core.text.Convert; + +/** + * 权限信息 + * + * @author boyue + */ +public class PermissionContextHolder +{ + private static final String PERMISSION_CONTEXT_ATTRIBUTES = "PERMISSION_CONTEXT"; + + public static void setContext(String permission) + { + RequestContextHolder.currentRequestAttributes().setAttribute(PERMISSION_CONTEXT_ATTRIBUTES, permission, + RequestAttributes.SCOPE_REQUEST); + } + + public static String getContext() + { + return Convert.toStr(RequestContextHolder.currentRequestAttributes().getAttribute(PERMISSION_CONTEXT_ATTRIBUTES, + RequestAttributes.SCOPE_REQUEST)); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/security/filter/JwtAuthenticationTokenFilter.java b/boyue-framework/src/main/java/com/boyue/framework/security/filter/JwtAuthenticationTokenFilter.java new file mode 100644 index 0000000..803db64 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/security/filter/JwtAuthenticationTokenFilter.java @@ -0,0 +1,44 @@ +package com.boyue.framework.security.filter; + +import java.io.IOException; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.framework.web.service.TokenService; + +/** + * token过滤器 验证token有效性 + * + * @author boyue + */ +@Component +public class JwtAuthenticationTokenFilter extends OncePerRequestFilter +{ + @Autowired + private TokenService tokenService; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) + throws ServletException, IOException + { + LoginUser loginUser = tokenService.getLoginUser(request); + if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication())) + { + tokenService.verifyToken(loginUser); + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities()); + authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authenticationToken); + } + chain.doFilter(request, response); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/security/handle/AuthenticationEntryPointImpl.java b/boyue-framework/src/main/java/com/boyue/framework/security/handle/AuthenticationEntryPointImpl.java new file mode 100644 index 0000000..0b2380d --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/security/handle/AuthenticationEntryPointImpl.java @@ -0,0 +1,34 @@ +package com.boyue.framework.security.handle; + +import java.io.IOException; +import java.io.Serializable; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; +import com.alibaba.fastjson2.JSON; +import com.boyue.common.constant.HttpStatus; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.utils.ServletUtils; +import com.boyue.common.utils.StringUtils; + +/** + * 认证失败处理类 返回未授权 + * + * @author boyue + */ +@Component +public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable +{ + private static final long serialVersionUID = -8970718410437077606L; + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) + throws IOException + { + int code = HttpStatus.UNAUTHORIZED; + String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI()); + ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg))); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/security/handle/LogoutSuccessHandlerImpl.java b/boyue-framework/src/main/java/com/boyue/framework/security/handle/LogoutSuccessHandlerImpl.java new file mode 100644 index 0000000..915e4de --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/security/handle/LogoutSuccessHandlerImpl.java @@ -0,0 +1,55 @@ +package com.boyue.framework.security.handle; + +import java.io.IOException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; + +import com.alibaba.fastjson2.JSON; +import com.boyue.common.constant.Constants; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.utils.MessageUtils; +import com.boyue.common.utils.ServletUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.framework.manager.AsyncManager; +import com.boyue.framework.manager.factory.AsyncFactory; +import com.boyue.framework.web.service.TokenService; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 自定义退出处理类 返回成功 + * + * @author boyue + */ +@Configuration +public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler { + @Autowired + private TokenService tokenService; + + /** + * 退出处理 + * + * @return + */ + @Override + public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) + throws IOException, ServletException { + LoginUser loginUser = tokenService.getLoginUser(request); + if (StringUtils.isNotNull(loginUser)) { + String userName = loginUser.getUsername(); + // 删除用户缓存记录 + tokenService.delLoginUser(loginUser.getToken()); + // 记录用户退出日志 + AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, + MessageUtils.message("user.logout.success"))); + } + ServletUtils.renderString(response, + JSON.toJSONString(AjaxResult.success(MessageUtils.message("user.logout.success")))); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/web/domain/Server.java b/boyue-framework/src/main/java/com/boyue/framework/web/domain/Server.java new file mode 100644 index 0000000..1fe97c8 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/web/domain/Server.java @@ -0,0 +1,240 @@ +package com.boyue.framework.web.domain; + +import java.net.UnknownHostException; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; +import com.boyue.common.utils.Arith; +import com.boyue.common.utils.ip.IpUtils; +import com.boyue.framework.web.domain.server.Cpu; +import com.boyue.framework.web.domain.server.Jvm; +import com.boyue.framework.web.domain.server.Mem; +import com.boyue.framework.web.domain.server.Sys; +import com.boyue.framework.web.domain.server.SysFile; +import oshi.SystemInfo; +import oshi.hardware.CentralProcessor; +import oshi.hardware.CentralProcessor.TickType; +import oshi.hardware.GlobalMemory; +import oshi.hardware.HardwareAbstractionLayer; +import oshi.software.os.FileSystem; +import oshi.software.os.OSFileStore; +import oshi.software.os.OperatingSystem; +import oshi.util.Util; + +/** + * 服务器相关信息 + * + * @author boyue + */ +public class Server +{ + private static final int OSHI_WAIT_SECOND = 1000; + + /** + * CPU相关信息 + */ + private Cpu cpu = new Cpu(); + + /** + * 內存相关信息 + */ + private Mem mem = new Mem(); + + /** + * JVM相关信息 + */ + private Jvm jvm = new Jvm(); + + /** + * 服务器相关信息 + */ + private Sys sys = new Sys(); + + /** + * 磁盘相关信息 + */ + private List sysFiles = new LinkedList(); + + public Cpu getCpu() + { + return cpu; + } + + public void setCpu(Cpu cpu) + { + this.cpu = cpu; + } + + public Mem getMem() + { + return mem; + } + + public void setMem(Mem mem) + { + this.mem = mem; + } + + public Jvm getJvm() + { + return jvm; + } + + public void setJvm(Jvm jvm) + { + this.jvm = jvm; + } + + public Sys getSys() + { + return sys; + } + + public void setSys(Sys sys) + { + this.sys = sys; + } + + public List getSysFiles() + { + return sysFiles; + } + + public void setSysFiles(List sysFiles) + { + this.sysFiles = sysFiles; + } + + public void copyTo() throws Exception + { + SystemInfo si = new SystemInfo(); + HardwareAbstractionLayer hal = si.getHardware(); + + setCpuInfo(hal.getProcessor()); + + setMemInfo(hal.getMemory()); + + setSysInfo(); + + setJvmInfo(); + + setSysFiles(si.getOperatingSystem()); + } + + /** + * 设置CPU信息 + */ + private void setCpuInfo(CentralProcessor processor) + { + // CPU信息 + long[] prevTicks = processor.getSystemCpuLoadTicks(); + Util.sleep(OSHI_WAIT_SECOND); + long[] ticks = processor.getSystemCpuLoadTicks(); + long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()]; + long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()]; + long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()]; + long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()]; + long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()]; + long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()]; + long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()]; + long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()]; + long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal; + cpu.setCpuNum(processor.getLogicalProcessorCount()); + cpu.setTotal(totalCpu); + cpu.setSys(cSys); + cpu.setUsed(user); + cpu.setWait(iowait); + cpu.setFree(idle); + } + + /** + * 设置内存信息 + */ + private void setMemInfo(GlobalMemory memory) + { + mem.setTotal(memory.getTotal()); + mem.setUsed(memory.getTotal() - memory.getAvailable()); + mem.setFree(memory.getAvailable()); + } + + /** + * 设置服务器信息 + */ + private void setSysInfo() + { + Properties props = System.getProperties(); + sys.setComputerName(IpUtils.getHostName()); + sys.setComputerIp(IpUtils.getHostIp()); + sys.setOsName(props.getProperty("os.name")); + sys.setOsArch(props.getProperty("os.arch")); + sys.setUserDir(props.getProperty("user.dir")); + } + + /** + * 设置Java虚拟机 + */ + private void setJvmInfo() throws UnknownHostException + { + Properties props = System.getProperties(); + jvm.setTotal(Runtime.getRuntime().totalMemory()); + jvm.setMax(Runtime.getRuntime().maxMemory()); + jvm.setFree(Runtime.getRuntime().freeMemory()); + jvm.setVersion(props.getProperty("java.version")); + jvm.setHome(props.getProperty("java.home")); + } + + /** + * 设置磁盘信息 + */ + private void setSysFiles(OperatingSystem os) + { + FileSystem fileSystem = os.getFileSystem(); + List fsArray = fileSystem.getFileStores(); + for (OSFileStore fs : fsArray) + { + long free = fs.getUsableSpace(); + long total = fs.getTotalSpace(); + long used = total - free; + SysFile sysFile = new SysFile(); + sysFile.setDirName(fs.getMount()); + sysFile.setSysTypeName(fs.getType()); + sysFile.setTypeName(fs.getName()); + sysFile.setTotal(convertFileSize(total)); + sysFile.setFree(convertFileSize(free)); + sysFile.setUsed(convertFileSize(used)); + sysFile.setUsage(Arith.mul(Arith.div(used, total, 4), 100)); + sysFiles.add(sysFile); + } + } + + /** + * 字节转换 + * + * @param size 字节大小 + * @return 转换后值 + */ + public String convertFileSize(long size) + { + long kb = 1024; + long mb = kb * 1024; + long gb = mb * 1024; + if (size >= gb) + { + return String.format("%.1f GB", (float) size / gb); + } + else if (size >= mb) + { + float f = (float) size / mb; + return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f); + } + else if (size >= kb) + { + float f = (float) size / kb; + return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f); + } + else + { + return String.format("%d B", size); + } + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/web/domain/server/Cpu.java b/boyue-framework/src/main/java/com/boyue/framework/web/domain/server/Cpu.java new file mode 100644 index 0000000..6e95b37 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/web/domain/server/Cpu.java @@ -0,0 +1,101 @@ +package com.boyue.framework.web.domain.server; + +import com.boyue.common.utils.Arith; + +/** + * CPU相关信息 + * + * @author boyue + */ +public class Cpu +{ + /** + * 核心数 + */ + private int cpuNum; + + /** + * CPU总的使用率 + */ + private double total; + + /** + * CPU系统使用率 + */ + private double sys; + + /** + * CPU用户使用率 + */ + private double used; + + /** + * CPU当前等待率 + */ + private double wait; + + /** + * CPU当前空闲率 + */ + private double free; + + public int getCpuNum() + { + return cpuNum; + } + + public void setCpuNum(int cpuNum) + { + this.cpuNum = cpuNum; + } + + public double getTotal() + { + return Arith.round(Arith.mul(total, 100), 2); + } + + public void setTotal(double total) + { + this.total = total; + } + + public double getSys() + { + return Arith.round(Arith.mul(sys / total, 100), 2); + } + + public void setSys(double sys) + { + this.sys = sys; + } + + public double getUsed() + { + return Arith.round(Arith.mul(used / total, 100), 2); + } + + public void setUsed(double used) + { + this.used = used; + } + + public double getWait() + { + return Arith.round(Arith.mul(wait / total, 100), 2); + } + + public void setWait(double wait) + { + this.wait = wait; + } + + public double getFree() + { + return Arith.round(Arith.mul(free / total, 100), 2); + } + + public void setFree(double free) + { + this.free = free; + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/web/domain/server/Jvm.java b/boyue-framework/src/main/java/com/boyue/framework/web/domain/server/Jvm.java new file mode 100644 index 0000000..ae27795 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/web/domain/server/Jvm.java @@ -0,0 +1,130 @@ +package com.boyue.framework.web.domain.server; + +import java.lang.management.ManagementFactory; +import com.boyue.common.utils.Arith; +import com.boyue.common.utils.DateUtils; + +/** + * JVM相关信息 + * + * @author boyue + */ +public class Jvm +{ + /** + * 当前JVM占用的内存总数(M) + */ + private double total; + + /** + * JVM最大可用内存总数(M) + */ + private double max; + + /** + * JVM空闲内存(M) + */ + private double free; + + /** + * JDK版本 + */ + private String version; + + /** + * JDK路径 + */ + private String home; + + public double getTotal() + { + return Arith.div(total, (1024 * 1024), 2); + } + + public void setTotal(double total) + { + this.total = total; + } + + public double getMax() + { + return Arith.div(max, (1024 * 1024), 2); + } + + public void setMax(double max) + { + this.max = max; + } + + public double getFree() + { + return Arith.div(free, (1024 * 1024), 2); + } + + public void setFree(double free) + { + this.free = free; + } + + public double getUsed() + { + return Arith.div(total - free, (1024 * 1024), 2); + } + + public double getUsage() + { + return Arith.mul(Arith.div(total - free, total, 4), 100); + } + + /** + * 获取JDK名称 + */ + public String getName() + { + return ManagementFactory.getRuntimeMXBean().getVmName(); + } + + public String getVersion() + { + return version; + } + + public void setVersion(String version) + { + this.version = version; + } + + public String getHome() + { + return home; + } + + public void setHome(String home) + { + this.home = home; + } + + /** + * JDK启动时间 + */ + public String getStartTime() + { + return DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getServerStartDate()); + } + + /** + * JDK运行时间 + */ + public String getRunTime() + { + return DateUtils.timeDistance(DateUtils.getNowDate(), DateUtils.getServerStartDate()); + } + + /** + * 运行参数 + */ + public String getInputArgs() + { + return ManagementFactory.getRuntimeMXBean().getInputArguments().toString(); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/web/domain/server/Mem.java b/boyue-framework/src/main/java/com/boyue/framework/web/domain/server/Mem.java new file mode 100644 index 0000000..0c7fc87 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/web/domain/server/Mem.java @@ -0,0 +1,61 @@ +package com.boyue.framework.web.domain.server; + +import com.boyue.common.utils.Arith; + +/** + * 內存相关信息 + * + * @author boyue + */ +public class Mem +{ + /** + * 内存总量 + */ + private double total; + + /** + * 已用内存 + */ + private double used; + + /** + * 剩余内存 + */ + private double free; + + public double getTotal() + { + return Arith.div(total, (1024 * 1024 * 1024), 2); + } + + public void setTotal(long total) + { + this.total = total; + } + + public double getUsed() + { + return Arith.div(used, (1024 * 1024 * 1024), 2); + } + + public void setUsed(long used) + { + this.used = used; + } + + public double getFree() + { + return Arith.div(free, (1024 * 1024 * 1024), 2); + } + + public void setFree(long free) + { + this.free = free; + } + + public double getUsage() + { + return Arith.mul(Arith.div(used, total, 4), 100); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/web/domain/server/Sys.java b/boyue-framework/src/main/java/com/boyue/framework/web/domain/server/Sys.java new file mode 100644 index 0000000..a39a8ca --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/web/domain/server/Sys.java @@ -0,0 +1,84 @@ +package com.boyue.framework.web.domain.server; + +/** + * 系统相关信息 + * + * @author boyue + */ +public class Sys +{ + /** + * 服务器名称 + */ + private String computerName; + + /** + * 服务器Ip + */ + private String computerIp; + + /** + * 项目路径 + */ + private String userDir; + + /** + * 操作系统 + */ + private String osName; + + /** + * 系统架构 + */ + private String osArch; + + public String getComputerName() + { + return computerName; + } + + public void setComputerName(String computerName) + { + this.computerName = computerName; + } + + public String getComputerIp() + { + return computerIp; + } + + public void setComputerIp(String computerIp) + { + this.computerIp = computerIp; + } + + public String getUserDir() + { + return userDir; + } + + public void setUserDir(String userDir) + { + this.userDir = userDir; + } + + public String getOsName() + { + return osName; + } + + public void setOsName(String osName) + { + this.osName = osName; + } + + public String getOsArch() + { + return osArch; + } + + public void setOsArch(String osArch) + { + this.osArch = osArch; + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/web/domain/server/SysFile.java b/boyue-framework/src/main/java/com/boyue/framework/web/domain/server/SysFile.java new file mode 100644 index 0000000..f96bb8c --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/web/domain/server/SysFile.java @@ -0,0 +1,114 @@ +package com.boyue.framework.web.domain.server; + +/** + * 系统文件相关信息 + * + * @author boyue + */ +public class SysFile +{ + /** + * 盘符路径 + */ + private String dirName; + + /** + * 盘符类型 + */ + private String sysTypeName; + + /** + * 文件类型 + */ + private String typeName; + + /** + * 总大小 + */ + private String total; + + /** + * 剩余大小 + */ + private String free; + + /** + * 已经使用量 + */ + private String used; + + /** + * 资源的使用率 + */ + private double usage; + + public String getDirName() + { + return dirName; + } + + public void setDirName(String dirName) + { + this.dirName = dirName; + } + + public String getSysTypeName() + { + return sysTypeName; + } + + public void setSysTypeName(String sysTypeName) + { + this.sysTypeName = sysTypeName; + } + + public String getTypeName() + { + return typeName; + } + + public void setTypeName(String typeName) + { + this.typeName = typeName; + } + + public String getTotal() + { + return total; + } + + public void setTotal(String total) + { + this.total = total; + } + + public String getFree() + { + return free; + } + + public void setFree(String free) + { + this.free = free; + } + + public String getUsed() + { + return used; + } + + public void setUsed(String used) + { + this.used = used; + } + + public double getUsage() + { + return usage; + } + + public void setUsage(double usage) + { + this.usage = usage; + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/web/exception/GlobalExceptionHandler.java b/boyue-framework/src/main/java/com/boyue/framework/web/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..bf0169b --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/web/exception/GlobalExceptionHandler.java @@ -0,0 +1,137 @@ +package com.boyue.framework.web.exception; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.validation.BindException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingPathVariableException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; + +import com.boyue.common.constant.HttpStatus; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.text.Convert; +import com.boyue.common.exception.DemoModeException; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.html.EscapeUtil; + +import jakarta.servlet.http.HttpServletRequest; + +/** + * 全局异常处理器 + * + * @author boyue + */ +@RestControllerAdvice +public class GlobalExceptionHandler { + private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); + + /** + * 权限校验异常 + */ + @ExceptionHandler(AccessDeniedException.class) + public AjaxResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',权限校验失败'{}'", requestURI, e.getMessage()); + return AjaxResult.error(HttpStatus.FORBIDDEN, "没有权限,请联系管理员授权"); + } + + /** + * 请求方式不支持 + */ + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, + HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod()); + return AjaxResult.error(e.getMessage()); + } + + /** + * 业务异常 + */ + @ExceptionHandler(ServiceException.class) + public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request) { + log.error(e.getMessage(), e); + Integer code = e.getCode(); + return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage()); + } + + /** + * 请求路径中缺少必需的路径变量 + */ + @ExceptionHandler(MissingPathVariableException.class) + public AjaxResult handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e); + return AjaxResult.error(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName())); + } + + /** + * 请求参数类型不匹配 + */ + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + public AjaxResult handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, + HttpServletRequest request) { + String requestURI = request.getRequestURI(); + String value = Convert.toStr(e.getValue()); + if (StringUtils.isNotEmpty(value)) { + value = EscapeUtil.clean(value); + } + log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e); + return AjaxResult.error(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), + e.getRequiredType().getName(), value)); + } + + /** + * 拦截未知的运行时异常 + */ + @ExceptionHandler(RuntimeException.class) + public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',发生未知异常.", requestURI, e); + return AjaxResult.error(e.getMessage()); + } + + /** + * 系统异常 + */ + @ExceptionHandler(Exception.class) + public AjaxResult handleException(Exception e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',发生系统异常.", requestURI, e); + return AjaxResult.error(e.getMessage()); + } + + /** + * 自定义验证异常 + */ + @ExceptionHandler(BindException.class) + public AjaxResult handleBindException(BindException e) { + log.error(e.getMessage(), e); + String message = e.getAllErrors().get(0).getDefaultMessage(); + return AjaxResult.error(message); + } + + /** + * 自定义验证异常 + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + log.error(e.getMessage(), e); + String message = e.getBindingResult().getFieldError().getDefaultMessage(); + return AjaxResult.error(message); + } + + /** + * 演示模式异常 + */ + @ExceptionHandler(DemoModeException.class) + public AjaxResult handleDemoModeException(DemoModeException e) { + return AjaxResult.error("演示模式,不允许操作"); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/web/service/PermissionService.java b/boyue-framework/src/main/java/com/boyue/framework/web/service/PermissionService.java new file mode 100644 index 0000000..718c6c5 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/web/service/PermissionService.java @@ -0,0 +1,130 @@ +package com.boyue.framework.web.service; + +import java.util.Set; + +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.core.security.service.IPermissionService; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.framework.security.context.PermissionContextHolder; + +/** + * boyue首创 自定义权限实现,ss取自SpringSecurity首字母 + * Geek改进 将自定义权限实现形成规范,提高扩展性 + * + * @author boyue&&Dftre + */ +@Service("ss") +public class PermissionService implements IPermissionService { + /** 所有权限标识 */ + private static final String ALL_PERMISSION = "*:*:*"; + + /** 管理员角色权限标识 */ + private static final String SUPER_ADMIN = "admin"; + + private static final String ROLE_DELIMETER = ","; + + private static final String PERMISSION_DELIMETER = ","; + + /** + * 验证用户是否具备某权限 + * + * @param permission 权限字符串 + * @return 用户是否具备某权限 + */ + public boolean hasPermi(String permission) { + if (StringUtils.isEmpty(permission)) { + return false; + } + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) { + return false; + } + PermissionContextHolder.setContext(permission); + return hasPermissions(loginUser.getPermissions(), permission); + } + + /** + * 验证用户是否具有以下任意一个权限 + * + * @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表 + * @return 用户是否具有以下任意一个权限 + */ + public boolean hasAnyPermi(String permissions) { + if (StringUtils.isEmpty(permissions)) { + return false; + } + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) { + return false; + } + PermissionContextHolder.setContext(permissions); + Set authorities = loginUser.getPermissions(); + for (String permission : permissions.split(PERMISSION_DELIMETER)) { + if (permission != null && hasPermissions(authorities, permission)) { + return true; + } + } + return false; + } + + /** + * 判断用户是否拥有某个角色 + * + * @param role 角色字符串 + * @return 用户是否具备某角色 + */ + public boolean hasRole(String role) { + if (StringUtils.isEmpty(role)) { + return false; + } + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles())) { + return false; + } + for (SysRole sysRole : loginUser.getUser().getRoles()) { + String roleKey = sysRole.getRoleKey(); + if (SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role))) { + return true; + } + } + return false; + } + + /** + * 验证用户是否具有以下任意一个角色 + * + * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表 + * @return 用户是否具有以下任意一个角色 + */ + public boolean hasAnyRoles(String roles) { + if (StringUtils.isEmpty(roles)) { + return false; + } + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles())) { + return false; + } + for (String role : roles.split(ROLE_DELIMETER)) { + if (hasRole(role)) { + return true; + } + } + return false; + } + + /** + * 判断是否包含权限 + * + * @param permissions 权限列表 + * @param permission 权限字符串 + * @return 用户是否具备某权限 + */ + private boolean hasPermissions(Set permissions, String permission) { + return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission)); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/web/service/SysLoginService.java b/boyue-framework/src/main/java/com/boyue/framework/web/service/SysLoginService.java new file mode 100644 index 0000000..b7bd9cd --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/web/service/SysLoginService.java @@ -0,0 +1,186 @@ +package com.boyue.framework.web.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; + +import com.boyue.common.constant.CacheConstants; +import com.boyue.common.constant.Constants; +import com.boyue.common.constant.UserConstants; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.exception.user.BlackListException; +import com.boyue.common.exception.user.CaptchaException; +import com.boyue.common.exception.user.CaptchaExpireException; +import com.boyue.common.exception.user.UserNotExistsException; +import com.boyue.common.exception.user.UserPasswordNotMatchException; +import com.boyue.common.utils.CacheUtils; +import com.boyue.common.utils.DateUtils; +import com.boyue.common.utils.MessageUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.ip.IpUtils; +import com.boyue.framework.manager.AsyncManager; +import com.boyue.framework.manager.factory.AsyncFactory; +import com.boyue.framework.security.context.AuthenticationContextHolder; +import com.boyue.system.service.ISysConfigService; +import com.boyue.system.service.ISysUserService; + +import jakarta.annotation.Resource; + +/** + * 登录校验方法 + * + * @author boyue + */ +@Component +public class SysLoginService +{ + @Autowired + private TokenService tokenService; + + @Resource + private AuthenticationManager authenticationManager; + + @Autowired + private ISysUserService userService; + + @Autowired + private ISysConfigService configService; + + @Autowired + private SysPasswordService passwordService; + + /** + * 登录验证 + * + * @param username 用户名 + * @param password 密码 + * @param code 验证码 + * @param uuid 唯一标识 + * @return 结果 + */ + public String login(String username, String password, String code, String uuid) + { + // 验证码校验 + validateCaptcha(username, code, uuid); + // 登录前置校验 + loginPreCheck(username, password); + String ip = IpUtils.getIpAddr(); + // 验证 IP 是否被封锁 + passwordService.validateIp(ip); + // 用户验证 + Authentication authentication = null; + try + { + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password); + AuthenticationContextHolder.setContext(authenticationToken); + // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername + authentication = authenticationManager.authenticate(authenticationToken); + } + catch (Exception e) + { + if (e instanceof BadCredentialsException) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); + throw new UserPasswordNotMatchException(); + } + else + { + passwordService.incrementIpFailCount(ip); + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage())); + throw new ServiceException(e.getMessage()); + } + } + finally + { + AuthenticationContextHolder.clearContext(); + } + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"))); + LoginUser loginUser = (LoginUser) authentication.getPrincipal(); + recordLoginInfo(loginUser.getUserId()); + // 生成token + return tokenService.createToken(loginUser); + } + + /** + * 校验验证码 + * + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + * @return 结果 + */ + public void validateCaptcha(String username, String code, String uuid) + { + boolean captchaEnabled = configService.selectCaptchaEnabled(); + if (captchaEnabled) + { + String captcha = CacheUtils.get(CacheConstants.CAPTCHA_CODE_KEY, StringUtils.nvl(uuid, ""), String.class); + CacheUtils.removeIfPresent(CacheConstants.CAPTCHA_CODE_KEY, StringUtils.nvl(uuid, "")); + if (captcha == null) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"))); + throw new CaptchaExpireException(); + } + if (!code.equalsIgnoreCase(captcha)) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"))); + throw new CaptchaException(); + } + } + } + + /** + * 登录前置校验 + * @param username 用户名 + * @param password 用户密码 + */ + public void loginPreCheck(String username, String password) + { + // 用户名或密码为空 错误 + if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null"))); + throw new UserNotExistsException(); + } + // 密码如果不在指定范围内 错误 + if (password.length() < UserConstants.PASSWORD_MIN_LENGTH + || password.length() > UserConstants.PASSWORD_MAX_LENGTH) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,MessageUtils.message("user.password.not.match"))); + throw new UserPasswordNotMatchException(); + } + // 用户名不在指定范围内 错误 + if (username.length() < UserConstants.USERNAME_MIN_LENGTH + || username.length() > UserConstants.USERNAME_MAX_LENGTH) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); + throw new UserPasswordNotMatchException(); + } + // IP黑名单校验 + String blackStr = configService.selectConfigByKey("sys.login.blackIPList"); + if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked"))); + throw new BlackListException(); + } + } + + /** + * 记录登录信息 + * + * @param userId 用户ID + */ + public void recordLoginInfo(Long userId) + { + SysUser sysUser = new SysUser(); + sysUser.setUserId(userId); + sysUser.setLoginIp(IpUtils.getIpAddr()); + sysUser.setLoginDate(DateUtils.getNowDate()); + userService.updateUserProfile(sysUser); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/web/service/SysPasswordService.java b/boyue-framework/src/main/java/com/boyue/framework/web/service/SysPasswordService.java new file mode 100644 index 0000000..cfb79b6 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/web/service/SysPasswordService.java @@ -0,0 +1,125 @@ +package com.boyue.framework.web.service; + +import com.boyue.common.exception.user.IpRetryLimitExceedException; +import com.boyue.common.utils.ip.IpUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.Cache; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; + +import com.boyue.common.constant.CacheConstants; +import com.boyue.common.constant.Constants; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.exception.user.UserPasswordNotMatchException; +import com.boyue.common.exception.user.UserPasswordRetryLimitExceedException; +import com.boyue.common.utils.CacheUtils; +import com.boyue.common.utils.MessageUtils; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.framework.manager.AsyncManager; +import com.boyue.framework.manager.factory.AsyncFactory; +import com.boyue.framework.security.context.AuthenticationContextHolder; + +import java.util.concurrent.TimeUnit; + +/** + * 登录密码方法 + * + * @author boyue + */ +@Component +public class SysPasswordService +{ + + @Value(value = "${user.password.maxRetryCount}") + private int maxRetryCount; + + @Value(value = "${user.password.lockTime}") + private int lockTime; + + @Value(value = "${user.ip.maxRetryCount:15}") + public int maxIpRetryCount; + + @Value(value = "${user.ip.lockTime:15}") + public int ipLockTime; + /** + * 登录账户密码错误次数缓存键名 + * + * @return 缓存Cache + */ + private Cache getCache() + { + return CacheUtils.getCache(CacheConstants.PWD_ERR_CNT_KEY); + } + + private Cache getIpCache() { + return CacheUtils.getCache(CacheConstants.IP_ERR_CNT_KEY); + } + + public void validate(SysUser user) + { + Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext(); + String username = usernamePasswordAuthenticationToken.getName(); + String password = usernamePasswordAuthenticationToken.getCredentials().toString(); + + String ip = IpUtils.getIpAddr(); + validateIp(ip); + Integer retryCount = getCache().get(username, Integer.class); + if (retryCount == null) + { + retryCount = 0; + } + if (retryCount >= Integer.valueOf(maxRetryCount).intValue()) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, + MessageUtils.message("user.password.retry.limit.exceed", maxRetryCount, lockTime))); + throw new UserPasswordRetryLimitExceedException(maxRetryCount, lockTime); + } + if (!matches(user, password)) + { + retryCount = retryCount + 1; + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, + MessageUtils.message("user.password.retry.limit.count", retryCount))); + CacheUtils.put(CacheConstants.PWD_ERR_CNT_KEY,username,retryCount,lockTime,TimeUnit.MINUTES); + throw new UserPasswordNotMatchException(); + } + else + { + clearLoginRecordCache(username); + } + } + + public void validateIp(String ip) + { + Integer ipRetryCount = getIpCache().get(ip, Integer.class); + if (ipRetryCount == null) + { + ipRetryCount = 0; + } + + if (ipRetryCount >= maxIpRetryCount) + { + throw new IpRetryLimitExceedException(maxIpRetryCount, ipLockTime); + } + } + + public void incrementIpFailCount(String ip) + { + Integer ipRetryCount = getIpCache().get(ip, Integer.class); + if (ipRetryCount == null) + { + ipRetryCount = 0; + } + ipRetryCount += 1; + CacheUtils.put(CacheConstants.IP_ERR_CNT_KEY,ip,ipRetryCount,ipLockTime,TimeUnit.MINUTES); + } + + public boolean matches(SysUser user, String rawPassword) + { + return SecurityUtils.matchesPassword(rawPassword, user.getPassword()); + } + + public void clearLoginRecordCache(String loginName) + { + getCache().evictIfPresent(loginName); + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/web/service/SysPermissionService.java b/boyue-framework/src/main/java/com/boyue/framework/web/service/SysPermissionService.java new file mode 100644 index 0000000..5544841 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/web/service/SysPermissionService.java @@ -0,0 +1,76 @@ +package com.boyue.framework.web.service; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import com.boyue.common.constant.UserConstants; +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.utils.StringUtils; +import com.boyue.system.service.ISysMenuService; +import com.boyue.system.service.ISysRoleService; + +/** + * 用户权限处理 + * + * @author boyue + */ +@Component +public class SysPermissionService { + @Autowired + private ISysRoleService roleService; + + @Autowired + private ISysMenuService menuService; + + /** + * 获取角色数据权限 + * + * @param user 用户信息 + * @return 角色权限信息 + */ + public Set getRolePermission(SysUser user) { + Set roles = new HashSet(); + // 管理员拥有所有权限 + if (user.isAdmin()) { + roles.add("admin"); + } else { + roles.addAll(roleService.selectRolePermissionByUserId(user.getUserId())); + } + return roles; + } + + /** + * 获取菜单数据权限 + * + * @param user 用户信息 + * @return 菜单权限信息 + */ + public Set getMenuPermission(SysUser user) { + Set perms = new HashSet(); + // 管理员拥有所有权限 + if (user.isAdmin()) { + perms.add("*:*:*"); + } else { + List roles = user.getRoles(); + if (!CollectionUtils.isEmpty(roles)) { + // 多角色设置permissions属性,以便数据权限匹配权限 + for (SysRole role : roles) { + if (StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL)) { + Set rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId()); + role.setPermissions(rolePerms); + perms.addAll(rolePerms); + } + } + } else { + perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId())); + } + } + return perms; + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/web/service/SysRegisterService.java b/boyue-framework/src/main/java/com/boyue/framework/web/service/SysRegisterService.java new file mode 100644 index 0000000..6719aa8 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/web/service/SysRegisterService.java @@ -0,0 +1,110 @@ +package com.boyue.framework.web.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.boyue.common.constant.CacheConstants; +import com.boyue.common.constant.Constants; +import com.boyue.common.constant.UserConstants; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.domain.model.RegisterBody; +import com.boyue.common.exception.user.CaptchaException; +import com.boyue.common.exception.user.CaptchaExpireException; +import com.boyue.common.utils.CacheUtils; +import com.boyue.common.utils.MessageUtils; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.framework.manager.AsyncManager; +import com.boyue.framework.manager.factory.AsyncFactory; +import com.boyue.system.service.ISysConfigService; +import com.boyue.system.service.ISysUserService; + +/** + * 注册校验方法 + * + * @author boyue + */ +@Component +public class SysRegisterService +{ + @Autowired + private ISysUserService userService; + + @Autowired + private ISysConfigService configService; + + /** + * 注册 + */ + public String register(RegisterBody registerBody) + { + String msg = "", username = registerBody.getUsername(), password = registerBody.getPassword(); + SysUser sysUser = new SysUser(); + sysUser.setUserName(username); + // 验证码开关 + boolean captchaEnabled = configService.selectCaptchaEnabled(); + if (captchaEnabled) + { + validateCaptcha(username, registerBody.getCode(), registerBody.getUuid()); + } + if (StringUtils.isEmpty(username)) + { + msg = "用户名不能为空"; + } + else if (StringUtils.isEmpty(password)) + { + msg = "用户密码不能为空"; + } + else if (username.length() < UserConstants.USERNAME_MIN_LENGTH + || username.length() > UserConstants.USERNAME_MAX_LENGTH) + { + msg = "账户长度必须在2到20个字符之间"; + } + else if (password.length() < UserConstants.PASSWORD_MIN_LENGTH + || password.length() > UserConstants.PASSWORD_MAX_LENGTH) + { + msg = "密码长度必须在5到20个字符之间"; + } + else if (!userService.checkUserNameUnique(sysUser)) + { + msg = "保存用户'" + username + "'失败,注册账号已存在"; + } + else + { + sysUser.setNickName(username); + sysUser.setPassword(SecurityUtils.encryptPassword(password)); + boolean regFlag = userService.registerUser(sysUser); + if (!regFlag) + { + msg = "注册失败,请联系系统管理人员"; + } + else + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.REGISTER, MessageUtils.message("user.register.success"))); + } + } + return msg; + } + + /** + * 校验验证码 + * + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + * @return 结果 + */ + public void validateCaptcha(String username, String code, String uuid) + { + String captcha = CacheUtils.get(CacheConstants.CAPTCHA_CODE_KEY, StringUtils.nvl(uuid, ""), String.class); + CacheUtils.removeIfPresent(CacheConstants.CAPTCHA_CODE_KEY, StringUtils.nvl(uuid, "")); + if (captcha == null) + { + throw new CaptchaExpireException(); + } + if (!code.equalsIgnoreCase(captcha)) + { + throw new CaptchaException(); + } + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/web/service/TokenService.java b/boyue-framework/src/main/java/com/boyue/framework/web/service/TokenService.java new file mode 100644 index 0000000..b9982eb --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/web/service/TokenService.java @@ -0,0 +1,203 @@ +package com.boyue.framework.web.service; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import javax.crypto.SecretKey; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import com.boyue.common.constant.CacheConstants; +import com.boyue.common.constant.Constants; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.utils.CacheUtils; +import com.boyue.common.utils.ServletUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.ip.AddressUtils; +import com.boyue.common.utils.ip.IpUtils; +import com.boyue.common.utils.uuid.IdUtils; + +import eu.bitwalker.useragentutils.UserAgent; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import jakarta.servlet.http.HttpServletRequest; + +/** + * token验证处理 + * + * @author boyue + */ +@Component +public class TokenService { + // 令牌自定义标识 + @Value("${token.header}") + private String header; + + // 令牌秘钥 + @Value("${token.secret}") + private String secret; + + // 令牌有效期(默认30分钟) + @Value("${token.expireTime}") + private int expireTime; + + protected static final long MILLIS_SECOND = 1000; + + protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; + + private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L; + + /** + * 获取用户身份信息 + * + * @return 用户信息 + */ + public LoginUser getLoginUser(HttpServletRequest request) { + // 获取请求携带的令牌 + String token = getToken(request); + if (StringUtils.isNotEmpty(token)) { + try { + Claims claims = parseToken(token); + // 解析对应的权限以及用户信息 + String uuid = (String) claims.get(Constants.LOGIN_USER_KEY); + LoginUser user = CacheUtils.get(CacheConstants.LOGIN_TOKEN_KEY, uuid, LoginUser.class); + return user; + } catch (Exception e) { + } + } + return null; + } + + /** + * 设置用户身份信息 + */ + public void setLoginUser(LoginUser loginUser) { + if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) { + refreshToken(loginUser); + } + } + + /** + * 删除用户身份信息 + */ + public void delLoginUser(String token) { + if (StringUtils.isNotEmpty(token)) { + CacheUtils.removeIfPresent(CacheConstants.LOGIN_TOKEN_KEY, token); + } + } + + /** + * 创建令牌 + * + * @param loginUser 用户信息 + * @return 令牌 + */ + public String createToken(LoginUser loginUser) { + String token = IdUtils.fastUUID(); + loginUser.setToken(token); + setUserAgent(loginUser); + refreshToken(loginUser); + Map claims = new HashMap<>(); + claims.put(Constants.LOGIN_USER_KEY, token); + return createToken(claims); + } + + /** + * 验证令牌有效期,相差不足20分钟,自动刷新缓存 + * + * @param loginUser + * @return 令牌 + */ + public void verifyToken(LoginUser loginUser) { + long expireTime = loginUser.getExpireTime(); + long currentTime = System.currentTimeMillis(); + if (expireTime - currentTime <= MILLIS_MINUTE_TEN) { + refreshToken(loginUser); + } + } + + /** + * 刷新令牌有效期 + * + * @param loginUser 登录信息 + */ + public void refreshToken(LoginUser loginUser) { + loginUser.setLoginTime(System.currentTimeMillis()); + loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE); + // 根据uuid将loginUser缓存 + CacheUtils.put(CacheConstants.LOGIN_TOKEN_KEY, loginUser.getToken(), loginUser, expireTime, TimeUnit.MINUTES); + } + + /** + * 设置用户代理信息 + * + * @param loginUser 登录信息 + */ + public void setUserAgent(LoginUser loginUser) { + UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); + String ip = IpUtils.getIpAddr(); + loginUser.setIpaddr(ip); + loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); + loginUser.setBrowser(userAgent.getBrowser().getName()); + loginUser.setOs(userAgent.getOperatingSystem().getName()); + } + + /** + * 从数据声明生成令牌 + * + * @param claims 数据声明 + * @return 令牌 + */ + private String createToken(Map claims) { + SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret)); + String token = Jwts.builder() + .claims(claims) + .signWith(key) + .compact(); + return token; + } + + /** + * 从令牌中获取数据声明 + * + * @param token 令牌 + * @return 数据声明 + */ + private Claims parseToken(String token) { + SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret)); + return Jwts.parser() + .verifyWith(key) + .build() + .parseSignedClaims(token) + .getPayload(); + } + + /** + * 从令牌中获取用户名 + * + * @param token 令牌 + * @return 用户名 + */ + public String getUsernameFromToken(String token) { + Claims claims = parseToken(token); + return claims.getSubject(); + } + + /** + * 获取请求token + * + * @param request + * @return token + */ + private String getToken(HttpServletRequest request) { + String token = request.getHeader(header); + if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) { + token = token.replace(Constants.TOKEN_PREFIX, ""); + } + return token; + } +} diff --git a/boyue-framework/src/main/java/com/boyue/framework/web/service/UserDetailsServiceImpl.java b/boyue-framework/src/main/java/com/boyue/framework/web/service/UserDetailsServiceImpl.java new file mode 100644 index 0000000..4734047 --- /dev/null +++ b/boyue-framework/src/main/java/com/boyue/framework/web/service/UserDetailsServiceImpl.java @@ -0,0 +1,72 @@ +package com.boyue.framework.web.service; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.enums.UserStatus; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.system.service.ISysUserService; + +/** + * 用户验证处理 + * + * @author boyue + */ +@Service +public class UserDetailsServiceImpl implements UserDetailsService { + private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class); + + @Autowired + private ISysUserService userService; + + @Autowired + private SysPasswordService passwordService; + + @Autowired + private SysPermissionService permissionService; + + @Autowired + private TokenService tokenService; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + SysUser user = userService.selectUserByUserName(username); + if (StringUtils.isNull(user)) { + log.info("登录用户:{} 不存在.", username); + throw new ServiceException("登录用户:" + username + " 不存在"); + } else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) { + log.info("登录用户:{} 已被删除.", username); + throw new ServiceException("对不起,您的账号:" + username + " 已被删除"); + } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", username); + throw new ServiceException("对不起,您的账号:" + username + " 已停用"); + } + + passwordService.validate(user); + + return createLoginUser(user); + } + + public UserDetails createLoginUser(SysUser user) { + return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user)); + } + + public void refreshLoginUser(Long userId) { + SysUser user = userService.selectUserById(userId); + LoginUser loginUser = SecurityUtils.getLoginUser(); + loginUser.setUserId(user.getUserId()); + loginUser.setDeptId(user.getDeptId()); + loginUser.setUser(user); + loginUser.setPermissions(permissionService.getMenuPermission(user)); + tokenService.refreshToken(loginUser); + } +} diff --git a/boyue-framework/src/main/resources/mybatis/mybatis-config.xml b/boyue-framework/src/main/resources/mybatis/mybatis-config.xml new file mode 100644 index 0000000..fa186dd --- /dev/null +++ b/boyue-framework/src/main/resources/mybatis/mybatis-config.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/boyue-middleware/boyue-middleware-rabbitmq/pom.xml b/boyue-middleware/boyue-middleware-rabbitmq/pom.xml new file mode 100644 index 0000000..4174ba9 --- /dev/null +++ b/boyue-middleware/boyue-middleware-rabbitmq/pom.xml @@ -0,0 +1,33 @@ + + + + boyue-middleware + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-middleware-rabbitmq + + + 中间件 + + + + + + + com.boyue + boyue-common + + + + + org.springframework.boot + spring-boot-starter-amqp + + + + + diff --git a/boyue-middleware/boyue-middleware-rabbitmq/src/main/java/com/boyue/middleware/rabbitmq/DirectRabbitConfig.java b/boyue-middleware/boyue-middleware-rabbitmq/src/main/java/com/boyue/middleware/rabbitmq/DirectRabbitConfig.java new file mode 100644 index 0000000..5aa8476 --- /dev/null +++ b/boyue-middleware/boyue-middleware-rabbitmq/src/main/java/com/boyue/middleware/rabbitmq/DirectRabbitConfig.java @@ -0,0 +1,80 @@ +package com.boyue.middleware.rabbitmq; + +import org.springframework.amqp.core.Binding; +import org.springframework.amqp.core.BindingBuilder; +import org.springframework.amqp.core.DirectExchange; +import org.springframework.amqp.core.Queue; +import org.springframework.amqp.rabbit.annotation.RabbitListenerConfigurer; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistrar; +import org.springframework.amqp.support.converter.DefaultClassMapper; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.converter.MappingJackson2MessageConverter; +import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory; + +/** + * @Author : JCccc + * @CreateTime : 2019/9/3 + * @Description : + **/ +@Configuration +public class DirectRabbitConfig implements RabbitListenerConfigurer{ + + // 队列 起名:TestDirectQueue + @Bean + public Queue TestDirectQueue() { + // durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效 + // exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable + // autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。 + // return new Queue("TestDirectQueue",true,true,false); + + // 一般设置一下队列的持久化就好,其余两个就是默认false + return new Queue("TestDirectQueue", true); + } + + // Direct交换机 起名:TestDirectExchange + @Bean + DirectExchange TestDirectExchange() { + // return new DirectExchange("TestDirectExchange",true,true); + return new DirectExchange("TestDirectExchange", true, false); + } + + // 绑定 将队列和交换机绑定, 并设置用于匹配键:TestDirectRouting + @Bean + Binding bindingDirect() { + return BindingBuilder.bind(TestDirectQueue()).to(TestDirectExchange()).with("TestDirectRouting"); + } + + @Bean + public MessageConverter jsonToMapMessageConverter() { + DefaultClassMapper defaultClassMapper = new DefaultClassMapper(); + // 指定反序列化期间要信任的一组包,星号 ( * ) 表示全部信任 + defaultClassMapper.setTrustedPackages("*"); + Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter(); + jackson2JsonMessageConverter.setClassMapper(defaultClassMapper); + return jackson2JsonMessageConverter; + } + + + + //以下配置RabbitMQ消息服务 + @Autowired + public ConnectionFactory connectionFactory; + + @Bean + public DefaultMessageHandlerMethodFactory myHandlerMethodFactory() { + DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory(); + // 设置转换器 + factory.setMessageConverter(new MappingJackson2MessageConverter()); + return factory; + } + + @Override + public void configureRabbitListeners(RabbitListenerEndpointRegistrar rabbitListenerEndpointRegistrar) { + rabbitListenerEndpointRegistrar.setMessageHandlerMethodFactory(myHandlerMethodFactory()); + } +} \ No newline at end of file diff --git a/boyue-middleware/boyue-middleware-rabbitmq/src/main/java/com/boyue/middleware/rabbitmq/DirectReceiver.java b/boyue-middleware/boyue-middleware-rabbitmq/src/main/java/com/boyue/middleware/rabbitmq/DirectReceiver.java new file mode 100644 index 0000000..f50378d --- /dev/null +++ b/boyue-middleware/boyue-middleware-rabbitmq/src/main/java/com/boyue/middleware/rabbitmq/DirectReceiver.java @@ -0,0 +1,19 @@ +package com.boyue.middleware.rabbitmq; + +import org.springframework.amqp.rabbit.annotation.RabbitHandler; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +import com.boyue.common.core.domain.Message; + +@Component +@RabbitListener(queues = "TestDirectQueue") // 监听的队列名称 TestDirectQueue +@ConditionalOnProperty(prefix = "spring.rabbitmq", name = { "enable" }, havingValue = "true", matchIfMissing = false) +public class DirectReceiver { + + @RabbitHandler + public void process(Message map) { + System.out.println("DirectReceiver m消费者收到消息 : " + map.toString()); + } +} \ No newline at end of file diff --git a/boyue-middleware/boyue-middleware-rabbitmq/src/main/java/com/boyue/middleware/rabbitmq/SendMessageController.java b/boyue-middleware/boyue-middleware-rabbitmq/src/main/java/com/boyue/middleware/rabbitmq/SendMessageController.java new file mode 100644 index 0000000..95c6ac8 --- /dev/null +++ b/boyue-middleware/boyue-middleware-rabbitmq/src/main/java/com/boyue/middleware/rabbitmq/SendMessageController.java @@ -0,0 +1,41 @@ +package com.boyue.middleware.rabbitmq; + +import java.util.Map; + +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Anonymous; +import com.boyue.common.core.domain.Message; + +/** + * @Author : JCccc + * @CreateTime : 2019/9/3 + * @Description : + **/ +@RestController +@RequestMapping("/rabbitmq") +public class SendMessageController { + + @Autowired + RabbitTemplate rabbitTemplate; // 使用RabbitTemplate,这提供了接收/发送等等方法 + + @GetMapping("/sendDirectMessage") + @Anonymous + public String sendDirectMessage() { + // 将消息携带绑定键值:TestDirectRouting 发送到交换机TestDirectExchange + rabbitTemplate.convertAndSend( + "TestDirectExchange", + "TestDirectRouting", + Message.create() + .setPayload(Map.of("message", "你好")) + .setReceiver("接收者") + .setSender("发送者") + ); + return "ok"; + } + +} \ No newline at end of file diff --git a/boyue-middleware/boyue-middleware-redis/pom.xml b/boyue-middleware/boyue-middleware-redis/pom.xml new file mode 100644 index 0000000..eb2b63c --- /dev/null +++ b/boyue-middleware/boyue-middleware-redis/pom.xml @@ -0,0 +1,33 @@ + + + + boyue-middleware + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-middleware-redis + + + 中间件 + + + + + + + com.boyue + boyue-framework + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + diff --git a/boyue-middleware/boyue-middleware-redis/src/main/java/com/boyue/middleware/redis/aspectj/RateLimiterAspect.java b/boyue-middleware/boyue-middleware-redis/src/main/java/com/boyue/middleware/redis/aspectj/RateLimiterAspect.java new file mode 100644 index 0000000..b540a4c --- /dev/null +++ b/boyue-middleware/boyue-middleware-redis/src/main/java/com/boyue/middleware/redis/aspectj/RateLimiterAspect.java @@ -0,0 +1,92 @@ +package com.boyue.middleware.redis.aspectj; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.List; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.RedisScript; +import org.springframework.stereotype.Component; + +import com.boyue.common.annotation.RateLimiter; +import com.boyue.common.enums.LimitType; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.ip.IpUtils; + +/** + * 限流处理 + * + * @author boyue + */ +@Aspect +@Component +@ConditionalOnProperty(prefix = "spring.cache", name = { "type" }, havingValue = "redis", matchIfMissing = false) +public class RateLimiterAspect +{ + private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class); + + private RedisTemplate redisTemplate; + + private RedisScript limitScript; + + @Autowired + public void setRedisTemplate1(RedisTemplate redisTemplate) + { + this.redisTemplate = redisTemplate; + } + + @Autowired + public void setLimitScript(RedisScript limitScript) + { + this.limitScript = limitScript; + } + + @Before("@annotation(rateLimiter)") + public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable + { + int time = rateLimiter.time(); + int count = rateLimiter.count(); + String combineKey = getCombineKey(rateLimiter, point); + List keys = Collections.singletonList(combineKey); + try + { + Long number = redisTemplate.execute(limitScript, keys, count, time); + if (StringUtils.isNull(number) || number.intValue() > count) + { + throw new ServiceException("访问过于频繁,请稍候再试"); + } + log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey); + } + catch (ServiceException e) + { + throw e; + } + catch (Exception e) + { + throw new RuntimeException("服务器限流异常,请稍候再试"); + } + } + + public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) + { + StringBuffer stringBuffer = new StringBuffer(rateLimiter.key()); + if (rateLimiter.limitType() == LimitType.IP) + { + stringBuffer.append(IpUtils.getIpAddr()).append("-"); + } + MethodSignature signature = (MethodSignature) point.getSignature(); + Method method = signature.getMethod(); + Class targetClass = method.getDeclaringClass(); + stringBuffer.append(targetClass.getName()).append("-").append(method.getName()); + return stringBuffer.toString(); + } +} diff --git a/boyue-middleware/boyue-middleware-redis/src/main/java/com/boyue/middleware/redis/config/FastJson2JsonRedisSerializer.java b/boyue-middleware/boyue-middleware-redis/src/main/java/com/boyue/middleware/redis/config/FastJson2JsonRedisSerializer.java new file mode 100644 index 0000000..eb7871f --- /dev/null +++ b/boyue-middleware/boyue-middleware-redis/src/main/java/com/boyue/middleware/redis/config/FastJson2JsonRedisSerializer.java @@ -0,0 +1,54 @@ +package com.boyue.middleware.redis.config; + +import java.nio.charset.Charset; + +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.SerializationException; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONReader; +import com.alibaba.fastjson2.JSONWriter; +// import com.alibaba.fastjson2.filter.Filter; +import com.alibaba.fastjson2.filter.Filter; +import com.boyue.common.constant.Constants; + +/** + * Redis使用FastJson序列化 + * + * @author boyue + */ +public class FastJson2JsonRedisSerializer implements RedisSerializer +{ + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + + static final Filter AUTO_TYPE_FILTER = JSONReader.autoTypeFilter(Constants.JSON_WHITELIST_STR); + + private Class clazz; + + public FastJson2JsonRedisSerializer(Class clazz) + { + super(); + this.clazz = clazz; + } + + @Override + public byte[] serialize(T t) throws SerializationException + { + if (t == null) + { + return new byte[0]; + } + return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET); + } + + @Override + public T deserialize(byte[] bytes) throws SerializationException + { + if (bytes == null || bytes.length <= 0) + { + return null; + } + String str = new String(bytes, DEFAULT_CHARSET); + return JSON.parseObject(str, clazz, AUTO_TYPE_FILTER); + } +} diff --git a/boyue-middleware/boyue-middleware-redis/src/main/java/com/boyue/middleware/redis/config/RedisConfig.java b/boyue-middleware/boyue-middleware-redis/src/main/java/com/boyue/middleware/redis/config/RedisConfig.java new file mode 100644 index 0000000..204b965 --- /dev/null +++ b/boyue-middleware/boyue-middleware-redis/src/main/java/com/boyue/middleware/redis/config/RedisConfig.java @@ -0,0 +1,97 @@ +package com.boyue.middleware.redis.config; + +import java.time.Duration; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.CachingConfigurer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * redis配置 + * + * @author boyue + */ +@Configuration +@ConditionalOnProperty(prefix = "spring.cache", name = { "type" }, havingValue = "redis", matchIfMissing = false) +public class RedisConfig implements CachingConfigurer { + + @Bean + @Primary + public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { + RedisCacheConfiguration config = instanceConfig(3600 * 24 * 15L); + return RedisCacheManager.builder(connectionFactory).cacheDefaults(config).transactionAware().build(); + } + + @Bean + public CacheManager cacheManager30m(RedisConnectionFactory connectionFactory) { + RedisCacheConfiguration config = instanceConfig(1800L); + return RedisCacheManager.builder(connectionFactory).cacheDefaults(config).transactionAware().build(); + } + + @SuppressWarnings(value = { "unchecked", "rawtypes" }) + private RedisCacheConfiguration instanceConfig(Long ttl) { + FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class); + return RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(ttl)).disableCachingNullValues() + .computePrefixWith(name -> name + ":") + .serializeKeysWith( + RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) + .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer)); + } + + @Bean + @SuppressWarnings(value = { "unchecked", "rawtypes" }) + public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { + + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(connectionFactory); + + FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class); + + // 使用StringRedisSerializer来序列化和反序列化redis的key值 + template.setKeySerializer(new StringRedisSerializer()); + template.setValueSerializer(serializer); + + // Hash的key也采用StringRedisSerializer的序列化方式 + template.setHashKeySerializer(new StringRedisSerializer()); + template.setHashValueSerializer(serializer); + + template.afterPropertiesSet(); + return template; + } + + @Bean + public DefaultRedisScript limitScript() { + DefaultRedisScript redisScript = new DefaultRedisScript<>(); + redisScript.setScriptText(limitScriptText()); + redisScript.setResultType(Long.class); + return redisScript; + } + + /** + * 限流脚本 + */ + private String limitScriptText() { + return "local key = KEYS[1]\n" + + "local count = tonumber(ARGV[1])\n" + + "local time = tonumber(ARGV[2])\n" + + "local current = redis.call('get', key);\n" + + "if current and tonumber(current) > count then\n" + + " return tonumber(current);\n" + + "end\n" + + "current = redis.call('incr', key)\n" + + "if tonumber(current) == 1 then\n" + + " redis.call('expire', key, time)\n" + + "end\n" + + "return tonumber(current);"; + } +} diff --git a/boyue-middleware/boyue-middleware-redis/src/main/java/com/boyue/middleware/redis/controller/RedisCacheController.java b/boyue-middleware/boyue-middleware-redis/src/main/java/com/boyue/middleware/redis/controller/RedisCacheController.java new file mode 100644 index 0000000..e0bdad7 --- /dev/null +++ b/boyue-middleware/boyue-middleware-redis/src/main/java/com/boyue/middleware/redis/controller/RedisCacheController.java @@ -0,0 +1,64 @@ +package com.boyue.middleware.redis.controller; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.utils.StringUtils; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +/** + * 缓存监控 + * + * @author boyue + */ +@Tag(name = "缓存监控") +@RestController +@SuppressWarnings(value = { "unchecked", "rawtypes" }) +@ConditionalOnProperty(prefix = "spring.cache", name = { "type" }, havingValue = "redis", matchIfMissing = false) +@RequestMapping("/monitor/cache") +public class RedisCacheController { + @Autowired + private RedisTemplate redisTemplate; + + @Operation(summary = "获取缓存信息") + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @GetMapping() + public AjaxResult getInfo() throws Exception { + Map result = new HashMap<>(3); + + Properties info = (Properties) redisTemplate + .execute((RedisCallback) connection -> connection.commands().info()); + Properties commandStats = (Properties) redisTemplate + .execute((RedisCallback) connection -> connection.commands().info("commandstats")); + Object dbSize = redisTemplate.execute((RedisCallback) connection -> connection.commands().dbSize()); + result.put("info", info); + result.put("dbSize", dbSize); + + List> pieList = new ArrayList<>(); + commandStats.stringPropertyNames().forEach(key -> { + Map data = new HashMap<>(2); + String property = commandStats.getProperty(key); + data.put("name", StringUtils.removeStart(key, "cmdstat_")); + data.put("value", StringUtils.substringBetween(property, "calls=", ",usec")); + pieList.add(data); + }); + result.put("commandStats", pieList); + return AjaxResult.success(result); + } + +} diff --git a/boyue-middleware/boyue-middleware-redis/src/main/java/com/boyue/middleware/redis/utils/RedisCache.java b/boyue-middleware/boyue-middleware-redis/src/main/java/com/boyue/middleware/redis/utils/RedisCache.java new file mode 100644 index 0000000..24e556f --- /dev/null +++ b/boyue-middleware/boyue-middleware-redis/src/main/java/com/boyue/middleware/redis/utils/RedisCache.java @@ -0,0 +1,288 @@ +package com.boyue.middleware.redis.utils; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cache.Cache; +import org.springframework.data.redis.core.BoundSetOperations; +import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Component; + +import com.boyue.common.service.cache.CacheKeys; +import com.boyue.common.service.cache.CacheTimeOut; +import com.boyue.common.utils.StringUtils; + +/** + * spring redis 工具类 + * + * @author boyue + **/ +@SuppressWarnings(value = { "unchecked", "rawtypes" }) +@Component +@ConditionalOnProperty(prefix = "spring.cache", name = { "type" }, havingValue = "redis", matchIfMissing = false) +public class RedisCache implements CacheKeys, CacheTimeOut { + @Autowired + public RedisTemplate redisTemplate; + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + */ + public void setCacheObject(final String cacheName, final String key, final T value) { + redisTemplate.opsForValue().set(cacheName + ":" + key, value); + } + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + */ + public void setCacheObject(final String key, final T value) { + redisTemplate.opsForValue().set(key, value); + } + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @param timeout 时间 + * @param timeUnit 时间颗粒度 + */ + public void setCacheObject(final String cacheName, final String key, final T value, final long timeout, + final TimeUnit timeUnit) { + redisTemplate.opsForValue().set(cacheName + ":" + key, value, timeout, timeUnit); + } + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @param timeout 时间 + * @param timeUnit 时间颗粒度 + */ + public void setCacheObject(final String key, final T value, final long timeout, final TimeUnit timeUnit) { + redisTemplate.opsForValue().set(key, value, timeout, timeUnit); + } + + /** + * 设置有效时间 + * + * @param key Redis键 + * @param timeout 超时时间 + * @return true=设置成功;false=设置失败 + */ + public boolean expire(final String key, final long timeout) { + return expire(key, timeout, TimeUnit.SECONDS); + } + + /** + * 设置有效时间 + * + * @param key Redis键 + * @param timeout 超时时间 + * @param unit 时间单位 + * @return true=设置成功;false=设置失败 + */ + public boolean expire(final String key, final long timeout, final TimeUnit unit) { + return redisTemplate.expire(key, timeout, unit); + } + + /** + * 获取有效时间 + * + * @param key Redis键 + * @return 有效时间 + */ + public long getExpire(final String key) { + return redisTemplate.getExpire(key); + } + + /** + * 判断 key是否存在 + * + * @param key 键 + * @return true 存在 false不存在 + */ + public Boolean hasKey(String key) { + return redisTemplate.hasKey(key); + } + + /** + * 获得缓存的基本对象。 + * + * @param key 缓存键值 + * @return 缓存键值对应的数据 + */ + public T getCacheObject(final String key) { + ValueOperations operation = redisTemplate.opsForValue(); + return operation.get(key); + } + + /** + * 删除单个对象 + * + * @param key + */ + public boolean deleteObject(final String key) { + return redisTemplate.delete(key); + } + + /** + * 删除集合对象 + * + * @param collection 多个对象 + * @return + */ + public boolean deleteObject(final Collection collection) { + return redisTemplate.delete(collection) > 0; + } + + /** + * 缓存List数据 + * + * @param key 缓存的键值 + * @param dataList 待缓存的List数据 + * @return 缓存的对象 + */ + public long setCacheList(final String key, final List dataList) { + Long count = redisTemplate.opsForList().rightPushAll(key, dataList); + return count == null ? 0 : count; + } + + /** + * 获得缓存的list对象 + * + * @param key 缓存的键值 + * @return 缓存键值对应的数据 + */ + public List getCacheList(final String key) { + return redisTemplate.opsForList().range(key, 0, -1); + } + + /** + * 缓存Set + * + * @param key 缓存键值 + * @param dataSet 缓存的数据 + * @return 缓存数据的对象 + */ + public BoundSetOperations setCacheSet(final String key, final Set dataSet) { + BoundSetOperations setOperation = redisTemplate.boundSetOps(key); + Iterator it = dataSet.iterator(); + while (it.hasNext()) { + setOperation.add(it.next()); + } + return setOperation; + } + + /** + * 获得缓存的set + * + * @param key + * @return + */ + public Set getCacheSet(final String key) { + return redisTemplate.opsForSet().members(key); + } + + /** + * 缓存Map + * + * @param key + * @param dataMap + */ + public void setCacheMap(final String key, final Map dataMap) { + if (dataMap != null) { + redisTemplate.opsForHash().putAll(key, dataMap); + } + } + + /** + * 获得缓存的Map + * + * @param key + * @return + */ + public Map getCacheMap(final String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * 往Hash中存入数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @param value 值 + */ + public void setCacheMapValue(final String key, final String hKey, final T value) { + redisTemplate.opsForHash().put(key, hKey, value); + } + + /** + * 获取Hash中的数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @return Hash中的对象 + */ + public T getCacheMapValue(final String key, final String hKey) { + HashOperations opsForHash = redisTemplate.opsForHash(); + return opsForHash.get(key, hKey); + } + + /** + * 获取多个Hash中的数据 + * + * @param key Redis键 + * @param hKeys Hash键集合 + * @return Hash对象集合 + */ + public List getMultiCacheMapValue(final String key, final Collection hKeys) { + return redisTemplate.opsForHash().multiGet(key, hKeys); + } + + /** + * 删除Hash中的某条数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @return 是否成功 + */ + public boolean deleteCacheMapValue(final String key, final String hKey) { + return redisTemplate.opsForHash().delete(key, hKey) > 0; + } + + /** + * 获得缓存的基本对象列表 + * + * @param pattern 字符串前缀 + * @return 对象列表 + */ + public Collection keys(final String pattern) { + return redisTemplate.keys(pattern); + } + + @Override + public Set getCachekeys(Cache cache) { + Set keyset = new HashSet<>(); + Set keysets = redisTemplate.keys(cache.getName() + "*"); + for (Object s : keysets) { + keyset.add(StringUtils.replace(s.toString(), cache.getName() + ":", "")); + } + return keyset; + } +} diff --git a/boyue-middleware/boyue-middleware-starter/pom.xml b/boyue-middleware/boyue-middleware-starter/pom.xml new file mode 100644 index 0000000..bf001d1 --- /dev/null +++ b/boyue-middleware/boyue-middleware-starter/pom.xml @@ -0,0 +1,38 @@ + + + + boyue-middleware + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-middleware-starter + + + 中间件 + + + + + + + com.boyue + boyue-common + + + + + com.boyue + boyue-middleware-redis + + + + com.boyue + boyue-middleware-rabbitmq + + + + + diff --git a/boyue-middleware/pom.xml b/boyue-middleware/pom.xml new file mode 100644 index 0000000..2c1614e --- /dev/null +++ b/boyue-middleware/pom.xml @@ -0,0 +1,44 @@ + + + + boyuehasfj-java + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-middleware + + + + + + 中间件 + + + + + + com.boyue + boyue-middleware-redis + ${boyue.version} + + + + com.boyue + boyue-middleware-rabbitmq + ${boyue.version} + + + + + + + + boyue-middleware-redis + boyue-middleware-rabbitmq + boyue-middleware-starter + + pom + diff --git a/boyue-models/boyue-flowable/pom.xml b/boyue-models/boyue-flowable/pom.xml new file mode 100644 index 0000000..9e859c5 --- /dev/null +++ b/boyue-models/boyue-flowable/pom.xml @@ -0,0 +1,64 @@ + + + + boyue-models + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-flowable + + + form表单 + + + + + + + com.boyue + boyue-system + + + + + org.flowable + flowable-spring-boot-starter + 7.1.0 + + + org.flowable + flowable-spring-security + + + + + + com.googlecode.aviator + aviator + 5.3.3 + + + + org.graalvm.js + js + 24.2.1 + pom + + + org.graalvm.js + js-scriptengine + 24.2.1 + runtime + + + + com.boyue + boyue-form + + + + + \ No newline at end of file diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/common/constant/ProcessConstants.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/common/constant/ProcessConstants.java new file mode 100644 index 0000000..5196aee --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/common/constant/ProcessConstants.java @@ -0,0 +1,80 @@ +package com.boyue.flowable.common.constant; + +/** + * 流程常量信息 + * + * @author Tony + * @date 2021/4/17 22:46 + */ +public class ProcessConstants { + + /** + * 动态数据 + */ + public static final String DYNAMIC = "dynamic"; + + /** + * 固定任务接收 + */ + public static final String FIXED = "fixed"; + + /** + * 单个审批人 + */ + public static final String ASSIGNEE = "assignee"; + + + /** + * 候选人 + */ + public static final String CANDIDATE_USERS = "candidateUsers"; + + + /** + * 审批组 + */ + public static final String CANDIDATE_GROUPS = "candidateGroups"; + + /** + * 单个审批人 + */ + public static final String PROCESS_APPROVAL = "approval"; + + /** + * 会签人员 + */ + public static final String PROCESS_MULTI_INSTANCE_USER = "userList"; + + /** + * nameapace + */ + public static final String NAMASPASE = "http://flowable.org/bpmn"; + + /** + * 会签节点 + */ + public static final String PROCESS_MULTI_INSTANCE = "multiInstance"; + + /** + * 自定义属性 dataType + */ + public static final String PROCESS_CUSTOM_DATA_TYPE = "dataType"; + + /** + * 自定义属性 userType + */ + public static final String PROCESS_CUSTOM_USER_TYPE = "userType"; + + /** + * 初始化人员 + */ + public static final String PROCESS_INITIATOR = "INITIATOR"; + + + /** + * 流程跳过 + */ + public static final String FLOWABLE_SKIP_EXPRESSION_ENABLED = "_FLOWABLE_SKIP_EXPRESSION_ENABLED"; + + +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/common/enums/FlowComment.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/common/enums/FlowComment.java new file mode 100644 index 0000000..f615e2d --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/common/enums/FlowComment.java @@ -0,0 +1,43 @@ +package com.boyue.flowable.common.enums; + +/** + * 流程意见类型 + * + * @author Tony + * @date 2021/4/19 + */ +public enum FlowComment { + + /** + * 说明 + */ + NORMAL("1", "正常意见"), + REBACK("2", "退回意见"), + REJECT("3", "驳回意见"), + DELEGATE("4", "委派意见"), + ASSIGN("5", "转办意见"), + STOP("6", "终止流程"); + + /** + * 类型 + */ + private final String type; + + /** + * 说明 + */ + private final String remark; + + FlowComment(String type, String remark) { + this.type = type; + this.remark = remark; + } + + public String getType() { + return type; + } + + public String getRemark() { + return remark; + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/common/expand/el/BaseEl.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/common/expand/el/BaseEl.java new file mode 100644 index 0000000..1199923 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/common/expand/el/BaseEl.java @@ -0,0 +1,12 @@ +package com.boyue.flowable.common.expand.el; + +/** + * 扩展表达式 + * + * @author Tony + * @date 2023-03-04 09:10 + */ +public interface BaseEl { + +} + diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/common/expand/el/FlowEl.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/common/expand/el/FlowEl.java new file mode 100644 index 0000000..1a5e480 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/common/expand/el/FlowEl.java @@ -0,0 +1,34 @@ +package com.boyue.flowable.common.expand.el; + +import org.springframework.stereotype.Component; + +import com.boyue.system.service.ISysDeptService; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; + + +/** + * 扩展表达式 + * + * @author Tony + * @date 2023-03-04 12:10 + */ +@Component +@Slf4j +public class FlowEl implements BaseEl { + + @Resource + private ISysDeptService sysDeptService; + + public String findDeptLeader(String name){ + log.info("开始查询表达式变量值,getName"); + return name; + } + + public String getName(String name){ + log.info("开始查询表达式变量值,getName"); + return name; + } +} + diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/config/FlowableConfig.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/config/FlowableConfig.java new file mode 100644 index 0000000..d8c2681 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/config/FlowableConfig.java @@ -0,0 +1,42 @@ +package com.boyue.flowable.config; + +import java.util.concurrent.ThreadPoolExecutor; + +import org.flowable.engine.impl.db.DbIdGenerator; +import org.flowable.spring.SpringProcessEngineConfiguration; +import org.flowable.spring.boot.EngineConfigurationConfigurer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +@Configuration +public class FlowableConfig implements EngineConfigurationConfigurer { + @Override + public void configure(SpringProcessEngineConfiguration engineConfiguration) { + engineConfiguration.setActivityFontName("宋体"); + engineConfiguration.setLabelFontName("宋体"); + engineConfiguration.setAnnotationFontName("宋体"); + engineConfiguration.setIdGenerator(new DbIdGenerator()); + } + + @Bean("applicationTaskExecutor") + public ThreadPoolTaskExecutor applicationTaskExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + // 此方法返回可用处理器的虚拟机的最大数量; 不小于1 + int core = Runtime.getRuntime().availableProcessors(); + executor.setCorePoolSize(core);// 设置核心线程数 + executor.setMaxPoolSize(core * 2 + 1);// 设置最大线程数 + executor.setKeepAliveSeconds(120);// 除核心线程外的线程存活时间 + executor.setQueueCapacity(120);// 如果传入值大于0,底层队列使用的是LinkedBlockingQueue,否则默认使用SynchronousQueue + executor.setThreadNamePrefix("thread-default-execute");// 线程名称前缀 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());// 设置拒绝策略,抛出 + // RejectedExecutionException来拒绝新任务的处理。 + // executor.setRejectedExecutionHandler(new + // ThreadPoolExecutor.CallerRunsPolicy());//设置拒绝策略,使用主线程 + // executor.setRejectedExecutionHandler(new + // ThreadPoolExecutor.DiscardPolicy());//设置拒绝策略,直接丢弃掉 + // executor.setRejectedExecutionHandler(new + // ThreadPoolExecutor.DiscardOldestPolicy());//设置拒绝策略,丢弃最早的未处理的任务请求。 + return executor; + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/controller/FlowDefinitionController.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/controller/FlowDefinitionController.java new file mode 100644 index 0000000..4d5e220 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/controller/FlowDefinitionController.java @@ -0,0 +1,228 @@ +package com.boyue.flowable.controller; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; + +import javax.imageio.ImageIO; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.flowable.domain.SysDeployForm; +import com.boyue.flowable.domain.SysExpression; +import com.boyue.flowable.domain.dto.FlowSaveXmlVo; +import com.boyue.flowable.service.IFlowDefinitionService; +import com.boyue.flowable.service.ISysDeployFormService; +import com.boyue.flowable.service.ISysExpressionService; +import com.boyue.system.service.ISysRoleService; +import com.boyue.system.service.ISysUserService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; + +/** + *

+ * 工作流程定义 + *

+ * + * @author Tony + * @date 2021-04-03 + */ +@Slf4j +@Tag(name = "流程定义") +@RestController +@RequestMapping("/flowable/definition") +public class FlowDefinitionController extends BaseController { + + @Autowired + private IFlowDefinitionService flowDefinitionService; + + @Autowired + private ISysUserService userService; + + @Resource + private ISysRoleService sysRoleService; + @Resource + private ISysExpressionService sysExpressionService; + + @Resource + private ISysDeployFormService sysDeployFormService; + + @GetMapping(value = "/list") + @Operation(summary = "流程定义列表") + public TableDataInfo list( + @RequestParam Integer pageNum, + @RequestParam Integer pageSize, + @RequestParam(required = false) String name) { + return getDataTable(flowDefinitionService.list(name, pageNum, pageSize)); + } + + @Operation(summary = "导入流程文件") + @PostMapping("/import") + public AjaxResult importFile( + @RequestParam(required = false) String name, + @RequestParam(required = false) String category, + MultipartFile file) { + InputStream in = null; + try { + in = file.getInputStream(); + flowDefinitionService.importFile(name, category, in); + } catch (Exception e) { + log.error("导入失败:", e); + return AjaxResult.success(e.getMessage()); + } finally { + try { + if (in != null) { + in.close(); + } + } catch (IOException e) { + log.error("关闭输入流出错", e); + } + } + + return AjaxResult.success("导入成功"); + } + + @Operation(summary = "读取xml文件") + @GetMapping("/readXml/{deployId}") + public AjaxResult readXml(@PathVariable String deployId) { + try { + return flowDefinitionService.readXml(deployId); + } catch (Exception e) { + return AjaxResult.error("加载xml文件异常"); + } + + } + + @Operation(summary = "读取图片文件") + @GetMapping("/readImage/{deployId}") + public void readImage(@PathVariable String deployId, HttpServletResponse response) { + OutputStream os = null; + BufferedImage image = null; + try { + image = ImageIO.read(flowDefinitionService.readImage(deployId)); + response.setContentType("image/png"); + os = response.getOutputStream(); + if (image != null) { + ImageIO.write(image, "png", os); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (os != null) { + os.flush(); + os.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + + @Operation(summary = "保存流程设计器内的xml文件") + @Log(title = "流程定义", businessType = BusinessType.INSERT) + @PostMapping("/save") + public AjaxResult save(@RequestBody FlowSaveXmlVo vo) { + InputStream in = null; + try { + in = new ByteArrayInputStream(vo.getXml().getBytes(StandardCharsets.UTF_8)); + flowDefinitionService.importFile(vo.getName(), vo.getCategory(), in); + } catch (Exception e) { + log.error("导入失败:", e); + return AjaxResult.error(e.getMessage()); + } finally { + try { + if (in != null) { + in.close(); + } + } catch (IOException e) { + log.error("关闭输入流出错", e); + } + } + + return AjaxResult.success("导入成功"); + } + + @Operation(summary = "发起流程") + @Log(title = "发起流程", businessType = BusinessType.INSERT) + @PostMapping("/start/{procDefId}") + public AjaxResult start(@PathVariable String procDefId, @RequestBody Map variables) { + return flowDefinitionService.startProcessInstanceById(procDefId, variables); + } + + @Operation(summary = "激活或挂起流程定义") + @Log(title = "激活/挂起流程", businessType = BusinessType.UPDATE) + @PutMapping(value = "/updateState") + public AjaxResult updateState(@RequestParam Integer state, @RequestParam String deployId) { + flowDefinitionService.updateState(state, deployId); + return AjaxResult.success(); + } + + @Operation(summary = "删除流程") + @Log(title = "删除流程", businessType = BusinessType.DELETE) + @DeleteMapping(value = "/{deployIds}") + public AjaxResult delete(@PathVariable String[] deployIds) { + for (String deployId : deployIds) { + flowDefinitionService.delete(deployId); + } + return AjaxResult.success(); + } + + @Operation(summary = "指定流程办理人员列表") + @GetMapping("/userList") + public AjaxResult userList(SysUser user) { + List list = userService.selectUserList(user); + return AjaxResult.success(list); + } + + @Operation(summary = "指定流程办理组列表") + @GetMapping("/roleList") + public AjaxResult roleList(SysRole role) { + List list = sysRoleService.selectRoleList(role); + return AjaxResult.success(list); + } + + @Operation(summary = "指定流程达式列表") + @GetMapping("/expList") + public AjaxResult expList(SysExpression sysExpression) { + List list = sysExpressionService.selectSysExpressionList(sysExpression); + return AjaxResult.success(list); + } + + /** + * 挂载流程表单 + */ + @Log(title = "流程表单", businessType = BusinessType.INSERT) + @PostMapping("/addDeployForm") + public AjaxResult addDeployForm(@RequestBody SysDeployForm sysDeployForm) { + return toAjax(sysDeployFormService.insertSysDeployForm(sysDeployForm)); + } + +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/controller/FlowInstanceController.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/controller/FlowInstanceController.java new file mode 100644 index 0000000..c1e81bc --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/controller/FlowInstanceController.java @@ -0,0 +1,72 @@ +package com.boyue.flowable.controller; + +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.enums.BusinessType; +import com.boyue.flowable.domain.vo.FlowTaskVo; +import com.boyue.flowable.service.IFlowInstanceService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; + +/** + *

+ * 工作流流程实例管理 + *

+ * + * @author Tony + * @date 2021-04-03 + */ +@Slf4j +@Tag(name = "工作流流程实例管理") +@RestController +@RequestMapping("/flowable/instance") +public class FlowInstanceController extends BaseController { + + @Autowired + private IFlowInstanceService flowInstanceService; + + @Operation(summary = "根据流程定义id启动流程实例") + @PostMapping("/startBy/{procDefId}") + public AjaxResult startById(@PathVariable String procDefId, @RequestBody Map variables) { + return flowInstanceService.startProcessInstanceById(procDefId, variables); + + } + + @Operation(summary = "激活或挂起流程实例") + @PostMapping(value = "/updateState") + public AjaxResult updateState(@RequestParam Integer state, @RequestParam String instanceId) { + flowInstanceService.updateState(state, instanceId); + return AjaxResult.success(); + } + + @Operation(summary = "结束流程实例") + @PostMapping(value = "/stopProcessInstance") + public AjaxResult stopProcessInstance(@RequestBody FlowTaskVo flowTaskVo) { + flowInstanceService.stopProcessInstance(flowTaskVo); + return AjaxResult.success(); + } + + @Operation(summary = "删除流程实例") + @Log(title = "删除任务", businessType = BusinessType.DELETE) + @DeleteMapping(value = "/delete/{instanceIds}") + public AjaxResult delete(@PathVariable String[] instanceIds, @RequestParam(required = false) String deleteReason) { + for (String instanceId : instanceIds) { + flowInstanceService.delete(instanceId, deleteReason); + } + return AjaxResult.success(); + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/controller/FlowTaskController.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/controller/FlowTaskController.java new file mode 100644 index 0000000..1fa94d4 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/controller/FlowTaskController.java @@ -0,0 +1,289 @@ +package com.boyue.flowable.controller; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; + +import javax.imageio.ImageIO; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.flowable.domain.dto.FlowTaskDto; +import com.boyue.flowable.domain.vo.FlowQueryVo; +import com.boyue.flowable.domain.vo.FlowTaskVo; +import com.boyue.flowable.service.IFlowTaskService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; + +/** + *

+ * 工作流任务管理 + *

+ * + * @author Tony + * @date 2021-04-03 + */ +@Slf4j +@Tag(name = "工作流流程任务管理") +@RestController +@RequestMapping("/flowable/task") +public class FlowTaskController extends BaseController { + + @Autowired + private IFlowTaskService flowTaskService; + + @Operation(summary = "我发起的流程") + @GetMapping(value = "/myProcess") + public TableDataInfo myProcess(FlowQueryVo queryVo) { + List myProcess = flowTaskService.myProcess(queryVo); + return getDataTable(myProcess); + } + + @Operation(summary = "取消申请") + @Log(title = "取消申请", businessType = BusinessType.UPDATE) + @PostMapping(value = "/stopProcess") + public AjaxResult stopProcess(@RequestBody FlowTaskVo flowTaskVo) { + return flowTaskService.stopProcess(flowTaskVo); + } + + @Operation(summary = "撤回流程") + @Log(title = "撤回流程", businessType = BusinessType.UPDATE) + @PostMapping(value = "/revokeProcess") + public AjaxResult revokeProcess(@RequestBody FlowTaskVo flowTaskVo) { + return flowTaskService.revokeProcess(flowTaskVo); + } + + @Operation(summary = "获取待办列表") + @GetMapping(value = "/todoList") + public TableDataInfo todoList(FlowQueryVo queryVo) { + return getDataTable(flowTaskService.todoList(queryVo)); + } + + @Operation(summary = "获取已办任务") + @GetMapping(value = "/finishedList") + public TableDataInfo finishedList(FlowQueryVo queryVo) { + return getDataTable(flowTaskService.finishedList(queryVo)); + } + + @Operation(summary = "流程历史流转记录") + @GetMapping(value = "/flowRecord") + public AjaxResult flowRecord(String procInsId, String deployId) { + return flowTaskService.flowRecord(procInsId, deployId); + } + + @Operation(summary = "根据任务ID查询挂载的表单信息") + @GetMapping(value = "/getTaskForm") + public AjaxResult getTaskForm(String taskId) { + return flowTaskService.getTaskForm(taskId); + } + + @Operation(summary = "流程初始化表单") + @GetMapping(value = "/flowFormData") + public AjaxResult flowFormData(String deployId) { + return flowTaskService.flowFormData(deployId); + } + + @Operation(summary = "获取流程变量") + @GetMapping(value = "/processVariables/{taskId}") + public AjaxResult processVariables(@PathVariable String taskId) { + return flowTaskService.processVariables(taskId); + } + + @Operation(summary = "审批任务") + @Log(title = "审批任务", businessType = BusinessType.UPDATE) + @PostMapping(value = "/complete") + public AjaxResult complete(@RequestBody FlowTaskVo flowTaskVo) { + return flowTaskService.complete(flowTaskVo); + } + + @Operation(summary = "驳回任务") + @Log(title = "驳回任务", businessType = BusinessType.UPDATE) + @PostMapping(value = "/reject") + public AjaxResult taskReject(@RequestBody FlowTaskVo flowTaskVo) { + flowTaskService.taskReject(flowTaskVo); + return AjaxResult.success(); + } + + @Operation(summary = "退回任务") + @Log(title = "退回任务", businessType = BusinessType.UPDATE) + @PostMapping(value = "/return") + public AjaxResult taskReturn(@RequestBody FlowTaskVo flowTaskVo) { + flowTaskService.taskReturn(flowTaskVo); + return AjaxResult.success(); + } + + @Operation(summary = "获取所有可回退的节点") + @PostMapping(value = "/returnList") + public AjaxResult findReturnTaskList(@RequestBody FlowTaskVo flowTaskVo) { + return flowTaskService.findReturnTaskList(flowTaskVo); + } + + @Operation(summary = "删除任务") + @Log(title = "删除任务", businessType = BusinessType.DELETE) + @DeleteMapping(value = "/delete") + public AjaxResult delete(@RequestBody FlowTaskVo flowTaskVo) { + flowTaskService.deleteTask(flowTaskVo); + return AjaxResult.success(); + } + + @Operation(summary = "认领/签收任务") + @PostMapping(value = "/claim") + public AjaxResult claim(@RequestBody FlowTaskVo flowTaskVo) { + flowTaskService.claim(flowTaskVo); + return AjaxResult.success(); + } + + @Operation(summary = "取消认领/签收任务") + @PostMapping(value = "/unClaim") + public AjaxResult unClaim(@RequestBody FlowTaskVo flowTaskVo) { + flowTaskService.unClaim(flowTaskVo); + return AjaxResult.success(); + } + + @Operation(summary = "委派任务") + @PostMapping(value = "/delegateTask") + public AjaxResult delegate(@RequestBody FlowTaskVo flowTaskVo) { + flowTaskService.delegateTask(flowTaskVo); + return AjaxResult.success(); + } + + @Operation(summary = "任务归还") + @PostMapping(value = "/resolveTask") + public AjaxResult resolveTask(@RequestBody FlowTaskVo flowTaskVo) { + flowTaskService.resolveTask(flowTaskVo); + return AjaxResult.success(); + } + + @Operation(summary = "转办任务") + @PostMapping(value = "/assignTask") + public AjaxResult assign(@RequestBody FlowTaskVo flowTaskVo) { + flowTaskService.assignTask(flowTaskVo); + return AjaxResult.success(); + } + + @PostMapping(value = "/addMultiInstanceExecution") + @Operation(summary = "多实例加签") + public AjaxResult addMultiInstanceExecution(@RequestBody FlowTaskVo flowTaskVo) { + flowTaskService.addMultiInstanceExecution(flowTaskVo); + return AjaxResult.success("加签成功"); + } + + @PostMapping(value = "/deleteMultiInstanceExecution") + @Operation(summary = "多实例减签") + public AjaxResult deleteMultiInstanceExecution(@RequestBody FlowTaskVo flowTaskVo) { + flowTaskService.deleteMultiInstanceExecution(flowTaskVo); + return AjaxResult.success("减签成功"); + } + + @Operation(summary = "获取下一节点") + @PostMapping(value = "/nextFlowNode") + public AjaxResult getNextFlowNode(@RequestBody FlowTaskVo flowTaskVo) { + return flowTaskService.getNextFlowNode(flowTaskVo); + } + + @Operation(summary = "流程发起时获取下一节点") + @PostMapping(value = "/nextFlowNodeByStart") + public AjaxResult getNextFlowNodeByStart(@RequestBody FlowTaskVo flowTaskVo) { + return flowTaskService.getNextFlowNodeByStart(flowTaskVo); + } + + /** + * 生成流程图 + * + * @param processId 任务ID + */ + @GetMapping("/diagram/{processId}") + public void genProcessDiagram(HttpServletResponse response, @PathVariable("processId") String processId) { + InputStream inputStream = flowTaskService.diagram(processId); + OutputStream os = null; + BufferedImage image = null; + try { + image = ImageIO.read(inputStream); + response.setContentType("image/png"); + os = response.getOutputStream(); + if (image != null) { + ImageIO.write(image, "png", os); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (os != null) { + os.flush(); + os.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 获取流程执行节点 + * + * @param procInsId 流程实例编号 + * @param procInsId 任务执行编号 + */ + @GetMapping("/flowViewer/{procInsId}/{executionId}") + public AjaxResult getFlowViewer( + @PathVariable("procInsId") String procInsId, + @PathVariable("executionId") String executionId) { + return flowTaskService.getFlowViewer(procInsId, executionId); + } + + /** + * 流程节点信息 + * + * @param procInsId 流程实例id + * @return + */ + @GetMapping("/flowXmlAndNode") + public AjaxResult flowXmlAndNode(@RequestParam(value = "procInsId", required = false) String procInsId, + @RequestParam(value = "deployId", required = false) String deployId) { + return flowTaskService.flowXmlAndNode(procInsId, deployId); + } + + /** + * 流程节点表单 + * + * @param taskId 流程任务编号 + * @return + */ + @GetMapping("/flowTaskForm") + public AjaxResult flowTaskForm(@RequestParam(value = "taskId", required = false) String taskId) throws Exception { + return flowTaskService.flowTaskForm(taskId); + } + + /** + * 流程节点信息 + * + * @param procInsId 流程实例编号 + * @param elementId 流程节点编号 + * @return + */ + @GetMapping("/flowTaskInfo") + public AjaxResult flowTaskInfo( + @RequestParam(value = "procInsId") String procInsId, + @RequestParam(value = "elementId") String elementId) { + return flowTaskService.flowTaskInfo(procInsId, elementId); + } + +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/controller/SysExpressionController.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/controller/SysExpressionController.java new file mode 100644 index 0000000..3c4a5cd --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/controller/SysExpressionController.java @@ -0,0 +1,100 @@ +package com.boyue.flowable.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.flowable.domain.SysExpression; +import com.boyue.flowable.service.ISysExpressionService; + +import jakarta.servlet.http.HttpServletResponse; + +/** + * 流程达式Controller + * + * @author boyue + * @date 2022-12-12 + */ +@RestController +@RequestMapping("/system/expression") +public class SysExpressionController extends BaseController { + @Autowired + private ISysExpressionService sysExpressionService; + + /** + * 查询流程达式列表 + */ + @PreAuthorize("@ss.hasPermi('system:expression:list')") + @GetMapping("/list") + public TableDataInfo list(SysExpression sysExpression) { + startPage(); + List list = sysExpressionService.selectSysExpressionList(sysExpression); + return getDataTable(list); + } + + /** + * 导出流程达式列表 + */ + @PreAuthorize("@ss.hasPermi('system:expression:export')") + @Log(title = "流程达式", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, SysExpression sysExpression) { + List list = sysExpressionService.selectSysExpressionList(sysExpression); + ExcelUtil util = new ExcelUtil(SysExpression.class); + util.exportExcel(response, list, "流程达式数据"); + } + + /** + * 获取流程达式详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:expression:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return success(sysExpressionService.selectSysExpressionById(id)); + } + + /** + * 新增流程达式 + */ + @PreAuthorize("@ss.hasPermi('system:expression:add')") + @Log(title = "流程达式", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody SysExpression sysExpression) { + return toAjax(sysExpressionService.insertSysExpression(sysExpression)); + } + + /** + * 修改流程达式 + */ + @PreAuthorize("@ss.hasPermi('system:expression:edit')") + @Log(title = "流程达式", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody SysExpression sysExpression) { + return toAjax(sysExpressionService.updateSysExpression(sysExpression)); + } + + /** + * 删除流程达式 + */ + @PreAuthorize("@ss.hasPermi('system:expression:remove')") + @Log(title = "流程达式", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(sysExpressionService.deleteSysExpressionByIds(ids)); + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/controller/SysListenerController.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/controller/SysListenerController.java new file mode 100644 index 0000000..d5611f0 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/controller/SysListenerController.java @@ -0,0 +1,100 @@ +package com.boyue.flowable.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.flowable.domain.SysListener; +import com.boyue.flowable.service.ISysListenerService; + +import jakarta.servlet.http.HttpServletResponse; + +/** + * 流程监听Controller + * + * @author Tony + * @date 2022-12-25 + */ +@RestController +@RequestMapping("/system/listener") +public class SysListenerController extends BaseController { + @Autowired + private ISysListenerService sysListenerService; + + /** + * 查询流程监听列表 + */ + @PreAuthorize("@ss.hasPermi('system:listener:list')") + @GetMapping("/list") + public TableDataInfo list(SysListener sysListener) { + startPage(); + List list = sysListenerService.selectSysListenerList(sysListener); + return getDataTable(list); + } + + /** + * 导出流程监听列表 + */ + @PreAuthorize("@ss.hasPermi('system:listener:export')") + @Log(title = "流程监听", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, SysListener sysListener) { + List list = sysListenerService.selectSysListenerList(sysListener); + ExcelUtil util = new ExcelUtil(SysListener.class); + util.exportExcel(response, list, "流程监听数据"); + } + + /** + * 获取流程监听详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:listener:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return success(sysListenerService.selectSysListenerById(id)); + } + + /** + * 新增流程监听 + */ + @PreAuthorize("@ss.hasPermi('system:listener:add')") + @Log(title = "流程监听", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody SysListener sysListener) { + return toAjax(sysListenerService.insertSysListener(sysListener)); + } + + /** + * 修改流程监听 + */ + @PreAuthorize("@ss.hasPermi('system:listener:edit')") + @Log(title = "流程监听", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody SysListener sysListener) { + return toAjax(sysListenerService.updateSysListener(sysListener)); + } + + /** + * 删除流程监听 + */ + @PreAuthorize("@ss.hasPermi('system:listener:remove')") + @Log(title = "流程监听", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(sysListenerService.deleteSysListenerByIds(ids)); + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/SysDeployForm.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/SysDeployForm.java new file mode 100644 index 0000000..7aeab39 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/SysDeployForm.java @@ -0,0 +1,65 @@ +package com.boyue.flowable.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.core.domain.BaseEntity; + +/** + * 流程实例关联表单对象 sys_instance_form + * + * @author Tony + * @date 2021-03-30 + */ +public class SysDeployForm extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 主键 */ + private Long id; + + /** 表单主键 */ + @Excel(name = "表单主键") + private Long formId; + + /** 流程定义主键 */ + @Excel(name = "流程定义主键") + private String deployId; + + public void setId(Long id) + { + this.id = id; + } + + public Long getId() + { + return id; + } + public void setFormId(Long formId) + { + this.formId = formId; + } + + public Long getFormId() + { + return formId; + } + + public String getDeployId() { + return deployId; + } + + public void setDeployId(String deployId) { + this.deployId = deployId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("formId", getFormId()) + .append("deployId", getDeployId()) + .toString(); + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/SysExpression.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/SysExpression.java new file mode 100644 index 0000000..5a499a9 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/SysExpression.java @@ -0,0 +1,96 @@ +package com.boyue.flowable.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.core.domain.BaseEntity; + +/** + * 流程达式对象 sys_expression + * + * @author boyue + * @date 2022-12-12 + */ +public class SysExpression extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 表单主键 */ + private Long id; + + /** 表达式名称 */ + @Excel(name = "表达式名称") + private String name; + + /** 表达式内容 */ + @Excel(name = "表达式内容") + private String expression; + /** 表达式类型 */ + @Excel(name = "表达式类型") + private String dataType; + + /** 状态 */ + private Integer status; + + public void setId(Long id) + { + this.id = id; + } + + public Long getId() + { + return id; + } + public void setName(String name) + { + this.name = name; + } + + public String getName() + { + return name; + } + public void setExpression(String expression) + { + this.expression = expression; + } + + public String getExpression() + { + return expression; + } + public void setStatus(Integer status) + { + this.status = status; + } + + public Integer getStatus() + { + return status; + } + + public void setDataType(String dataType) { + this.dataType = dataType; + } + public String getDataType() { + return dataType; + } + + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("name", getName()) + .append("expression", getExpression()) + .append("dataType", getDataType()) + .append("createTime", getCreateTime()) + .append("updateTime", getUpdateTime()) + .append("createBy", getCreateBy()) + .append("updateBy", getUpdateBy()) + .append("status", getStatus()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/SysListener.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/SysListener.java new file mode 100644 index 0000000..81cb2c0 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/SysListener.java @@ -0,0 +1,127 @@ +package com.boyue.flowable.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.core.domain.BaseEntity; + +/** + * 流程监听对象 sys_listener + * + * @author Tony + * @date 2022-12-25 + */ +public class SysListener extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 表单主键 */ + private Long id; + + /** 名称 */ + @Excel(name = "名称") + private String name; + + /** 监听类型 */ + @Excel(name = "监听类型") + private String type; + + /** 事件类型 */ + @Excel(name = "事件类型") + private String eventType; + + /** 值类型 */ + @Excel(name = "值类型") + private String valueType; + + /** 执行内容 */ + @Excel(name = "执行内容") + private String value; + + /** 状态 */ + @Excel(name = "状态") + private Integer status; + + public void setId(Long id) + { + this.id = id; + } + + public Long getId() + { + return id; + } + public void setName(String name) + { + this.name = name; + } + + public String getName() + { + return name; + } + public void setType(String type) + { + this.type = type; + } + + public String getType() + { + return type; + } + public void setEventType(String eventType) + { + this.eventType = eventType; + } + + public String getEventType() + { + return eventType; + } + public void setValueType(String valueType) + { + this.valueType = valueType; + } + + public String getValueType() + { + return valueType; + } + public void setValue(String value) + { + this.value = value; + } + + public String getValue() + { + return value; + } + public void setStatus(Integer status) + { + this.status = status; + } + + public Integer getStatus() + { + return status; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("name", getName()) + .append("type", getType()) + .append("eventType", getEventType()) + .append("valueType", getValueType()) + .append("value", getValue()) + .append("createTime", getCreateTime()) + .append("updateTime", getUpdateTime()) + .append("createBy", getCreateBy()) + .append("updateBy", getUpdateBy()) + .append("status", getStatus()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/SysTaskForm.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/SysTaskForm.java new file mode 100644 index 0000000..9da3e2b --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/SysTaskForm.java @@ -0,0 +1,66 @@ +package com.boyue.flowable.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.core.domain.BaseEntity; + +/** + * 流程任务关联单对象 sys_task_form + * + * @author Tony + * @date 2021-04-03 + */ +public class SysTaskForm extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 主键 */ + private Long id; + + /** 表单主键 */ + @Excel(name = "表单主键") + private Long formId; + + /** 所属任务 */ + @Excel(name = "所属任务") + private String taskId; + + public void setId(Long id) + { + this.id = id; + } + + public Long getId() + { + return id; + } + public void setFormId(Long formId) + { + this.formId = formId; + } + + public Long getFormId() + { + return formId; + } + public void setTaskId(String taskId) + { + this.taskId = taskId; + } + + public String getTaskId() + { + return taskId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("formId", getFormId()) + .append("taskId", getTaskId()) + .toString(); + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowCommentDto.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowCommentDto.java new file mode 100644 index 0000000..1195e39 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowCommentDto.java @@ -0,0 +1,25 @@ +package com.boyue.flowable.domain.dto; + +import lombok.Builder; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author Tony + * @date 2021/3/28 15:50 + */ +@Data +@Builder +public class FlowCommentDto implements Serializable { + + /** + * 意见类别 0 正常意见 1 退回意见 2 驳回意见 + */ + private String type; + + /** + * 意见内容 + */ + private String comment; +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowFromFieldDTO.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowFromFieldDTO.java new file mode 100644 index 0000000..d8c2fb0 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowFromFieldDTO.java @@ -0,0 +1,15 @@ +package com.boyue.flowable.domain.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author Tony + * @date 2021/3/31 23:20 + */ +@Data +public class FlowFromFieldDTO implements Serializable { + + private Object fields; +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowNextDto.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowNextDto.java new file mode 100644 index 0000000..cddf873 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowNextDto.java @@ -0,0 +1,30 @@ +package com.boyue.flowable.domain.dto; + +import java.io.Serializable; + +import lombok.Data; + +/** + * 动态人员、组 + * @author Tony + * @date 2021/4/17 22:59 + */ +@Data +public class FlowNextDto implements Serializable { + + /** + * 审批人类型 + */ + private String type; + + /** + * 是否需要动态指定任务审批人 + */ + private String dataType; + + /** + * 流程变量 + */ + private String vars; + +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowProcDefDto.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowProcDefDto.java new file mode 100644 index 0000000..ff34aec --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowProcDefDto.java @@ -0,0 +1,56 @@ +package com.boyue.flowable.domain.dto; +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + *

流程定义

+ * + * @author Tony + * @date 2021-04-03 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Schema(description = "流程定义") +public class FlowProcDefDto implements Serializable { + + @Schema(title = "流程id") + private String id; + + @Schema(title = "流程名称") + private String name; + + @Schema(title = "流程key") + private String flowKey; + + @Schema(title = "流程分类") + private String category; + + @Schema(title = "配置表单名称") + private String formName; + + @Schema(title = "配置表单id") + private Long formId; + + @Schema(title = "版本") + private int version; + + @Schema(title = "部署ID") + private String deploymentId; + + @Schema(title = "流程定义状态: 1:激活 , 2:中止") + private int suspensionState; + + @Schema(title = "部署时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date deploymentTime; + + +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowSaveXmlVo.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowSaveXmlVo.java new file mode 100644 index 0000000..cfa1817 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowSaveXmlVo.java @@ -0,0 +1,28 @@ +package com.boyue.flowable.domain.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author Tony + * @date 2021/3/28 19:48 + */ +@Data +public class FlowSaveXmlVo implements Serializable { + + /** + * 流程名称 + */ + private String name; + + /** + * 流程分类 + */ + private String category; + + /** + * xml 文件 + */ + private String xml; +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowTaskDto.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowTaskDto.java new file mode 100644 index 0000000..e44dbd5 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowTaskDto.java @@ -0,0 +1,104 @@ +package com.boyue.flowable.domain.dto; + +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +/** + *

+ * 工作流任务 + *

+ * + * @author Tony + * @date 2021-04-03 + */ +@Getter +@Setter +@Schema(description = "工作流任务相关-返回参数") +public class FlowTaskDto implements Serializable { + + @Schema(title = "任务编号") + private String taskId; + + @Schema(title = "任务执行编号") + private String executionId; + + @Schema(title = "任务名称") + private String taskName; + + @Schema(title = "任务Key") + private String taskDefKey; + + @Schema(title = "任务执行人Id") + private Long assigneeId; + + @Schema(title = "部门名称") + private String deptName; + + @Schema(title = "流程发起人部门名称") + private String startDeptName; + + @Schema(title = "任务执行人名称") + private String assigneeName; + @Schema(title = "任务执行人部门") + private String assigneeDeptName;; + + @Schema(title = "流程发起人Id") + private String startUserId; + + @Schema(title = "流程发起人名称") + private String startUserName; + + @Schema(title = "流程类型") + private String category; + + @Schema(title = "流程变量信息") + private Object variables; + + @Schema(title = "局部变量信息") + private Object taskLocalVars; + + @Schema(title = "流程部署编号") + private String deployId; + + @Schema(title = "流程ID") + private String procDefId; + + @Schema(title = "流程key") + private String procDefKey; + + @Schema(title = "流程定义名称") + private String procDefName; + + @Schema(title = "流程定义内置使用版本") + private int procDefVersion; + + @Schema(title = "流程实例ID") + private String procInsId; + + @Schema(title = "历史流程实例ID") + private String hisProcInsId; + + @Schema(title = "任务耗时") + private String duration; + + @Schema(title = "任务意见") + private FlowCommentDto comment; + + @Schema(title = "候选执行人") + private String candidate; + + @Schema(title = "任务创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(title = "任务完成时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date finishTime; + +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowViewerDto.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowViewerDto.java new file mode 100644 index 0000000..b44b43d --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/dto/FlowViewerDto.java @@ -0,0 +1,23 @@ +package com.boyue.flowable.domain.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author Tony + * @date 2021/4/21 20:55 + */ +@Data +public class FlowViewerDto implements Serializable { + + /** + * 流程key + */ + private String key; + + /** + * 是否完成(已经审批) + */ + private boolean completed; +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/vo/FlowQueryVo.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/vo/FlowQueryVo.java new file mode 100644 index 0000000..34c97db --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/vo/FlowQueryVo.java @@ -0,0 +1,32 @@ +package com.boyue.flowable.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + *

流程任务

+ * + * @author Tony + * @date 2021-04-03 + */ +@Data +@Schema(description = "工作流任务相关--请求参数") +public class FlowQueryVo { + + @Schema(title = "流程名称") + private String name; + + @Schema(title = "开始时间") + private String startTime; + + @Schema(title = "结束时间") + private String endTime; + + @Schema(title = "当前页码") + private Integer pageNum; + + @Schema(title = "每页条数") + private Integer pageSize; + + +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/vo/FlowTaskVo.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/vo/FlowTaskVo.java new file mode 100644 index 0000000..98aa263 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/vo/FlowTaskVo.java @@ -0,0 +1,55 @@ +package com.boyue.flowable.domain.vo; + +import java.util.List; +import java.util.Map; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + *

流程任务

+ * + * @author Tony + * @date 2021-04-03 + */ +@Data +@Schema(description = "工作流任务相关--请求参数") +public class FlowTaskVo { + + @Schema(title = "任务Id") + private String taskId; + + @Schema(title = "用户Id") + private String userId; + + @Schema(title = "任务意见") + private String comment; + + @Schema(title = "流程实例Id") + private String instanceId; + + @Schema(title = "节点") + private String targetKey; + + private String deploymentId; + @Schema(title = "流程环节定义ID") + private String defId; + + @Schema(title = "子执行流ID") + private String currentChildExecutionId; + + @Schema(title = "子执行流是否已执行") + private Boolean flag; + + @Schema(title = "流程变量信息") + private Map variables; + + @Schema(title = "审批人") + private String assignee; + + @Schema(title = "候选人") + private List candidateUsers; + + @Schema(title = "审批组") + private List candidateGroups; +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/vo/ReturnTaskNodeVo.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/vo/ReturnTaskNodeVo.java new file mode 100644 index 0000000..66a76ad --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/domain/vo/ReturnTaskNodeVo.java @@ -0,0 +1,22 @@ +package com.boyue.flowable.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + *

可退回节点

+ * + * @author tony + * @date 2022-04-23 11:01:52 + */ +@Data +@Schema(description = "可退回节点") +public class ReturnTaskNodeVo { + + @Schema(title = "任务Id") + private String id; + + @Schema(title = "用户Id") + private String name; + +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/expression/FlowDelegationExpression.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/expression/FlowDelegationExpression.java new file mode 100644 index 0000000..a8f2e98 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/expression/FlowDelegationExpression.java @@ -0,0 +1,16 @@ +package com.boyue.flowable.expression; + +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.JavaDelegate; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component("flowDelegationExpression") +public class FlowDelegationExpression implements JavaDelegate { + @Override + public void execute(DelegateExecution execution) { + log.info("代理表达式执行器:{}", execution); + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/factory/FlowServiceFactory.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/factory/FlowServiceFactory.java new file mode 100644 index 0000000..2a7519a --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/factory/FlowServiceFactory.java @@ -0,0 +1,48 @@ +package com.boyue.flowable.factory; + +import org.flowable.engine.HistoryService; +import org.flowable.engine.IdentityService; +import org.flowable.engine.ManagementService; +import org.flowable.engine.ProcessEngine; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import jakarta.annotation.Resource; +import lombok.Getter; + + +/** + * flowable 引擎注入封装 + * @author Tony + * @date 2021-04-03 + */ +@Component +@Getter +public class FlowServiceFactory { + + @Resource + protected RepositoryService repositoryService; + + @Resource + protected RuntimeService runtimeService; + + @Resource + protected IdentityService identityService; + + @Resource + protected TaskService taskService; + + @Resource + protected HistoryService historyService; + + @Resource + protected ManagementService managementService; + + @Qualifier("processEngine") + @Resource + protected ProcessEngine processEngine; + +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/flow/CustomProcessDiagramCanvas.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/flow/CustomProcessDiagramCanvas.java new file mode 100644 index 0000000..5cca47a --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/flow/CustomProcessDiagramCanvas.java @@ -0,0 +1,457 @@ +package com.boyue.flowable.flow; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.Paint; +import java.awt.RenderingHints; +import java.awt.Stroke; +import java.awt.font.FontRenderContext; +import java.awt.font.LineBreakMeasurer; +import java.awt.font.TextAttribute; +import java.awt.font.TextLayout; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; + +import javax.imageio.ImageIO; + +import org.flowable.bpmn.model.AssociationDirection; +import org.flowable.bpmn.model.GraphicInfo; +import org.flowable.image.impl.DefaultProcessDiagramCanvas; +import org.flowable.image.util.ReflectUtil; + +/** + * @author Tony + * @date 2021/4/4 23:58 + */ +public class CustomProcessDiagramCanvas extends DefaultProcessDiagramCanvas { + // 定义走过流程连线颜色为绿色 + protected static Color HIGHLIGHT_SequenceFlow_COLOR = Color.GREEN; + // 设置未走过流程的连接线颜色 + protected static Color CONNECTION_COLOR = Color.BLACK; + // 设置flows连接线字体颜色red + protected static Color LABEL_COLOR = new Color(0, 0, 0); + // 高亮显示task框颜色 + protected static Color HIGHLIGHT_COLOR = Color.GREEN; + protected static Color HIGHLIGHT_COLOR1 = Color.RED; + + public CustomProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, + String activityFontName, String labelFontName, String annotationFontName, + ClassLoader customClassLoader) { + super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, + customClassLoader); + this.initialize(imageType); + } + + /** + * 重写绘制连线的方式,设置绘制颜色 + * + * @param xPoints + * @param yPoints + * @param conditional + * @param isDefault + * @param connectionType + * @param associationDirection + * @param highLighted + * @param scaleFactor + */ + @Override + public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, + String connectionType, AssociationDirection associationDirection, boolean highLighted, + double scaleFactor) { + Paint originalPaint = this.g.getPaint(); + Stroke originalStroke = this.g.getStroke(); + this.g.setPaint(CONNECTION_COLOR); + if (connectionType.equals("association")) { + this.g.setStroke(ASSOCIATION_STROKE); + } else if (highLighted) { + this.g.setPaint(HIGHLIGHT_SequenceFlow_COLOR); + this.g.setStroke(HIGHLIGHT_FLOW_STROKE); + } + + for (int i = 1; i < xPoints.length; ++i) { + Integer sourceX = xPoints[i - 1]; + Integer sourceY = yPoints[i - 1]; + Integer targetX = xPoints[i]; + Integer targetY = yPoints[i]; + java.awt.geom.Line2D.Double line = new java.awt.geom.Line2D.Double((double) sourceX, + (double) sourceY, + (double) targetX, (double) targetY); + this.g.draw(line); + } + + java.awt.geom.Line2D.Double line; + if (isDefault) { + line = new java.awt.geom.Line2D.Double((double) xPoints[0], (double) yPoints[0], + (double) xPoints[1], + (double) yPoints[1]); + this.drawDefaultSequenceFlowIndicator(line, scaleFactor); + } + + if (conditional) { + line = new java.awt.geom.Line2D.Double((double) xPoints[0], (double) yPoints[0], + (double) xPoints[1], + (double) yPoints[1]); + this.drawConditionalSequenceFlowIndicator(line, scaleFactor); + } + + if (associationDirection.equals(AssociationDirection.ONE) + || associationDirection.equals(AssociationDirection.BOTH)) { + line = new java.awt.geom.Line2D.Double((double) xPoints[xPoints.length - 2], + (double) yPoints[xPoints.length - 2], (double) xPoints[xPoints.length - 1], + (double) yPoints[xPoints.length - 1]); + this.drawArrowHead(line, scaleFactor); + } + + if (associationDirection.equals(AssociationDirection.BOTH)) { + line = new java.awt.geom.Line2D.Double((double) xPoints[1], (double) yPoints[1], + (double) xPoints[0], + (double) yPoints[0]); + this.drawArrowHead(line, scaleFactor); + } + + this.g.setPaint(originalPaint); + this.g.setStroke(originalStroke); + } + + /** + * 设置字体大小图标颜色 + * + * @param imageType + */ + @Override + public void initialize(String imageType) { + if ("png".equalsIgnoreCase(imageType)) { + this.processDiagram = new BufferedImage(this.canvasWidth, this.canvasHeight, 2); + } else { + this.processDiagram = new BufferedImage(this.canvasWidth, this.canvasHeight, 1); + } + + this.g = this.processDiagram.createGraphics(); + if (!"png".equalsIgnoreCase(imageType)) { + this.g.setBackground(new Color(255, 255, 255, 0)); + this.g.clearRect(0, 0, this.canvasWidth, this.canvasHeight); + } + + this.g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + // 修改图标颜色,修改图标字体大小 + this.g.setPaint(Color.black); + Font font = new Font(this.activityFontName, 10, 14); + this.g.setFont(font); + this.fontMetrics = this.g.getFontMetrics(); + // 修改连接线字体大小 + LABEL_FONT = new Font(this.labelFontName, 10, 15); + ANNOTATION_FONT = new Font(this.annotationFontName, 0, 11); + + try { + USERTASK_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/userTask.png", + this.customClassLoader)); + SCRIPTTASK_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/scriptTask.png", + this.customClassLoader)); + SERVICETASK_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/serviceTask.png", + this.customClassLoader)); + RECEIVETASK_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/receiveTask.png", + this.customClassLoader)); + SENDTASK_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/sendTask.png", + this.customClassLoader)); + CASETASK_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/caseTask.png", + this.customClassLoader)); + MANUALTASK_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/manualTask.png", + this.customClassLoader)); + BUSINESS_RULE_TASK_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/businessRuleTask.png", + this.customClassLoader)); + SHELL_TASK_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/shellTask.png", + this.customClassLoader)); + DMN_TASK_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/dmnTask.png", + this.customClassLoader)); + CAMEL_TASK_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/camelTask.png", + this.customClassLoader)); + HTTP_TASK_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/httpTask.png", + this.customClassLoader)); + TIMER_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/timer.png", + this.customClassLoader)); + COMPENSATE_THROW_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/compensate-throw.png", + this.customClassLoader)); + COMPENSATE_CATCH_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/compensate.png", + this.customClassLoader)); + CONDITIONAL_CATCH_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/conditional.png", + this.customClassLoader)); + ERROR_THROW_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/error-throw.png", + this.customClassLoader)); + ERROR_CATCH_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/error.png", + this.customClassLoader)); + ESCALATION_THROW_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/escalation-throw.png", + this.customClassLoader)); + ESCALATION_CATCH_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/escalation.png", + this.customClassLoader)); + MESSAGE_THROW_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/message-throw.png", + this.customClassLoader)); + MESSAGE_CATCH_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/message.png", + this.customClassLoader)); + SIGNAL_THROW_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/signal-throw.png", + this.customClassLoader)); + SIGNAL_CATCH_IMAGE = ImageIO + .read(ReflectUtil.getResource("org/flowable/icons/signal.png", + this.customClassLoader)); + + } catch (IOException var4) { + LOGGER.warn("Could not load image for process diagram creation: {}", var4.getMessage()); + } + + } + + /** + * 设置连接线字体 + * + * @param text + * @param graphicInfo + * @param centered + */ + @Override + public void drawLabel(String text, GraphicInfo graphicInfo, boolean centered) { + float interline = 1.0f; + + // text + if (text != null && text.length() > 0) { + Paint originalPaint = g.getPaint(); + Font originalFont = g.getFont(); + + g.setPaint(LABEL_COLOR); + g.setFont(LABEL_FONT); + + int wrapWidth = 100; + int textY = (int) graphicInfo.getY(); + + AttributedString as = new AttributedString(text); + as.addAttribute(TextAttribute.FOREGROUND, g.getPaint()); + as.addAttribute(TextAttribute.FONT, g.getFont()); + AttributedCharacterIterator aci = as.getIterator(); + FontRenderContext frc = new FontRenderContext(null, true, false); + LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc); + + while (lbm.getPosition() < text.length()) { + TextLayout tl = lbm.nextLayout(wrapWidth); + textY += tl.getAscent(); + + Rectangle2D bb = tl.getBounds(); + double tX = graphicInfo.getX(); + + if (centered) { + tX += (int) (graphicInfo.getWidth() / 2 - bb.getWidth() / 2); + } + tl.draw(g, (float) tX, textY); + textY += tl.getDescent() + tl.getLeading() + (interline - 1.0f) * tl.getAscent(); + } + + // restore originals + g.setFont(originalFont); + g.setPaint(originalPaint); + } + } + + /** + * 高亮显示task框完成的 + * + * @param x + * @param y + * @param width + * @param height + */ + @Override + public void drawHighLight(int x, int y, int width, int height) { + Paint originalPaint = g.getPaint(); + Stroke originalStroke = g.getStroke(); + + g.setPaint(HIGHLIGHT_COLOR); + g.setStroke(THICK_TASK_BORDER_STROKE); + + RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20); + g.draw(rect); + + g.setPaint(originalPaint); + g.setStroke(originalStroke); + } + + /** + * 自定义task框当前的位置 + * + * @param x + * @param y + * @param width + * @param height + */ + public void drawHighLightNow(int x, int y, int width, int height) { + Paint originalPaint = g.getPaint(); + Stroke originalStroke = g.getStroke(); + + g.setPaint(HIGHLIGHT_COLOR1); + g.setStroke(THICK_TASK_BORDER_STROKE); + + RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20); + g.draw(rect); + + g.setPaint(originalPaint); + g.setStroke(originalStroke); + } + + /** + * 自定义结束节点 + * + * @param x + * @param y + * @param width + * @param height + */ + public void drawHighLightEnd(int x, int y, int width, int height) { + Paint originalPaint = g.getPaint(); + Stroke originalStroke = g.getStroke(); + + g.setPaint(HIGHLIGHT_COLOR); + g.setStroke(THICK_TASK_BORDER_STROKE); + + RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20); + g.draw(rect); + + g.setPaint(originalPaint); + g.setStroke(originalStroke); + } + + /** + * task框自定义文字 + * + * @param name + * @param graphicInfo + * @param thickBorder + * @param scaleFactor + */ + @Override + protected void drawTask(String name, GraphicInfo graphicInfo, boolean thickBorder, double scaleFactor) { + + Paint originalPaint = g.getPaint(); + int x = (int) graphicInfo.getX(); + int y = (int) graphicInfo.getY(); + int width = (int) graphicInfo.getWidth(); + int height = (int) graphicInfo.getHeight(); + + // Create a new gradient paint for every task box, gradient depends on x and y + // and is not relative + g.setPaint(TASK_BOX_COLOR); + + int arcR = 6; + if (thickBorder) { + arcR = 3; + } + + // shape + RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, arcR, arcR); + g.fill(rect); + g.setPaint(TASK_BORDER_COLOR); + + if (thickBorder) { + Stroke originalStroke = g.getStroke(); + g.setStroke(THICK_TASK_BORDER_STROKE); + g.draw(rect); + g.setStroke(originalStroke); + } else { + g.draw(rect); + } + + g.setPaint(originalPaint); + // text + if (scaleFactor == 1.0 && name != null && name.length() > 0) { + int boxWidth = width - (2 * TEXT_PADDING); + int boxHeight = height - 16 - ICON_PADDING - ICON_PADDING - MARKER_WIDTH - 2 - 2; + int boxX = x + width / 2 - boxWidth / 2; + int boxY = y + height / 2 - boxHeight / 2 + ICON_PADDING + ICON_PADDING - 2 - 2; + + drawMultilineCentredText(name, boxX, boxY, boxWidth, boxHeight); + } + } + + protected static Color EVENT_COLOR = new Color(255, 255, 255); + + /** + * 重写开始事件 + * + * @param graphicInfo + * @param image + * @param scaleFactor + */ + @Override + public void drawStartEvent(GraphicInfo graphicInfo, BufferedImage image, double scaleFactor) { + Paint originalPaint = g.getPaint(); + g.setPaint(EVENT_COLOR); + Ellipse2D circle = new Ellipse2D.Double(graphicInfo.getX(), graphicInfo.getY(), + graphicInfo.getWidth(), graphicInfo.getHeight()); + g.fill(circle); + g.setPaint(EVENT_BORDER_COLOR); + g.draw(circle); + g.setPaint(originalPaint); + if (image != null) { + // calculate coordinates to center image + int imageX = (int) Math + .round(graphicInfo.getX() + (graphicInfo.getWidth() / 2) + - (image.getWidth() / (2 * scaleFactor))); + int imageY = (int) Math.round( + graphicInfo.getY() + (graphicInfo.getHeight() / 2) + - (image.getHeight() / (2 * scaleFactor))); + g.drawImage(image, imageX, imageY, + (int) (image.getWidth() / scaleFactor), (int) (image.getHeight() / scaleFactor), + null); + } + + } + + /** + * 重写结束事件 + * + * @param graphicInfo + * @param scaleFactor + */ + @Override + public void drawNoneEndEvent(GraphicInfo graphicInfo, double scaleFactor) { + Paint originalPaint = g.getPaint(); + Stroke originalStroke = g.getStroke(); + g.setPaint(EVENT_COLOR); + Ellipse2D circle = new Ellipse2D.Double(graphicInfo.getX(), graphicInfo.getY(), + graphicInfo.getWidth(), graphicInfo.getHeight()); + g.fill(circle); + g.setPaint(EVENT_BORDER_COLOR); + // g.setPaint(HIGHLIGHT_COLOR); + if (scaleFactor == 1.0) { + g.setStroke(END_EVENT_STROKE); + } else { + g.setStroke(new BasicStroke(2.0f)); + } + g.draw(circle); + g.setStroke(originalStroke); + g.setPaint(originalPaint); + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/flow/CustomProcessDiagramGenerator.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/flow/CustomProcessDiagramGenerator.java new file mode 100644 index 0000000..9b299fd --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/flow/CustomProcessDiagramGenerator.java @@ -0,0 +1,431 @@ +package com.boyue.flowable.flow; + +import java.util.Iterator; +import java.util.List; + +import org.flowable.bpmn.model.Activity; +import org.flowable.bpmn.model.Artifact; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.CallActivity; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.FlowElementsContainer; +import org.flowable.bpmn.model.FlowNode; +import org.flowable.bpmn.model.Gateway; +import org.flowable.bpmn.model.GraphicInfo; +import org.flowable.bpmn.model.Lane; +import org.flowable.bpmn.model.MultiInstanceLoopCharacteristics; +import org.flowable.bpmn.model.Pool; +import org.flowable.bpmn.model.Process; +import org.flowable.bpmn.model.SequenceFlow; +import org.flowable.bpmn.model.SubProcess; +import org.flowable.image.impl.DefaultProcessDiagramCanvas; +import org.flowable.image.impl.DefaultProcessDiagramGenerator; + +/** + * @author Tony + * @date 2021/4/5 0:31 + */ +public class CustomProcessDiagramGenerator extends DefaultProcessDiagramGenerator { + @Override + protected DefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType, + List highLightedActivities, List highLightedFlows, String activityFontName, + String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, + boolean drawSequenceFlowNameWithNoLabelDI) { + this.prepareBpmnModel(bpmnModel); + DefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, + activityFontName, labelFontName, annotationFontName, customClassLoader); + Iterator var13 = bpmnModel.getPools().iterator(); + + while (var13.hasNext()) { + Pool process = (Pool) var13.next(); + GraphicInfo subProcesses = bpmnModel.getGraphicInfo(process.getId()); + processDiagramCanvas.drawPoolOrLane(process.getName(), subProcesses, scaleFactor); + } + + var13 = bpmnModel.getProcesses().iterator(); + + Process process1; + Iterator subProcesses1; + while (var13.hasNext()) { + process1 = (Process) var13.next(); + subProcesses1 = process1.getLanes().iterator(); + + while (subProcesses1.hasNext()) { + Lane artifact = (Lane) subProcesses1.next(); + GraphicInfo subProcess = bpmnModel.getGraphicInfo(artifact.getId()); + processDiagramCanvas.drawPoolOrLane(artifact.getName(), subProcess, scaleFactor); + } + } + + var13 = bpmnModel.getProcesses().iterator(); + + while (var13.hasNext()) { + process1 = (Process) var13.next(); + subProcesses1 = process1.findFlowElementsOfType(FlowNode.class).iterator(); + + while (subProcesses1.hasNext()) { + FlowNode artifact1 = (FlowNode) subProcesses1.next(); + if (!this.isPartOfCollapsedSubProcess(artifact1, bpmnModel)) { + this.drawActivity(processDiagramCanvas, bpmnModel, artifact1, highLightedActivities, + highLightedFlows, scaleFactor, Boolean.valueOf(drawSequenceFlowNameWithNoLabelDI)); + } + } + } + + var13 = bpmnModel.getProcesses().iterator(); + + label75: while (true) { + List subProcesses2; + do { + if (!var13.hasNext()) { + return processDiagramCanvas; + } + + process1 = (Process) var13.next(); + subProcesses1 = process1.getArtifacts().iterator(); + + while (subProcesses1.hasNext()) { + Artifact artifact2 = (Artifact) subProcesses1.next(); + this.drawArtifact(processDiagramCanvas, bpmnModel, artifact2); + } + + subProcesses2 = process1.findFlowElementsOfType(SubProcess.class, true); + } while (subProcesses2 == null); + + Iterator artifact3 = subProcesses2.iterator(); + + while (true) { + GraphicInfo graphicInfo; + SubProcess subProcess1; + do { + do { + if (!artifact3.hasNext()) { + continue label75; + } + + subProcess1 = (SubProcess) artifact3.next(); + graphicInfo = bpmnModel.getGraphicInfo(subProcess1.getId()); + } while (graphicInfo != null && graphicInfo.getExpanded() != null + && !graphicInfo.getExpanded().booleanValue()); + } while (this.isPartOfCollapsedSubProcess(subProcess1, bpmnModel)); + + Iterator var19 = subProcess1.getArtifacts().iterator(); + + while (var19.hasNext()) { + Artifact subProcessArtifact = (Artifact) var19.next(); + this.drawArtifact(processDiagramCanvas, bpmnModel, subProcessArtifact); + } + } + } + } + + protected static DefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType, + String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) { + double minX = 1.7976931348623157E308D; + double maxX = 0.0D; + double minY = 1.7976931348623157E308D; + double maxY = 0.0D; + + GraphicInfo nrOfLanes; + for (Iterator flowNodes = bpmnModel.getPools().iterator(); flowNodes + .hasNext(); maxY = nrOfLanes.getY() + nrOfLanes.getHeight()) { + Pool artifacts = (Pool) flowNodes.next(); + nrOfLanes = bpmnModel.getGraphicInfo(artifacts.getId()); + minX = nrOfLanes.getX(); + maxX = nrOfLanes.getX() + nrOfLanes.getWidth(); + minY = nrOfLanes.getY(); + } + + List var23 = gatherAllFlowNodes(bpmnModel); + Iterator var24 = var23.iterator(); + + label155: while (var24.hasNext()) { + FlowNode var26 = (FlowNode) var24.next(); + GraphicInfo artifact = bpmnModel.getGraphicInfo(var26.getId()); + if (artifact.getX() + artifact.getWidth() > maxX) { + maxX = artifact.getX() + artifact.getWidth(); + } + + if (artifact.getX() < minX) { + minX = artifact.getX(); + } + + if (artifact.getY() + artifact.getHeight() > maxY) { + maxY = artifact.getY() + artifact.getHeight(); + } + + if (artifact.getY() < minY) { + minY = artifact.getY(); + } + + Iterator process = var26.getOutgoingFlows().iterator(); + + while (true) { + List l; + do { + if (!process.hasNext()) { + continue label155; + } + + SequenceFlow graphicInfoList = (SequenceFlow) process.next(); + l = bpmnModel.getFlowLocationGraphicInfo(graphicInfoList.getId()); + } while (l == null); + + Iterator graphicInfo = l.iterator(); + + while (graphicInfo.hasNext()) { + GraphicInfo graphicInfo1 = (GraphicInfo) graphicInfo.next(); + if (graphicInfo1.getX() > maxX) { + maxX = graphicInfo1.getX(); + } + + if (graphicInfo1.getX() < minX) { + minX = graphicInfo1.getX(); + } + + if (graphicInfo1.getY() > maxY) { + maxY = graphicInfo1.getY(); + } + + if (graphicInfo1.getY() < minY) { + minY = graphicInfo1.getY(); + } + } + } + } + + List var25 = gatherAllArtifacts(bpmnModel); + Iterator var27 = var25.iterator(); + + GraphicInfo var37; + while (var27.hasNext()) { + Artifact var29 = (Artifact) var27.next(); + GraphicInfo var31 = bpmnModel.getGraphicInfo(var29.getId()); + if (var31 != null) { + if (var31.getX() + var31.getWidth() > maxX) { + maxX = var31.getX() + var31.getWidth(); + } + + if (var31.getX() < minX) { + minX = var31.getX(); + } + + if (var31.getY() + var31.getHeight() > maxY) { + maxY = var31.getY() + var31.getHeight(); + } + + if (var31.getY() < minY) { + minY = var31.getY(); + } + } + + List var33 = bpmnModel.getFlowLocationGraphicInfo(var29.getId()); + if (var33 != null) { + Iterator var35 = var33.iterator(); + + while (var35.hasNext()) { + var37 = (GraphicInfo) var35.next(); + if (var37.getX() > maxX) { + maxX = var37.getX(); + } + + if (var37.getX() < minX) { + minX = var37.getX(); + } + + if (var37.getY() > maxY) { + maxY = var37.getY(); + } + + if (var37.getY() < minY) { + minY = var37.getY(); + } + } + } + } + + int var28 = 0; + Iterator var30 = bpmnModel.getProcesses().iterator(); + + while (var30.hasNext()) { + Process var32 = (Process) var30.next(); + Iterator var34 = var32.getLanes().iterator(); + + while (var34.hasNext()) { + Lane var36 = (Lane) var34.next(); + ++var28; + var37 = bpmnModel.getGraphicInfo(var36.getId()); + if (var37.getX() + var37.getWidth() > maxX) { + maxX = var37.getX() + var37.getWidth(); + } + + if (var37.getX() < minX) { + minX = var37.getX(); + } + + if (var37.getY() + var37.getHeight() > maxY) { + maxY = var37.getY() + var37.getHeight(); + } + + if (var37.getY() < minY) { + minY = var37.getY(); + } + } + } + + if (var23.isEmpty() && bpmnModel.getPools().isEmpty() && var28 == 0) { + minX = 0.0D; + minY = 0.0D; + } + + return new CustomProcessDiagramCanvas((int) maxX + 10, (int) maxY + 10, (int) minX, (int) minY, imageType, + activityFontName, labelFontName, annotationFontName, customClassLoader); + } + + private static void drawHighLight(DefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) { + processDiagramCanvas.drawHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(), + (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight()); + + } + + private static void drawHighLightNow(CustomProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) { + processDiagramCanvas.drawHighLightNow((int) graphicInfo.getX(), (int) graphicInfo.getY(), + (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight()); + + } + + private static void drawHighLightEnd(CustomProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) { + processDiagramCanvas.drawHighLightEnd((int) graphicInfo.getX(), (int) graphicInfo.getY(), + (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight()); + + } + + @Override + protected void drawActivity(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, + FlowNode flowNode, java.util.List highLightedActivities, java.util.List highLightedFlows, + double scaleFactor, Boolean drawSequenceFlowNameWithNoLabelDI) { + + DefaultProcessDiagramGenerator.ActivityDrawInstruction drawInstruction = activityDrawInstructions + .get(flowNode.getClass()); + if (drawInstruction != null) { + + drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode); + + // Gather info on the multi instance marker + boolean multiInstanceSequential = false; + boolean multiInstanceParallel = false; + boolean collapsed = false; + if (flowNode instanceof Activity) { + Activity activity = (Activity) flowNode; + MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics(); + if (multiInstanceLoopCharacteristics != null) { + multiInstanceSequential = multiInstanceLoopCharacteristics.isSequential(); + multiInstanceParallel = !multiInstanceSequential; + } + } + + // Gather info on the collapsed marker + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + if (flowNode instanceof SubProcess) { + collapsed = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded(); + } else if (flowNode instanceof CallActivity) { + collapsed = true; + } + + if (scaleFactor == 1.0) { + // Actually draw the markers + processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), (int) graphicInfo.getY(), + (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(), + multiInstanceSequential, multiInstanceParallel, collapsed); + } + + // Draw highlighted activities + if (highLightedActivities.contains(flowNode.getId())) { + + if (highLightedActivities.get(highLightedActivities.size() - 1).equals(flowNode.getId()) + && !"endenv".equals(flowNode.getId())) { + if ((flowNode.getId().contains("Event_"))) { + drawHighLightEnd((CustomProcessDiagramCanvas) processDiagramCanvas, + bpmnModel.getGraphicInfo(flowNode.getId())); + } else { + drawHighLightNow((CustomProcessDiagramCanvas) processDiagramCanvas, + bpmnModel.getGraphicInfo(flowNode.getId())); + } + } else { + drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId())); + } + + } + + } + + // Outgoing transitions of activity + for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) { + boolean highLighted = (highLightedFlows.contains(sequenceFlow.getId())); + String defaultFlow = null; + if (flowNode instanceof Activity) { + defaultFlow = ((Activity) flowNode).getDefaultFlow(); + } else if (flowNode instanceof Gateway) { + defaultFlow = ((Gateway) flowNode).getDefaultFlow(); + } + + boolean isDefault = false; + if (defaultFlow != null && defaultFlow.equalsIgnoreCase(sequenceFlow.getId())) { + isDefault = true; + } + boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null + && !(flowNode instanceof Gateway); + + String sourceRef = sequenceFlow.getSourceRef(); + String targetRef = sequenceFlow.getTargetRef(); + FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef); + FlowElement targetElement = bpmnModel.getFlowElement(targetRef); + java.util.List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId()); + if (graphicInfoList != null && graphicInfoList.size() > 0) { + graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, + targetElement, graphicInfoList); + int xPoints[] = new int[graphicInfoList.size()]; + int yPoints[] = new int[graphicInfoList.size()]; + + for (int i = 1; i < graphicInfoList.size(); i++) { + GraphicInfo graphicInfo = graphicInfoList.get(i); + GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1); + + if (i == 1) { + xPoints[0] = (int) previousGraphicInfo.getX(); + yPoints[0] = (int) previousGraphicInfo.getY(); + } + xPoints[i] = (int) graphicInfo.getX(); + yPoints[i] = (int) graphicInfo.getY(); + + } + + processDiagramCanvas.drawSequenceflow(xPoints, yPoints, drawConditionalIndicator, isDefault, + highLighted, scaleFactor); + + // Draw sequenceflow label + GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId()); + if (labelGraphicInfo != null) { + processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false); + } else { + if (drawSequenceFlowNameWithNoLabelDI) { + GraphicInfo lineCenter = getLineCenter(graphicInfoList); + processDiagramCanvas.drawLabel(sequenceFlow.getName(), lineCenter, false); + } + + } + } + } + + // Nested elements + if (flowNode instanceof FlowElementsContainer) { + for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) { + if (nestedFlowElement instanceof FlowNode + && !isPartOfCollapsedSubProcess(nestedFlowElement, bpmnModel)) { + drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement, + highLightedActivities, highLightedFlows, scaleFactor, drawSequenceFlowNameWithNoLabelDI); + } + } + } + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/flow/FindNextNodeUtil.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/flow/FindNextNodeUtil.java new file mode 100644 index 0000000..4573b71 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/flow/FindNextNodeUtil.java @@ -0,0 +1,286 @@ +package com.boyue.flowable.flow; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.CallActivity; +import org.flowable.bpmn.model.EndEvent; +import org.flowable.bpmn.model.ExclusiveGateway; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.Gateway; +import org.flowable.bpmn.model.ParallelGateway; +//import com.greenpineyu.fel.FelEngine; +//import com.greenpineyu.fel.FelEngineImpl; +//import com.greenpineyu.fel.context.FelContext; +//import org.apache.commons.jexl2.JexlContext; +//import org.apache.commons.jexl2.JexlEngine; +//import org.apache.commons.jexl2.MapContext; +//import org.apache.commons.lang3.StringUtils; +import org.flowable.bpmn.model.Process; +import org.flowable.bpmn.model.ReceiveTask; +import org.flowable.bpmn.model.SequenceFlow; +import org.flowable.bpmn.model.ServiceTask; +import org.flowable.bpmn.model.StartEvent; +import org.flowable.bpmn.model.SubProcess; +import org.flowable.bpmn.model.Task; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.repository.ProcessDefinition; + +import com.googlecode.aviator.AviatorEvaluator; +import com.googlecode.aviator.Expression; + +/** + * @author Tony + * @date 2021/4/19 20:51 + */ +public class FindNextNodeUtil { + + /** + * 获取下一步骤的用户任务 + * + * @param repositoryService + * @param map + * @return + */ + public static List getNextUserTasks(RepositoryService repositoryService, org.flowable.task.api.Task task, + Map map) { + List data = new ArrayList<>(); + ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() + .processDefinitionId(task.getProcessDefinitionId()).singleResult(); + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); + Process mainProcess = bpmnModel.getMainProcess(); + Collection flowElements = mainProcess.getFlowElements(); + String key = task.getTaskDefinitionKey(); + FlowElement flowElement = bpmnModel.getFlowElement(key); + next(flowElements, flowElement, map, data); + return data; + } + + /** + * 启动流程时获取下一步骤的用户任务 + * + * @param repositoryService + * @param map + * @return + */ + public static List getNextUserTasksByStart(RepositoryService repositoryService, + ProcessDefinition processDefinition, Map map) { + List data = new ArrayList<>(); + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); + Process mainProcess = bpmnModel.getMainProcess(); + Collection flowElements = mainProcess.getFlowElements(); + String key = null; + // 找到开始节点 并获取唯一key + for (FlowElement flowElement : flowElements) { + if (flowElement instanceof StartEvent) { + key = flowElement.getId(); + break; + } + } + FlowElement flowElement = bpmnModel.getFlowElement(key); + List sequenceFlows = ((StartEvent) flowElement).getOutgoingFlows(); + // 获取出口连线, 此时从开始节点往后,只能是一个出口 + if (!sequenceFlows.isEmpty()) { + SequenceFlow sequenceFlow = sequenceFlows.get(0); + FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement(); + next(flowElements, targetFlowElement, map, data); + } + return data; + } + + /** + * 查找下一节点 + * + * @param flowElements + * @param flowElement + * @param map + * @param nextUser + */ + public static void next(Collection flowElements, FlowElement flowElement, Map map, + List nextUser) { + // 如果是结束节点 + if (flowElement instanceof EndEvent) { + // 如果是子任务的结束节点 + if (getSubProcess(flowElements, flowElement) != null) { + flowElement = getSubProcess(flowElements, flowElement); + } + } + // 获取Task的出线信息--可以拥有多个 + List outGoingFlows = null; + if (flowElement instanceof Task) { + outGoingFlows = ((Task) flowElement).getOutgoingFlows(); + } else if (flowElement instanceof Gateway) { + outGoingFlows = ((Gateway) flowElement).getOutgoingFlows(); + } else if (flowElement instanceof StartEvent) { + outGoingFlows = ((StartEvent) flowElement).getOutgoingFlows(); + } else if (flowElement instanceof SubProcess) { + outGoingFlows = ((SubProcess) flowElement).getOutgoingFlows(); + } else if (flowElement instanceof CallActivity) { + outGoingFlows = ((CallActivity) flowElement).getOutgoingFlows(); + } + if (outGoingFlows != null && outGoingFlows.size() > 0) { + // 遍历所有的出线--找到可以正确执行的那一条 + for (SequenceFlow sequenceFlow : outGoingFlows) { + // 1.有表达式,且为true + // 2.无表达式 + String expression = sequenceFlow.getConditionExpression(); + if (expression == null || + expressionResult(map, + expression.substring(expression.lastIndexOf("{") + 1, expression.lastIndexOf("}")))) { + // 出线的下一节点 + String nextFlowElementID = sequenceFlow.getTargetRef(); + if (checkSubProcess(nextFlowElementID, flowElements, nextUser)) { + continue; + } + + // 查询下一节点的信息 + FlowElement nextFlowElement = getFlowElementById(nextFlowElementID, flowElements); + // 调用流程 + if (nextFlowElement instanceof CallActivity) { + CallActivity ca = (CallActivity) nextFlowElement; + if (ca.getLoopCharacteristics() != null) { + UserTask userTask = new UserTask(); + userTask.setId(ca.getId()); + + userTask.setId(ca.getId()); + userTask.setLoopCharacteristics(ca.getLoopCharacteristics()); + userTask.setName(ca.getName()); + nextUser.add(userTask); + } + next(flowElements, nextFlowElement, map, nextUser); + } + // 用户任务 + if (nextFlowElement instanceof UserTask) { + nextUser.add((UserTask) nextFlowElement); + } + // 排他网关 + else if (nextFlowElement instanceof ExclusiveGateway) { + next(flowElements, nextFlowElement, map, nextUser); + } + // 并行网关 + else if (nextFlowElement instanceof ParallelGateway) { + next(flowElements, nextFlowElement, map, nextUser); + } + // 接收任务 + else if (nextFlowElement instanceof ReceiveTask) { + next(flowElements, nextFlowElement, map, nextUser); + } + // 服务任务 + else if (nextFlowElement instanceof ServiceTask) { + next(flowElements, nextFlowElement, map, nextUser); + } + // 子任务的起点 + else if (nextFlowElement instanceof StartEvent) { + next(flowElements, nextFlowElement, map, nextUser); + } + // 结束节点 + else if (nextFlowElement instanceof EndEvent) { + next(flowElements, nextFlowElement, map, nextUser); + } + } + } + } + } + + /** + * 判断是否是多实例子流程并且需要设置集合类型变量 + */ + public static boolean checkSubProcess(String id, Collection flowElements, List nextUser) { + for (FlowElement flowElement1 : flowElements) { + if (flowElement1 instanceof SubProcess && flowElement1.getId().equals(id)) { + + SubProcess sp = (SubProcess) flowElement1; + if (sp.getLoopCharacteristics() != null) { + // String inputDataItem = sp.getLoopCharacteristics().getInputDataItem(); + UserTask userTask = new UserTask(); + userTask.setId(sp.getId()); + userTask.setLoopCharacteristics(sp.getLoopCharacteristics()); + userTask.setName(sp.getName()); + nextUser.add(userTask); + return true; + } + } + } + + return false; + + } + + /** + * 查询一个节点的是否子任务中的节点,如果是,返回子任务 + * + * @param flowElements 全流程的节点集合 + * @param flowElement 当前节点 + * @return + */ + public static FlowElement getSubProcess(Collection flowElements, FlowElement flowElement) { + for (FlowElement flowElement1 : flowElements) { + if (flowElement1 instanceof SubProcess) { + for (FlowElement flowElement2 : ((SubProcess) flowElement1).getFlowElements()) { + if (flowElement.equals(flowElement2)) { + return flowElement1; + } + } + } + } + return null; + } + + /** + * 根据ID查询流程节点对象, 如果是子任务,则返回子任务的开始节点 + * + * @param Id 节点ID + * @param flowElements 流程节点集合 + * @return + */ + public static FlowElement getFlowElementById(String Id, Collection flowElements) { + for (FlowElement flowElement : flowElements) { + if (flowElement.getId().equals(Id)) { + // 如果是子任务,则查询出子任务的开始节点 + if (flowElement instanceof SubProcess) { + return getStartFlowElement(((SubProcess) flowElement).getFlowElements()); + } + return flowElement; + } + if (flowElement instanceof SubProcess) { + FlowElement flowElement1 = getFlowElementById(Id, ((SubProcess) flowElement).getFlowElements()); + if (flowElement1 != null) { + return flowElement1; + } + } + } + return null; + } + + /** + * 返回流程的开始节点 + * + * @param flowElements 节点集合 + * @description: + */ + public static FlowElement getStartFlowElement(Collection flowElements) { + for (FlowElement flowElement : flowElements) { + if (flowElement instanceof StartEvent) { + return flowElement; + } + } + return null; + } + + /** + * 校验el表达式 + * + * @param map + * @param expression + * @return + */ + public static boolean expressionResult(Map map, String expression) { + Expression exp = AviatorEvaluator.compile(expression); + return (Boolean) exp.execute(map); + // return true; + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/flow/FlowableUtils.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/flow/FlowableUtils.java new file mode 100644 index 0000000..2dffa43 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/flow/FlowableUtils.java @@ -0,0 +1,772 @@ +package com.boyue.flowable.flow; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.Stack; +import java.util.stream.Collectors; + +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.EndEvent; +import org.flowable.bpmn.model.ExtensionAttribute; +import org.flowable.bpmn.model.ExtensionElement; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.FlowNode; +import org.flowable.bpmn.model.Gateway; +import org.flowable.bpmn.model.SequenceFlow; +import org.flowable.bpmn.model.StartEvent; +import org.flowable.bpmn.model.SubProcess; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; +import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.task.api.history.HistoricTaskInstance; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author Tony + * @date 2021-04-03 23:57 + */ +@Slf4j +public class FlowableUtils { + + /** + * 根据节点,获取入口连线 + * + * @param source + * @return + */ + public static List getElementIncomingFlows(FlowElement source) { + List sequenceFlows = null; + if (source instanceof FlowNode) { + sequenceFlows = ((FlowNode) source).getIncomingFlows(); + } else if (source instanceof Gateway) { + sequenceFlows = ((Gateway) source).getIncomingFlows(); + } else if (source instanceof SubProcess) { + sequenceFlows = ((SubProcess) source).getIncomingFlows(); + } else if (source instanceof StartEvent) { + sequenceFlows = ((StartEvent) source).getIncomingFlows(); + } else if (source instanceof EndEvent) { + sequenceFlows = ((EndEvent) source).getIncomingFlows(); + } + return sequenceFlows; + } + + /** + * 根据节点,获取出口连线 + * + * @param source + * @return + */ + public static List getElementOutgoingFlows(FlowElement source) { + List sequenceFlows = null; + if (source instanceof FlowNode) { + sequenceFlows = ((FlowNode) source).getOutgoingFlows(); + } else if (source instanceof Gateway) { + sequenceFlows = ((Gateway) source).getOutgoingFlows(); + } else if (source instanceof SubProcess) { + sequenceFlows = ((SubProcess) source).getOutgoingFlows(); + } else if (source instanceof StartEvent) { + sequenceFlows = ((StartEvent) source).getOutgoingFlows(); + } else if (source instanceof EndEvent) { + sequenceFlows = ((EndEvent) source).getOutgoingFlows(); + } + return sequenceFlows; + } + + /** + * 获取全部节点列表,包含子流程节点 + * + * @param flowElements + * @param allElements + * @return + */ + public static Collection getAllElements(Collection flowElements, + Collection allElements) { + allElements = allElements == null ? new ArrayList<>() : allElements; + + for (FlowElement flowElement : flowElements) { + allElements.add(flowElement); + if (flowElement instanceof SubProcess) { + // 继续深入子流程,进一步获取子流程 + allElements = FlowableUtils.getAllElements(((SubProcess) flowElement).getFlowElements(), allElements); + } + } + return allElements; + } + + /** + * 迭代获取父级任务节点列表,向前找 + * + * @param source 起始节点 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param userTaskList 已找到的用户任务节点 + * @return + */ + public static List iteratorFindParentUserTasks(FlowElement source, Set hasSequenceFlow, + List userTaskList) { + userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 + if (source instanceof StartEvent && source.getSubProcess() != null) { + userTaskList = iteratorFindParentUserTasks(source.getSubProcess(), hasSequenceFlow, userTaskList); + } + + // 根据类型,获取入口连线 + List sequenceFlows = getElementIncomingFlows(source); + + if (sequenceFlows != null) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 类型为用户节点,则新增父级节点 + if (sequenceFlow.getSourceFlowElement() instanceof UserTask) { + userTaskList.add((UserTask) sequenceFlow.getSourceFlowElement()); + continue; + } + // 类型为子流程,则添加子流程开始节点出口处相连的节点 + if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) { + // 获取子流程用户任务节点 + List childUserTaskList = findChildProcessUserTasks( + (StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements() + .toArray()[0], + null, null); + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续 + if (childUserTaskList != null && childUserTaskList.size() > 0) { + userTaskList.addAll(childUserTaskList); + continue; + } + } + // 继续迭代 + userTaskList = iteratorFindParentUserTasks(sequenceFlow.getSourceFlowElement(), hasSequenceFlow, + userTaskList); + } + } + return userTaskList; + } + + /** + * 根据正在运行的任务节点,迭代获取子级任务节点列表,向后找 + * + * @param source 起始节点(退回节点) + * @param runTaskKeyList 正在运行的任务 Key,用于校验任务节点是否是正在运行的节点 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param userTaskList 需要撤回的用户任务列表 + * @return + */ + public static List iteratorFindChildUserTasks(FlowElement source, List runTaskKeyList, + Set hasSequenceFlow, List userTaskList) { + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; + + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 + if (source instanceof EndEvent && source.getSubProcess() != null) { + userTaskList = iteratorFindChildUserTasks(source.getSubProcess(), runTaskKeyList, hasSequenceFlow, + userTaskList); + } + + // 根据类型,获取出口连线 + List sequenceFlows = getElementOutgoingFlows(source); + + if (sequenceFlows != null) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加 + if (sequenceFlow.getTargetFlowElement() instanceof UserTask + && runTaskKeyList.contains((sequenceFlow.getTargetFlowElement()).getId())) { + userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement()); + continue; + } + // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取 + if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { + List childUserTaskList = iteratorFindChildUserTasks( + (FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements() + .toArray()[0]), + runTaskKeyList, hasSequenceFlow, null); + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续 + if (childUserTaskList != null && childUserTaskList.size() > 0) { + userTaskList.addAll(childUserTaskList); + continue; + } + } + // 继续迭代 + userTaskList = iteratorFindChildUserTasks(sequenceFlow.getTargetFlowElement(), runTaskKeyList, + hasSequenceFlow, userTaskList); + } + } + return userTaskList; + } + + /** + * 迭代获取子流程用户任务节点 + * + * @param source 起始节点 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param userTaskList 需要撤回的用户任务列表 + * @return + */ + public static List findChildProcessUserTasks(FlowElement source, Set hasSequenceFlow, + List userTaskList) { + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; + + // 根据类型,获取出口连线 + List sequenceFlows = getElementOutgoingFlows(source); + + if (sequenceFlows != null) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加 + if (sequenceFlow.getTargetFlowElement() instanceof UserTask) { + userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement()); + continue; + } + // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取 + if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { + List childUserTaskList = findChildProcessUserTasks( + (FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements() + .toArray()[0]), + hasSequenceFlow, null); + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续 + if (childUserTaskList != null && childUserTaskList.size() > 0) { + userTaskList.addAll(childUserTaskList); + continue; + } + } + // 继续迭代 + userTaskList = findChildProcessUserTasks(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, + userTaskList); + } + } + return userTaskList; + } + + /** + * 从后向前寻路,获取所有脏线路上的点 + * + * @param source 起始节点 + * @param passRoads 已经经过的点集合 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param targets 目标脏线路终点 + * @param dirtyRoads 确定为脏数据的点,因为不需要重复,因此使用 set 存储 + * @return + */ + public static Set iteratorFindDirtyRoads(FlowElement source, List passRoads, + Set hasSequenceFlow, List targets, Set dirtyRoads) { + passRoads = passRoads == null ? new ArrayList<>() : passRoads; + dirtyRoads = dirtyRoads == null ? new HashSet<>() : dirtyRoads; + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 + if (source instanceof StartEvent && source.getSubProcess() != null) { + dirtyRoads = iteratorFindDirtyRoads(source.getSubProcess(), passRoads, hasSequenceFlow, targets, + dirtyRoads); + } + + // 根据类型,获取入口连线 + List sequenceFlows = getElementIncomingFlows(source); + + if (sequenceFlows != null) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 新增经过的路线 + passRoads.add(sequenceFlow.getSourceFlowElement().getId()); + // 如果此点为目标点,确定经过的路线为脏线路,添加点到脏线路中,然后找下个连线 + if (targets.contains(sequenceFlow.getSourceFlowElement().getId())) { + dirtyRoads.addAll(passRoads); + continue; + } + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 + if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) { + dirtyRoads = findChildProcessAllDirtyRoad( + (StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements() + .toArray()[0], + null, dirtyRoads); + // 是否存在子流程上,true 是,false 否 + Boolean isInChildProcess = dirtyTargetInChildProcess( + (StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements() + .toArray()[0], + null, targets, null); + if (isInChildProcess) { + // 已在子流程上找到,该路线结束 + continue; + } + } + // 继续迭代 + dirtyRoads = iteratorFindDirtyRoads(sequenceFlow.getSourceFlowElement(), passRoads, hasSequenceFlow, + targets, dirtyRoads); + } + } + return dirtyRoads; + } + + /** + * 迭代获取子流程脏路线 + * 说明,假如回退的点就是子流程,那么也肯定会回退到子流程最初的用户任务节点,因此子流程中的节点全是脏路线 + * + * @param source 起始节点 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param dirtyRoads 确定为脏数据的点,因为不需要重复,因此使用 set 存储 + * @return + */ + public static Set findChildProcessAllDirtyRoad(FlowElement source, Set hasSequenceFlow, + Set dirtyRoads) { + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + dirtyRoads = dirtyRoads == null ? new HashSet<>() : dirtyRoads; + + // 根据类型,获取出口连线 + List sequenceFlows = getElementOutgoingFlows(source); + + if (sequenceFlows != null) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 添加脏路线 + dirtyRoads.add(sequenceFlow.getTargetFlowElement().getId()); + // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取 + if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { + dirtyRoads = findChildProcessAllDirtyRoad( + (FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements() + .toArray()[0]), + hasSequenceFlow, dirtyRoads); + } + // 继续迭代 + dirtyRoads = findChildProcessAllDirtyRoad(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, + dirtyRoads); + } + } + return dirtyRoads; + } + + /** + * 判断脏路线结束节点是否在子流程上 + * + * @param source 起始节点 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param targets 判断脏路线节点是否存在子流程上,只要存在一个,说明脏路线只到子流程为止 + * @param inChildProcess 是否存在子流程上,true 是,false 否 + * @return + */ + public static Boolean dirtyTargetInChildProcess(FlowElement source, Set hasSequenceFlow, + List targets, Boolean inChildProcess) { + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + inChildProcess = inChildProcess != null && inChildProcess; + + // 根据类型,获取出口连线 + List sequenceFlows = getElementOutgoingFlows(source); + + if (sequenceFlows != null && !inChildProcess) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 如果发现目标点在子流程上存在,说明只到子流程为止 + if (targets.contains(sequenceFlow.getTargetFlowElement().getId())) { + inChildProcess = true; + break; + } + // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取 + if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { + inChildProcess = dirtyTargetInChildProcess( + (FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements() + .toArray()[0]), + hasSequenceFlow, targets, inChildProcess); + } + // 继续迭代 + inChildProcess = dirtyTargetInChildProcess(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, + targets, inChildProcess); + } + } + return inChildProcess; + } + + /** + * 迭代从后向前扫描,判断目标节点相对于当前节点是否是串行 + * 不存在直接回退到子流程中的情况,但存在从子流程出去到父流程情况 + * + * @param source 起始节点 + * @param isSequential 是否串行 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param targetKsy 目标节点 + * @return + */ + public static Boolean iteratorCheckSequentialReferTarget(FlowElement source, String targetKsy, + Set hasSequenceFlow, Boolean isSequential) { + isSequential = isSequential == null || isSequential; + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 + if (source instanceof StartEvent && source.getSubProcess() != null) { + isSequential = iteratorCheckSequentialReferTarget(source.getSubProcess(), targetKsy, hasSequenceFlow, + isSequential); + } + + // 根据类型,获取入口连线 + List sequenceFlows = getElementIncomingFlows(source); + + if (sequenceFlows != null) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 如果目标节点已被判断为并行,后面都不需要执行,直接返回 + if (!isSequential) { + break; + } + // 这条线路存在目标节点,这条线路完成,进入下个线路 + if (targetKsy.equals(sequenceFlow.getSourceFlowElement().getId())) { + continue; + } + if (sequenceFlow.getSourceFlowElement() instanceof StartEvent) { + isSequential = false; + break; + } + // 否则就继续迭代 + isSequential = iteratorCheckSequentialReferTarget(sequenceFlow.getSourceFlowElement(), targetKsy, + hasSequenceFlow, isSequential); + } + } + return isSequential; + } + + /** + * 从后向前寻路,获取到达节点的所有路线 + * 不存在直接回退到子流程,但是存在回退到父级流程的情况 + * + * @param source 起始节点 + * @param passRoads 已经经过的点集合 + * @param roads 路线 + * @return + */ + public static List> findRoad(FlowElement source, List passRoads, + Set hasSequenceFlow, List> roads) { + passRoads = passRoads == null ? new ArrayList<>() : passRoads; + roads = roads == null ? new ArrayList<>() : roads; + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 + if (source instanceof StartEvent && source.getSubProcess() != null) { + roads = findRoad(source.getSubProcess(), passRoads, hasSequenceFlow, roads); + } + + // 根据类型,获取入口连线 + List sequenceFlows = getElementIncomingFlows(source); + + if (sequenceFlows != null && sequenceFlows.size() != 0) { + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 添加经过路线 + if (sequenceFlow.getSourceFlowElement() instanceof UserTask) { + passRoads.add((UserTask) sequenceFlow.getSourceFlowElement()); + } + // 继续迭代 + roads = findRoad(sequenceFlow.getSourceFlowElement(), passRoads, hasSequenceFlow, roads); + } + } else { + // 添加路线 + roads.add(passRoads); + } + return roads; + } + + /** + * 历史节点数据清洗,清洗掉又回滚导致的脏数据 + * + * @param allElements 全部节点信息 + * @param historicTaskInstanceList 历史任务实例信息,数据采用开始时间升序 + * @return + */ + public static List historicTaskInstanceClean(Collection allElements, + List historicTaskInstanceList) { + // 会签节点收集 + List multiTask = new ArrayList<>(); + allElements.forEach(flowElement -> { + if (flowElement instanceof UserTask) { + // 如果该节点的行为为会签行为,说明该节点为会签节点 + if (((UserTask) flowElement).getBehavior() instanceof ParallelMultiInstanceBehavior + || ((UserTask) flowElement).getBehavior() instanceof SequentialMultiInstanceBehavior) { + multiTask.add(flowElement.getId()); + } + } + }); + // 循环放入栈,栈 LIFO:后进先出 + Stack stack = new Stack<>(); + historicTaskInstanceList.forEach(stack::push); + // 清洗后的历史任务实例 + List lastHistoricTaskInstanceList = new ArrayList<>(); + // 网关存在可能只走了部分分支情况,且还存在跳转废弃数据以及其他分支数据的干扰,因此需要对历史节点数据进行清洗 + // 临时用户任务 key + StringBuilder userTaskKey = null; + // 临时被删掉的任务 key,存在并行情况 + List deleteKeyList = new ArrayList<>(); + // 临时脏数据线路 + List> dirtyDataLineList = new ArrayList<>(); + // 由某个点跳到会签点,此时出现多个会签实例对应 1 个跳转情况,需要把这些连续脏数据都找到 + // 会签特殊处理下标 + int multiIndex = -1; + // 会签特殊处理 key + StringBuilder multiKey = null; + // 会签特殊处理操作标识 + boolean multiOpera = false; + while (!stack.empty()) { + // 从这里开始 userTaskKey 都还是上个栈的 key + // 是否是脏数据线路上的点 + final boolean[] isDirtyData = { false }; + for (Set oldDirtyDataLine : dirtyDataLineList) { + if (oldDirtyDataLine.contains(stack.peek().getTaskDefinitionKey())) { + isDirtyData[0] = true; + } + } + // 删除原因不为空,说明从这条数据开始回跳或者回退的 + // MI_END:会签完成后,其他未签到节点的删除原因,不在处理范围内 + if (stack.peek().getDeleteReason() != null && !"MI_END".equals(stack.peek().getDeleteReason())) { + // 可以理解为脏线路起点 + String dirtyPoint = ""; + if (stack.peek().getDeleteReason().contains("Change activity to ")) { + dirtyPoint = stack.peek().getDeleteReason().replace("Change activity to ", ""); + } + // 会签回退删除原因有点不同 + if (stack.peek().getDeleteReason().contains("Change parent activity to ")) { + dirtyPoint = stack.peek().getDeleteReason().replace("Change parent activity to ", ""); + } + FlowElement dirtyTask = null; + // 获取变更节点的对应的入口处连线 + // 如果是网关并行回退情况,会变成两条脏数据路线,效果一样 + for (FlowElement flowElement : allElements) { + if (flowElement.getId().equals(stack.peek().getTaskDefinitionKey())) { + dirtyTask = flowElement; + } + } + // 获取脏数据线路 + Set dirtyDataLine = FlowableUtils.iteratorFindDirtyRoads(dirtyTask, null, null, + Arrays.asList(dirtyPoint.split(",")), null); + // 自己本身也是脏线路上的点,加进去 + dirtyDataLine.add(stack.peek().getTaskDefinitionKey()); + log.info(stack.peek().getTaskDefinitionKey() + "点脏路线集合:" + dirtyDataLine); + // 是全新的需要添加的脏线路 + boolean isNewDirtyData = true; + for (int i = 0; i < dirtyDataLineList.size(); i++) { + // 如果发现他的上个节点在脏线路内,说明这个点可能是并行的节点,或者连续驳回 + // 这时,都以之前的脏线路节点为标准,只需合并脏线路即可,也就是路线补全 + if (dirtyDataLineList.get(i).contains(userTaskKey.toString())) { + isNewDirtyData = false; + dirtyDataLineList.get(i).addAll(dirtyDataLine); + } + } + // 已确定时全新的脏线路 + if (isNewDirtyData) { + // deleteKey 单一路线驳回到并行,这种同时生成多个新实例记录情况,这时 deleteKey 其实是由多个值组成 + // 按照逻辑,回退后立刻生成的实例记录就是回退的记录 + // 至于驳回所生成的 Key,直接从删除原因中获取,因为存在驳回到并行的情况 + deleteKeyList.add(dirtyPoint + ","); + dirtyDataLineList.add(dirtyDataLine); + } + // 添加后,现在这个点变成脏线路上的点了 + isDirtyData[0] = true; + } + // 如果不是脏线路上的点,说明是有效数据,添加历史实例 Key + if (!isDirtyData[0]) { + lastHistoricTaskInstanceList.add(stack.peek().getTaskDefinitionKey()); + } + // 校验脏线路是否结束 + for (int i = 0; i < deleteKeyList.size(); i++) { + // 如果发现脏数据属于会签,记录下下标与对应 Key,以备后续比对,会签脏数据范畴开始 + if (multiKey == null && multiTask.contains(stack.peek().getTaskDefinitionKey()) + && deleteKeyList.get(i).contains(stack.peek().getTaskDefinitionKey())) { + multiIndex = i; + multiKey = new StringBuilder(stack.peek().getTaskDefinitionKey()); + } + // 会签脏数据处理,节点退回会签清空 + // 如果在会签脏数据范畴中发现 Key改变,说明会签脏数据在上个节点就结束了,可以把会签脏数据删掉 + if (multiKey != null && !multiKey.toString().equals(stack.peek().getTaskDefinitionKey())) { + deleteKeyList.set(multiIndex, + deleteKeyList.get(multiIndex).replace(stack.peek().getTaskDefinitionKey() + ",", "")); + multiKey = null; + // 结束进行下校验删除 + multiOpera = true; + } + // 其他脏数据处理 + // 发现该路线最后一条脏数据,说明这条脏数据线路处理完了,删除脏数据信息 + // 脏数据产生的新实例中是否包含这条数据 + if (multiKey == null && deleteKeyList.get(i).contains(stack.peek().getTaskDefinitionKey())) { + // 删除匹配到的部分 + deleteKeyList.set(i, deleteKeyList.get(i).replace(stack.peek().getTaskDefinitionKey() + ",", "")); + } + // 如果每组中的元素都以匹配过,说明脏数据结束 + if ("".equals(deleteKeyList.get(i))) { + // 同时删除脏数据 + deleteKeyList.remove(i); + dirtyDataLineList.remove(i); + break; + } + } + // 会签数据处理需要在循环外处理,否则可能导致溢出 + // 会签的数据肯定是之前放进去的所以理论上不会溢出,但还是校验下 + if (multiOpera && deleteKeyList.size() > multiIndex && "".equals(deleteKeyList.get(multiIndex))) { + // 同时删除脏数据 + deleteKeyList.remove(multiIndex); + dirtyDataLineList.remove(multiIndex); + multiIndex = -1; + multiOpera = false; + } + // pop() 方法与 peek() 方法不同,在返回值的同时,会把值从栈中移除 + // 保存新的 userTaskKey 在下个循环中使用 + userTaskKey = new StringBuilder(stack.pop().getTaskDefinitionKey()); + } + log.info("清洗后的历史节点数据:" + lastHistoricTaskInstanceList); + return lastHistoricTaskInstanceList; + } + + /** + * 从 flowElement 获取 指定名称的 拓展元素 + * + * @param flowElement 元素 + * @param extensionElementName 拓展元素名称 + */ + public static ExtensionElement getExtensionElementFromFlowElementByName(FlowElement flowElement, + String extensionElementName) { + + if (flowElement == null) { + return null; + } + Map> extensionElements = flowElement.getExtensionElements(); + for (Map.Entry> stringEntry : extensionElements.entrySet()) { + if (stringEntry.getKey().equals(extensionElementName)) { + for (ExtensionElement extensionElement : stringEntry.getValue()) { + if (extensionElement.getName().equals(extensionElementName)) { + return extensionElement; + } + } + } + } + + return null; + } + + /** + * 获取当前任务节点扩展属性信息 + * + * @param repositoryService + * @param task 当前任务 + * @return 自定义属性列表 + */ + public static List getPropertyElement(RepositoryService repositoryService, + org.flowable.task.api.Task task) { + FlowElement flowElement = getCurrentElement(repositoryService, task); + ExtensionElement extensionElement = FlowableUtils.getExtensionElementFromFlowElementByName(flowElement, + "properties"); + if (extensionElement == null) { + return Collections.emptyList(); + } + return getPropertyExtensionElementByName(extensionElement, "property"); + } + + /** + * 获取当前任务节点 + * + * @param repositoryService + * @param task + * @return + */ + public static FlowElement getCurrentElement(RepositoryService repositoryService, org.flowable.task.api.Task task) { + ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() + .processDefinitionId(task.getProcessDefinitionId()).singleResult(); + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); + return bpmnModel.getFlowElement(task.getTaskDefinitionKey()); + } + + /** + * 根据属性名获取扩展元素中的扩展属性列表 + * + * @param extensionElement 扩展元素 + * @param attributesName 属性名 + * @return 扩展属性列表 + */ + public static List getPropertyExtensionElementByName(ExtensionElement extensionElement, + String attributesName) { + try { + // 获取名称为attributesName的子元素 + return Optional.ofNullable(extensionElement.getChildElements().get(attributesName)) + .orElse(Collections.emptyList()) // 如果子元素不存在则返回空集合,避免null引用 + .stream() + .map(element -> { + // 获取子元素的属性 + Map> attributes = element.getAttributes(); + Object propertyDto = new Object(); + // 获取FlowPropertyDto的所有属性 + Arrays.stream(propertyDto.getClass().getDeclaredFields()) + .forEach(field -> { + field.setAccessible(true); + // 获取属性名称和值 + attributes.getOrDefault(field.getName(), Collections.emptyList()) + .stream() + .findFirst() + .ifPresent(attribute -> { + try { + // 反射设置属性值 + field.set(propertyDto, attribute.getValue()); + } catch (IllegalAccessException e) { + e.printStackTrace(); + // 如果反射设置失败则忽略该属性 + } + }); + }); + return propertyDto; + }).collect(Collectors.toList()); + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyList(); // 如果发生异常则返回空列表 + } + } + +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/listener/FlowExecutionListener.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/listener/FlowExecutionListener.java new file mode 100644 index 0000000..c2af02d --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/listener/FlowExecutionListener.java @@ -0,0 +1,37 @@ +package com.boyue.flowable.listener; + +import org.flowable.common.engine.api.delegate.Expression; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.ExecutionListener; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +/** + * 执行监听器 + * + * 执行监听器允许在执行过程中执行Java代码。 + * 执行监听器可以捕获事件的类型: + * 流程实例启动,结束 + * 输出流捕获 + * 获取启动,结束 + * 路由开始,结束 + * 中间事件开始,结束 + * 触发开始事件,触发结束事件 + * + * @author Tony + * @date 2022/12/16 + */ +@Slf4j +@Component +public class FlowExecutionListener implements ExecutionListener { + /** + * 流程设计器添加的参数 + */ + private Expression param; + + @Override + public void notify(DelegateExecution execution) { + log.info("执行监听器:{},参数:{}", execution, param); + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/listener/FlowTaskListener.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/listener/FlowTaskListener.java new file mode 100644 index 0000000..815c9b8 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/listener/FlowTaskListener.java @@ -0,0 +1,38 @@ +package com.boyue.flowable.listener; + +import org.flowable.common.engine.api.delegate.Expression; +import org.flowable.engine.delegate.TaskListener; +import org.flowable.task.service.delegate.DelegateTask; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +/** + * 任务监听器 + * + * create(创建):在任务被创建且所有的任务属性设置完成后才触发 + * assignment(指派):在任务被分配给某个办理人之后触发 + * complete(完成):在配置了监听器的上一个任务完成时触发 + * delete(删除):在任务即将被删除前触发。请注意任务由completeTask正常完成时也会触发 + * + * @author Tony + * @date 2021/4/20 + */ +@Slf4j +@Component +public class FlowTaskListener implements TaskListener { + + /** + * 流程设计器添加的参数 + */ + private Expression param; + + @Override + public void notify(DelegateTask delegateTask) { + + // 获取事件类型 delegateTask.getEventName(),可以通过监听器给任务执行人发送相应的通知消息 + log.info("任务监听器:{}", delegateTask, param.getValue(delegateTask)); + + } + +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/mapper/FlowDeployMapper.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/mapper/FlowDeployMapper.java new file mode 100644 index 0000000..f383399 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/mapper/FlowDeployMapper.java @@ -0,0 +1,23 @@ +package com.boyue.flowable.mapper; + +import java.util.List; + +import com.boyue.flowable.domain.dto.FlowProcDefDto; + +/** + * 流程定义查询 + * + * @author Tony + * @email + * @date 2022/1/29 5:44 下午 + **/ +public interface FlowDeployMapper { + + /** + * 流程定义列表 + * + * @param name + * @return + */ + List selectDeployList(String name); +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/mapper/SysDeployFormMapper.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/mapper/SysDeployFormMapper.java new file mode 100644 index 0000000..5284636 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/mapper/SysDeployFormMapper.java @@ -0,0 +1,74 @@ +package com.boyue.flowable.mapper; + + + +import java.util.List; + +import com.boyue.flowable.domain.SysDeployForm; +import com.boyue.form.domain.FormTemplate; + +/** + * 流程实例关联表单Mapper接口 + * + * @author Tony + * @date 2021-03-30 + */ +public interface SysDeployFormMapper +{ + /** + * 查询流程实例关联表单 + * + * @param id 流程实例关联表单ID + * @return 流程实例关联表单 + */ + public SysDeployForm selectSysDeployFormById(Long id); + + /** + * 查询流程实例关联表单列表 + * + * @param SysDeployForm 流程实例关联表单 + * @return 流程实例关联表单集合 + */ + public List selectSysDeployFormList(SysDeployForm SysDeployForm); + + /** + * 新增流程实例关联表单 + * + * @param SysDeployForm 流程实例关联表单 + * @return 结果 + */ + public int insertSysDeployForm(SysDeployForm SysDeployForm); + + /** + * 修改流程实例关联表单 + * + * @param SysDeployForm 流程实例关联表单 + * @return 结果 + */ + public int updateSysDeployForm(SysDeployForm SysDeployForm); + + /** + * 删除流程实例关联表单 + * + * @param id 流程实例关联表单ID + * @return 结果 + */ + public int deleteSysDeployFormById(Long id); + + /** + * 批量删除流程实例关联表单 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteSysDeployFormByIds(Long[] ids); + + + + /** + * 查询流程挂着的表单 + * @param deployId + * @return + */ + FormTemplate selectSysDeployFormByDeployId(String deployId); +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/mapper/SysExpressionMapper.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/mapper/SysExpressionMapper.java new file mode 100644 index 0000000..6b62199 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/mapper/SysExpressionMapper.java @@ -0,0 +1,63 @@ +package com.boyue.flowable.mapper; + +import java.util.List; + +import com.boyue.flowable.domain.SysExpression; + + +/** + * 流程达式Mapper接口 + * + * @author boyue + * @date 2022-12-12 + */ +public interface SysExpressionMapper +{ + /** + * 查询流程达式 + * + * @param id 流程达式主键 + * @return 流程达式 + */ + public SysExpression selectSysExpressionById(Long id); + + /** + * 查询流程达式列表 + * + * @param sysExpression 流程达式 + * @return 流程达式集合 + */ + public List selectSysExpressionList(SysExpression sysExpression); + + /** + * 新增流程达式 + * + * @param sysExpression 流程达式 + * @return 结果 + */ + public int insertSysExpression(SysExpression sysExpression); + + /** + * 修改流程达式 + * + * @param sysExpression 流程达式 + * @return 结果 + */ + public int updateSysExpression(SysExpression sysExpression); + + /** + * 删除流程达式 + * + * @param id 流程达式主键 + * @return 结果 + */ + public int deleteSysExpressionById(Long id); + + /** + * 批量删除流程达式 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteSysExpressionByIds(Long[] ids); +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/mapper/SysListenerMapper.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/mapper/SysListenerMapper.java new file mode 100644 index 0000000..19db979 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/mapper/SysListenerMapper.java @@ -0,0 +1,62 @@ +package com.boyue.flowable.mapper; + +import java.util.List; + +import com.boyue.flowable.domain.SysListener; + +/** + * 流程监听Mapper接口 + * + * @author Tony + * @date 2022-12-25 + */ +public interface SysListenerMapper +{ + /** + * 查询流程监听 + * + * @param id 流程监听主键 + * @return 流程监听 + */ + public SysListener selectSysListenerById(Long id); + + /** + * 查询流程监听列表 + * + * @param sysListener 流程监听 + * @return 流程监听集合 + */ + public List selectSysListenerList(SysListener sysListener); + + /** + * 新增流程监听 + * + * @param sysListener 流程监听 + * @return 结果 + */ + public int insertSysListener(SysListener sysListener); + + /** + * 修改流程监听 + * + * @param sysListener 流程监听 + * @return 结果 + */ + public int updateSysListener(SysListener sysListener); + + /** + * 删除流程监听 + * + * @param id 流程监听主键 + * @return 结果 + */ + public int deleteSysListenerById(Long id); + + /** + * 批量删除流程监听 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteSysListenerByIds(Long[] ids); +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/mapper/SysTaskFormMapper.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/mapper/SysTaskFormMapper.java new file mode 100644 index 0000000..ccd153a --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/mapper/SysTaskFormMapper.java @@ -0,0 +1,64 @@ +package com.boyue.flowable.mapper; + + + +import java.util.List; + +import com.boyue.flowable.domain.SysTaskForm; + +/** + * 流程任务关联单Mapper接口 + * + * @author Tony + * @date 2021-04-03 + */ +public interface SysTaskFormMapper +{ + /** + * 查询流程任务关联单 + * + * @param id 流程任务关联单ID + * @return 流程任务关联单 + */ + public SysTaskForm selectSysTaskFormById(Long id); + + /** + * 查询流程任务关联单列表 + * + * @param sysTaskForm 流程任务关联单 + * @return 流程任务关联单集合 + */ + public List selectSysTaskFormList(SysTaskForm sysTaskForm); + + /** + * 新增流程任务关联单 + * + * @param sysTaskForm 流程任务关联单 + * @return 结果 + */ + public int insertSysTaskForm(SysTaskForm sysTaskForm); + + /** + * 修改流程任务关联单 + * + * @param sysTaskForm 流程任务关联单 + * @return 结果 + */ + public int updateSysTaskForm(SysTaskForm sysTaskForm); + + /** + * 删除流程任务关联单 + * + * @param id 流程任务关联单ID + * @return 结果 + */ + public int deleteSysTaskFormById(Long id); + + /** + * 批量删除流程任务关联单 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteSysTaskFormByIds(Long[] ids); +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/IFlowDefinitionService.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/IFlowDefinitionService.java new file mode 100644 index 0000000..c9f40dc --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/IFlowDefinitionService.java @@ -0,0 +1,80 @@ +package com.boyue.flowable.service; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Map; + +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.flowable.domain.dto.FlowProcDefDto; + +/** + * @author Tony + * @date 2021-04-03 14:41 + */ +public interface IFlowDefinitionService { + + boolean exist(String processDefinitionKey); + + + /** + * 流程定义列表 + * + * @param pageNum 当前页码 + * @param pageSize 每页条数 + * @return 流程定义分页列表数据 + */ + List list(String name,Integer pageNum, Integer pageSize); + + /** + * 导入流程文件 + * 当每个key的流程第一次部署时,指定版本为1。对其后所有使用相同key的流程定义, + * 部署时版本会在该key当前已部署的最高版本号基础上加1。key参数用于区分流程定义 + * @param name + * @param category + * @param in + */ + void importFile(String name, String category, InputStream in); + + /** + * 读取xml + * @param deployId + * @return + */ + AjaxResult readXml(String deployId) throws IOException; + + /** + * 根据流程定义ID启动流程实例 + * + * @param procDefId + * @param variables + * @return + */ + + AjaxResult startProcessInstanceById(String procDefId, Map variables); + + + /** + * 激活或挂起流程定义 + * + * @param state 状态 + * @param deployId 流程部署ID + */ + void updateState(Integer state, String deployId); + + + /** + * 删除流程定义 + * + * @param deployId 流程部署ID act_ge_bytearray 表中 deployment_id值 + */ + void delete(String deployId); + + + /** + * 读取图片文件 + * @param deployId + * @return + */ + InputStream readImage(String deployId); +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/IFlowInstanceService.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/IFlowInstanceService.java new file mode 100644 index 0000000..d00390e --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/IFlowInstanceService.java @@ -0,0 +1,53 @@ +package com.boyue.flowable.service; + +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.flowable.domain.vo.FlowTaskVo; +import org.flowable.engine.history.HistoricProcessInstance; +import java.util.Map; + +/** + * @author Tony + * @date 2021-04-03 14:40 + */ +public interface IFlowInstanceService { + + /** + * 结束流程实例 + * + * @param vo + */ + void stopProcessInstance(FlowTaskVo vo); + + /** + * 激活或挂起流程实例 + * + * @param state 状态 + * @param instanceId 流程实例ID + */ + void updateState(Integer state, String instanceId); + + /** + * 删除流程实例ID + * + * @param instanceId 流程实例ID + * @param deleteReason 删除原因 + */ + void delete(String instanceId, String deleteReason); + + /** + * 根据实例ID查询历史实例数据 + * + * @param processInstanceId + * @return + */ + HistoricProcessInstance getHistoricProcessInstanceById(String processInstanceId); + + /** + * 根据流程定义ID启动流程实例 + * + * @param procDefId 流程定义Id + * @param variables 流程变量 + * @return + */ + AjaxResult startProcessInstanceById(String procDefId, Map variables); +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/IFlowTaskService.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/IFlowTaskService.java new file mode 100644 index 0000000..2f79cec --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/IFlowTaskService.java @@ -0,0 +1,218 @@ +package com.boyue.flowable.service; + +import java.io.InputStream; +import java.util.List; + +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.flowable.domain.dto.FlowTaskDto; +import com.boyue.flowable.domain.vo.FlowQueryVo; +import com.boyue.flowable.domain.vo.FlowTaskVo; + +/** + * @author Tony + * @date 2021-04-03 14:42 + */ +public interface IFlowTaskService { + + /** + * 审批任务 + * + * @param task 请求实体参数 + */ + AjaxResult complete(FlowTaskVo task); + + /** + * 驳回任务 + * + * @param flowTaskVo + */ + void taskReject(FlowTaskVo flowTaskVo); + + + /** + * 退回任务 + * + * @param flowTaskVo 请求实体参数 + */ + void taskReturn(FlowTaskVo flowTaskVo); + + /** + * 获取所有可回退的节点 + * + * @param flowTaskVo + * @return + */ + AjaxResult findReturnTaskList(FlowTaskVo flowTaskVo); + + /** + * 删除任务 + * + * @param flowTaskVo 请求实体参数 + */ + void deleteTask(FlowTaskVo flowTaskVo); + + /** + * 认领/签收任务 + * + * @param flowTaskVo 请求实体参数 + */ + void claim(FlowTaskVo flowTaskVo); + + /** + * 取消认领/签收任务 + * + * @param flowTaskVo 请求实体参数 + */ + void unClaim(FlowTaskVo flowTaskVo); + + /** + * 委派任务 + * + * @param flowTaskVo 请求实体参数 + */ + void delegateTask(FlowTaskVo flowTaskVo); + + /** + * 任务归还 + * + * @param flowTaskVo 请求实体参数 + */ + void resolveTask(FlowTaskVo flowTaskVo); + + + /** + * 转办任务 + * + * @param flowTaskVo 请求实体参数 + */ + void assignTask(FlowTaskVo flowTaskVo); + + + /** + * 多实例加签 + * @param flowTaskVo + */ + void addMultiInstanceExecution(FlowTaskVo flowTaskVo); + + /** + * 多实例减签 + * @param flowTaskVo + */ + void deleteMultiInstanceExecution(FlowTaskVo flowTaskVo); + + /** + * 我发起的流程 + * @param queryVo 请求参数 + * @return + */ + List myProcess(FlowQueryVo queryVo); + + /** + * 取消申请 + * 目前实现方式: 直接将当前流程变更为已完成 + * @param flowTaskVo + * @return + */ + AjaxResult stopProcess(FlowTaskVo flowTaskVo); + + /** + * 撤回流程 + * @param flowTaskVo + * @return + */ + AjaxResult revokeProcess(FlowTaskVo flowTaskVo); + + + /** + * 代办任务列表 + * + * @param queryVo 请求参数 + * @return + */ + List todoList(FlowQueryVo queryVo); + + + /** + * 已办任务列表 + * + * @param queryVo 请求参数 + * @return + */ + List finishedList(FlowQueryVo queryVo); + + /** + * 流程历史流转记录 + * + * @param procInsId 流程实例Id + * @return + */ + AjaxResult flowRecord(String procInsId,String deployId); + + /** + * 根据任务ID查询挂载的表单信息 + * + * @param taskId 任务Id + * @return + */ + AjaxResult getTaskForm(String taskId); + + /** + * 获取流程过程图 + * @param processId + * @return + */ + InputStream diagram(String processId); + + /** + * 获取流程执行节点 + * @param procInsId + * @return + */ + AjaxResult getFlowViewer(String procInsId,String executionId); + + /** + * 获取流程变量 + * @param taskId + * @return + */ + AjaxResult processVariables(String taskId); + + /** + * 获取下一节点 + * @param flowTaskVo 任务 + * @return + */ + AjaxResult getNextFlowNode(FlowTaskVo flowTaskVo); + + AjaxResult getNextFlowNodeByStart(FlowTaskVo flowTaskVo); + + /** + * 流程初始化表单 + * @param deployId + * @return + */ + AjaxResult flowFormData(String deployId); + + /** + * 流程节点信息 + * @param procInsId + * @return + */ + AjaxResult flowXmlAndNode(String procInsId,String deployId); + + /** + * 流程节点表单 + * @param taskId 流程任务编号 + * @return + */ + AjaxResult flowTaskForm(String taskId) throws Exception; + + + /** + * 流程节点信息 + * @param procInsId + * @param elementId + * @return + */ + AjaxResult flowTaskInfo(String procInsId, String elementId); +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/ISysDeployFormService.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/ISysDeployFormService.java new file mode 100644 index 0000000..341f15d --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/ISysDeployFormService.java @@ -0,0 +1,69 @@ +package com.boyue.flowable.service; + +import java.util.List; + +import com.boyue.flowable.domain.SysDeployForm; +import com.boyue.form.domain.FormTemplate; +/** + * 流程实例关联表单Service接口 + * + * @author Tony + * @date 2021-04-03 + */ +public interface ISysDeployFormService +{ + /** + * 查询流程实例关联表单 + * + * @param id 流程实例关联表单ID + * @return 流程实例关联表单 + */ + public SysDeployForm selectSysDeployFormById(Long id); + + /** + * 查询流程实例关联表单列表 + * + * @param sysDeployForm 流程实例关联表单 + * @return 流程实例关联表单集合 + */ + public List selectSysDeployFormList(SysDeployForm sysDeployForm); + + /** + * 新增流程实例关联表单 + * + * @param sysDeployForm 流程实例关联表单 + * @return 结果 + */ + public int insertSysDeployForm(SysDeployForm sysDeployForm); + + /** + * 修改流程实例关联表单 + * + * @param sysDeployForm 流程实例关联表单 + * @return 结果 + */ + public int updateSysDeployForm(SysDeployForm sysDeployForm); + + /** + * 批量删除流程实例关联表单 + * + * @param ids 需要删除的流程实例关联表单ID + * @return 结果 + */ + public int deleteSysDeployFormByIds(Long[] ids); + + /** + * 删除流程实例关联表单信息 + * + * @param id 流程实例关联表单ID + * @return 结果 + */ + public int deleteSysDeployFormById(Long id); + + /** + * 查询流程挂着的表单 + * @param deployId + * @return + */ + FormTemplate selectSysDeployFormByDeployId(String deployId); +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/ISysExpressionService.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/ISysExpressionService.java new file mode 100644 index 0000000..09dd3f8 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/ISysExpressionService.java @@ -0,0 +1,62 @@ +package com.boyue.flowable.service; + +import java.util.List; + +import com.boyue.flowable.domain.SysExpression; + +/** + * 流程达式Service接口 + * + * @author boyue + * @date 2022-12-12 + */ +public interface ISysExpressionService +{ + /** + * 查询流程达式 + * + * @param id 流程达式主键 + * @return 流程达式 + */ + public SysExpression selectSysExpressionById(Long id); + + /** + * 查询流程达式列表 + * + * @param sysExpression 流程达式 + * @return 流程达式集合 + */ + public List selectSysExpressionList(SysExpression sysExpression); + + /** + * 新增流程达式 + * + * @param sysExpression 流程达式 + * @return 结果 + */ + public int insertSysExpression(SysExpression sysExpression); + + /** + * 修改流程达式 + * + * @param sysExpression 流程达式 + * @return 结果 + */ + public int updateSysExpression(SysExpression sysExpression); + + /** + * 批量删除流程达式 + * + * @param ids 需要删除的流程达式主键集合 + * @return 结果 + */ + public int deleteSysExpressionByIds(Long[] ids); + + /** + * 删除流程达式信息 + * + * @param id 流程达式主键 + * @return 结果 + */ + public int deleteSysExpressionById(Long id); +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/ISysListenerService.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/ISysListenerService.java new file mode 100644 index 0000000..3b53ac9 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/ISysListenerService.java @@ -0,0 +1,62 @@ +package com.boyue.flowable.service; + +import java.util.List; + +import com.boyue.flowable.domain.SysListener; + +/** + * 流程监听Service接口 + * + * @author Tony + * @date 2022-12-25 + */ +public interface ISysListenerService +{ + /** + * 查询流程监听 + * + * @param id 流程监听主键 + * @return 流程监听 + */ + public SysListener selectSysListenerById(Long id); + + /** + * 查询流程监听列表 + * + * @param sysListener 流程监听 + * @return 流程监听集合 + */ + public List selectSysListenerList(SysListener sysListener); + + /** + * 新增流程监听 + * + * @param sysListener 流程监听 + * @return 结果 + */ + public int insertSysListener(SysListener sysListener); + + /** + * 修改流程监听 + * + * @param sysListener 流程监听 + * @return 结果 + */ + public int updateSysListener(SysListener sysListener); + + /** + * 批量删除流程监听 + * + * @param ids 需要删除的流程监听主键集合 + * @return 结果 + */ + public int deleteSysListenerByIds(Long[] ids); + + /** + * 删除流程监听信息 + * + * @param id 流程监听主键 + * @return 结果 + */ + public int deleteSysListenerById(Long id); +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/FlowDefinitionServiceImpl.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/FlowDefinitionServiceImpl.java new file mode 100644 index 0000000..f3783e1 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/FlowDefinitionServiceImpl.java @@ -0,0 +1,246 @@ +package com.boyue.flowable.service.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import org.apache.commons.io.IOUtils; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.repository.ProcessDefinitionQuery; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.image.impl.DefaultProcessDiagramGenerator; +import org.flowable.task.api.Task; +import org.springframework.stereotype.Service; + +import com.github.pagehelper.PageHelper; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.flowable.common.constant.ProcessConstants; +import com.boyue.flowable.common.enums.FlowComment; +import com.boyue.flowable.domain.dto.FlowProcDefDto; +import com.boyue.flowable.factory.FlowServiceFactory; +import com.boyue.flowable.mapper.FlowDeployMapper; +import com.boyue.flowable.service.IFlowDefinitionService; +import com.boyue.flowable.service.ISysDeployFormService; +import com.boyue.form.domain.FormTemplate; +import com.boyue.system.service.ISysDeptService; +import com.boyue.system.service.ISysUserService; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; + +/** + * 流程定义 + * + * @author Tony + * @date 2021-04-03 + */ +@Service +@Slf4j +public class FlowDefinitionServiceImpl extends FlowServiceFactory implements IFlowDefinitionService { + + @Resource + private ISysDeployFormService sysDeployFormService; + + @Resource + private ISysUserService sysUserService; + + @Resource + private ISysDeptService sysDeptService; + + @Resource + private FlowDeployMapper flowDeployMapper; + + private static final String BPMN_FILE_SUFFIX = ".bpmn"; + + @Override + public boolean exist(String processDefinitionKey) { + ProcessDefinitionQuery processDefinitionQuery + = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processDefinitionKey); + long count = processDefinitionQuery.count(); + return count > 0 ? true : false; + } + + + /** + * 流程定义列表 + * + * @param pageNum 当前页码 + * @param pageSize 每页条数 + * @return 流程定义分页列表数据 + */ + @Override + public List list(String name, Integer pageNum, Integer pageSize) { +// Page page = new Page(); +// // 流程定义列表数据查询 +// final ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery(); +// if (StringUtils.isNotEmpty(name)) { +// processDefinitionQuery.processDefinitionNameLike(name); +// } +//// processDefinitionQuery.orderByProcessDefinitionKey().asc(); +// page.setTotal(processDefinitionQuery.count()); +// List processDefinitionList = processDefinitionQuery.listPage(pageSize * (pageNum - 1), pageSize); +// +// List dataList = new ArrayList<>(); +// for (ProcessDefinition processDefinition : processDefinitionList) { +// String deploymentId = processDefinition.getDeploymentId(); +// Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult(); +// FlowProcDefDto reProcDef = new FlowProcDefDto(); +// BeanUtils.copyProperties(processDefinition, reProcDef); +// SysForm sysForm = sysDeployFormService.selectSysDeployFormByDeployId(deploymentId); +// if (Objects.nonNull(sysForm)) { +// reProcDef.setFormName(sysForm.getFormName()); +// reProcDef.setFormId(sysForm.getFormId()); +// } +// // 流程定义时间 +// reProcDef.setDeploymentTime(deployment.getDeploymentTime()); +// dataList.add(reProcDef); +// } + PageHelper.startPage(pageNum, pageSize); + final List dataList = flowDeployMapper.selectDeployList(name); + // 加载挂表单 + for (FlowProcDefDto procDef : dataList) { + FormTemplate sysForm = sysDeployFormService.selectSysDeployFormByDeployId(procDef.getDeploymentId()); + if (Objects.nonNull(sysForm)) { + procDef.setFormName(sysForm.getFormName()); + procDef.setFormId(sysForm.getFormId()); + } + } + return dataList; + } + + + /** + * 导入流程文件 + * + * 当每个key的流程第一次部署时,指定版本为1。对其后所有使用相同key的流程定义, + * 部署时版本会在该key当前已部署的最高版本号基础上加1。key参数用于区分流程定义 + * @param name + * @param category + * @param in + */ + @Override + public void importFile(String name, String category, InputStream in) { + Deployment deploy = repositoryService.createDeployment().addInputStream(name + BPMN_FILE_SUFFIX, in).name(name).category(category).deploy(); + ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult(); + repositoryService.setProcessDefinitionCategory(definition.getId(), category); + + } + + /** + * 读取xml + * + * @param deployId + * @return + */ + @Override + public AjaxResult readXml(String deployId) throws IOException { + ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult(); + InputStream inputStream = repositoryService.getResourceAsStream(definition.getDeploymentId(), definition.getResourceName()); + String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8.name()); + return AjaxResult.success("", result); + } + + /** + * 读取xml + * + * @param deployId + * @return + */ + @Override + public InputStream readImage(String deployId) { + ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult(); + //获得图片流 + DefaultProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator(); + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); + //输出为图片 + return diagramGenerator.generateDiagram( + bpmnModel, + "png", + Collections.emptyList(), + Collections.emptyList(), + "宋体", + "宋体", + "宋体", + null, + 1.0, + false); + + } + + /** + * 根据流程定义ID启动流程实例 + * + * @param procDefId 流程模板ID + * @param variables 流程变量 + * @return + */ + @Override + public AjaxResult startProcessInstanceById(String procDefId, Map variables) { + try { + ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId) + .latestVersion().singleResult(); + if (Objects.nonNull(processDefinition) && processDefinition.isSuspended()) { + return AjaxResult.error("流程已被挂起,请先激活流程"); + } + // 设置流程发起人Id到流程中 + SysUser sysUser = SecurityUtils.getLoginUser().getUser(); + identityService.setAuthenticatedUserId(sysUser.getUserId().toString()); + variables.put(ProcessConstants.PROCESS_INITIATOR, sysUser.getUserId()); + + // 流程发起时 跳过发起人节点 + ProcessInstance processInstance = runtimeService.startProcessInstanceById(procDefId, variables); + // 给第一步申请人节点设置任务执行人和意见 + Task task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).singleResult(); + if (Objects.nonNull(task)) { + taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), FlowComment.NORMAL.getType(), sysUser.getNickName() + "发起流程申请"); + taskService.complete(task.getId(), variables); + } + return AjaxResult.success("流程启动成功"); + } catch (Exception e) { + e.printStackTrace(); + return AjaxResult.error("流程启动错误"); + } + } + + + /** + * 激活或挂起流程定义 + * + * @param state 状态 + * @param deployId 流程部署ID + */ + @Override + public void updateState(Integer state, String deployId) { + ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult(); + // 激活 + if (state == 1) { + repositoryService.activateProcessDefinitionById(procDef.getId(), true, null); + } + // 挂起 + if (state == 2) { + repositoryService.suspendProcessDefinitionById(procDef.getId(), true, null); + } + } + + + /** + * 删除流程定义 + * + * @param deployId 流程部署ID act_ge_bytearray 表中 deployment_id值 + */ + @Override + public void delete(String deployId) { + // true 允许级联删除 ,不设置会导致数据库外键关联异常 + repositoryService.deleteDeployment(deployId, true); + } + + +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/FlowInstanceServiceImpl.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/FlowInstanceServiceImpl.java new file mode 100644 index 0000000..d5822b2 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/FlowInstanceServiceImpl.java @@ -0,0 +1,140 @@ +package com.boyue.flowable.service.impl; + +import java.util.Map; +import java.util.Objects; + +import org.flowable.common.engine.api.FlowableObjectNotFoundException; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.task.api.Task; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.flowable.domain.vo.FlowTaskVo; +import com.boyue.flowable.factory.FlowServiceFactory; +import com.boyue.flowable.service.IFlowInstanceService; + +import lombok.extern.slf4j.Slf4j; + +/** + *

+ * 工作流流程实例管理 + *

+ * + * @author Tony + * @date 2021-04-03 + */ +@Service +@Slf4j +public class FlowInstanceServiceImpl extends FlowServiceFactory implements IFlowInstanceService { + + /** + * 结束流程实例 + * + * @param vo + */ + @Override + public void stopProcessInstance(FlowTaskVo vo) { + String taskId = vo.getTaskId(); + + if (!StringUtils.hasText(taskId)) { + throw new IllegalArgumentException("任务ID不能为空。"); + } + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + if (task == null) { + throw new RuntimeException("未找到ID为 " + taskId + " 的任务,无法停止流程实例。可能任务已完成或不存在。"); + } + String processInstanceId = task.getProcessInstanceId(); + if (!StringUtils.hasText(processInstanceId)) { + throw new RuntimeException("任务 " + taskId + " 没有关联的流程实例ID。"); + } + String deleteReason = vo.getComment(); // 假设 FlowTaskVo 有 getComment() 方法获取原因 + if (!StringUtils.hasText(deleteReason)) { + deleteReason = "流程实例由用户通过任务ID " + taskId + " 手动停止。"; // 提供一个默认原因 + } + runtimeService.deleteProcessInstance(processInstanceId, deleteReason); + } + + /** + * 激活或挂起流程实例 + * + * @param state 状态 + * @param instanceId 流程实例ID + */ + @Override + public void updateState(Integer state, String instanceId) { + + // 激活 + if (state == 1) { + runtimeService.activateProcessInstanceById(instanceId); + } + // 挂起 + if (state == 2) { + runtimeService.suspendProcessInstanceById(instanceId); + } + } + + /** + * 删除流程实例ID + * + * @param instanceId 流程实例ID + * @param deleteReason 删除原因 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(String instanceId, String deleteReason) { + + // 查询历史数据 + HistoricProcessInstance historicProcessInstance = getHistoricProcessInstanceById(instanceId); + if (historicProcessInstance.getEndTime() != null) { + historyService.deleteHistoricProcessInstance(historicProcessInstance.getId()); + return; + } + // 删除流程实例 + runtimeService.deleteProcessInstance(instanceId, deleteReason); + // 删除历史流程实例 + historyService.deleteHistoricProcessInstance(instanceId); + } + + /** + * 根据实例ID查询历史实例数据 + * + * @param processInstanceId + * @return + */ + @Override + public HistoricProcessInstance getHistoricProcessInstanceById(String processInstanceId) { + HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() + .processInstanceId(processInstanceId).singleResult(); + if (Objects.isNull(historicProcessInstance)) { + throw new FlowableObjectNotFoundException("流程实例不存在: " + processInstanceId); + } + return historicProcessInstance; + } + + /** + * 根据流程定义ID启动流程实例 + * + * @param procDefId 流程定义Id + * @param variables 流程变量 + * @return + */ + @Override + public AjaxResult startProcessInstanceById(String procDefId, Map variables) { + + try { + // 设置流程发起人Id到流程中 + Long userId = SecurityUtils.getLoginUser().getUser().getUserId(); + // identityService.setAuthenticatedUserId(userId.toString()); + variables.put("initiator", userId); + variables.put("_FLOWABLE_SKIP_EXPRESSION_ENABLED", true); + runtimeService.startProcessInstanceById(procDefId, variables); + return AjaxResult.success("流程启动成功"); + } catch (Exception e) { + e.printStackTrace(); + return AjaxResult.error("流程启动错误"); + } + } +} \ No newline at end of file diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/FlowTaskServiceImpl.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/FlowTaskServiceImpl.java new file mode 100644 index 0000000..57ac330 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/FlowTaskServiceImpl.java @@ -0,0 +1,1315 @@ +package com.boyue.flowable.service.impl; + +import java.io.InputStream; +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.EndEvent; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.MultiInstanceLoopCharacteristics; +import org.flowable.bpmn.model.Process; +import org.flowable.bpmn.model.UserTask; +import org.flowable.common.engine.api.FlowableException; +import org.flowable.common.engine.api.FlowableObjectNotFoundException; +import org.flowable.common.engine.impl.identity.Authentication; +import org.flowable.engine.ProcessEngineConfiguration; +import org.flowable.engine.history.HistoricActivityInstance; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.history.HistoricProcessInstanceQuery; +import org.flowable.engine.impl.cmd.AddMultiInstanceExecutionCmd; +import org.flowable.engine.impl.cmd.DeleteMultiInstanceExecutionCmd; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.runtime.Execution; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.engine.task.Comment; +import org.flowable.identitylink.api.history.HistoricIdentityLink; +import org.flowable.image.ProcessDiagramGenerator; +import org.flowable.task.api.DelegationState; +import org.flowable.task.api.Task; +import org.flowable.task.api.TaskQuery; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.flowable.task.api.history.HistoricTaskInstanceQuery; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.alibaba.fastjson2.TypeReference; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.flowable.common.constant.ProcessConstants; +import com.boyue.flowable.common.enums.FlowComment; +import com.boyue.flowable.domain.dto.FlowCommentDto; +import com.boyue.flowable.domain.dto.FlowNextDto; +import com.boyue.flowable.domain.dto.FlowTaskDto; +import com.boyue.flowable.domain.dto.FlowViewerDto; +import com.boyue.flowable.domain.vo.FlowQueryVo; +import com.boyue.flowable.domain.vo.FlowTaskVo; +import com.boyue.flowable.factory.FlowServiceFactory; +import com.boyue.flowable.flow.CustomProcessDiagramGenerator; +import com.boyue.flowable.flow.FindNextNodeUtil; +import com.boyue.flowable.flow.FlowableUtils; +import com.boyue.flowable.service.IFlowTaskService; +import com.boyue.flowable.service.ISysDeployFormService; +import com.boyue.form.domain.FormTemplate; +import com.boyue.form.service.IFormTemplateService; +import com.boyue.system.service.ISysRoleService; +import com.boyue.system.service.ISysUserService; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; + +/** + * @author Tony + * @date 2021-04-03 + **/ +@Service +@Slf4j +public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTaskService { + + @Resource + private ISysUserService sysUserService; + @Resource + private ISysRoleService sysRoleService; + @Resource + private ISysDeployFormService sysInstanceFormService; + // @Resource + // private ISysFormService sysFormService; + @Resource + private IFormTemplateService formTemplateService; + + /** + * 完成任务 + * + * @param taskVo 请求实体参数 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public AjaxResult complete(FlowTaskVo taskVo) { + Task task = taskService.createTaskQuery().taskId(taskVo.getTaskId()).singleResult(); + if (Objects.isNull(task)) { + return AjaxResult.error("任务不存在"); + } + if (DelegationState.PENDING.equals(task.getDelegationState())) { + taskService.addComment(taskVo.getTaskId(), taskVo.getInstanceId(), FlowComment.DELEGATE.getType(), + taskVo.getComment()); + taskService.resolveTask(taskVo.getTaskId(), taskVo.getVariables()); + } else { + taskService.addComment(taskVo.getTaskId(), taskVo.getInstanceId(), FlowComment.NORMAL.getType(), + taskVo.getComment()); + Long userId = SecurityUtils.getLoginUser().getUser().getUserId(); + taskService.setAssignee(taskVo.getTaskId(), userId.toString()); + taskService.complete(taskVo.getTaskId(), taskVo.getVariables()); + } + return AjaxResult.success(); + } + + /** + * 驳回任务 + * + * @param flowTaskVo + */ + @Override + public void taskReject(FlowTaskVo flowTaskVo) { + if (taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult().isSuspended()) { + throw new ServiceException("任务处于挂起状态!"); + } + // 当前任务 task + Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult(); + // 获取流程定义信息 + ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() + .processDefinitionId(task.getProcessDefinitionId()).singleResult(); + // 获取所有节点信息 + Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0); + // 获取全部节点列表,包含子节点 + Collection allElements = FlowableUtils.getAllElements(process.getFlowElements(), null); + // 获取当前任务节点元素 + FlowElement source = null; + if (allElements != null) { + for (FlowElement flowElement : allElements) { + // 类型为用户节点 + if (flowElement.getId().equals(task.getTaskDefinitionKey())) { + // 获取节点信息 + source = flowElement; + } + } + } + + // 目的获取所有跳转到的节点 targetIds + // 获取当前节点的所有父级用户任务节点 + // 深度优先算法思想:延边迭代深入 + List parentUserTaskList = FlowableUtils.iteratorFindParentUserTasks(source, null, null); + if (parentUserTaskList == null || parentUserTaskList.size() == 0) { + throw new ServiceException("当前节点为初始任务节点,不能驳回"); + } + // 获取活动 ID 即节点 Key + List parentUserTaskKeyList = new ArrayList<>(); + parentUserTaskList.forEach(item -> parentUserTaskKeyList.add(item.getId())); + // 获取全部历史节点活动实例,即已经走过的节点历史,数据采用开始时间升序 + List historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery() + .processInstanceId(task.getProcessInstanceId()).orderByHistoricTaskInstanceStartTime().asc().list(); + // 数据清洗,将回滚导致的脏数据清洗掉 + List lastHistoricTaskInstanceList = FlowableUtils.historicTaskInstanceClean(allElements, + historicTaskInstanceList); + // 此时历史任务实例为倒序,获取最后走的节点 + List targetIds = new ArrayList<>(); + // 循环结束标识,遇到当前目标节点的次数 + int number = 0; + StringBuilder parentHistoricTaskKey = new StringBuilder(); + for (String historicTaskInstanceKey : lastHistoricTaskInstanceList) { + // 当会签时候会出现特殊的,连续都是同一个节点历史数据的情况,这种时候跳过 + if (parentHistoricTaskKey.toString().equals(historicTaskInstanceKey)) { + continue; + } + parentHistoricTaskKey = new StringBuilder(historicTaskInstanceKey); + if (historicTaskInstanceKey.equals(task.getTaskDefinitionKey())) { + number++; + } + // 在数据清洗后,历史节点就是唯一一条从起始到当前节点的历史记录,理论上每个点只会出现一次 + // 在流程中如果出现循环,那么每次循环中间的点也只会出现一次,再出现就是下次循环 + // number == 1,第一次遇到当前节点 + // number == 2,第二次遇到,代表最后一次的循环范围 + if (number == 2) { + break; + } + // 如果当前历史节点,属于父级的节点,说明最后一次经过了这个点,需要退回这个点 + if (parentUserTaskKeyList.contains(historicTaskInstanceKey)) { + targetIds.add(historicTaskInstanceKey); + } + } + + // 目的获取所有需要被跳转的节点 currentIds + // 取其中一个父级任务,因为后续要么存在公共网关,要么就是串行公共线路 + UserTask oneUserTask = parentUserTaskList.get(0); + // 获取所有正常进行的任务节点 Key,这些任务不能直接使用,需要找出其中需要撤回的任务 + List runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list(); + List runTaskKeyList = new ArrayList<>(); + runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey())); + // 需驳回任务列表 + List currentIds = new ArrayList<>(); + // 通过父级网关的出口连线,结合 runTaskList 比对,获取需要撤回的任务 + List currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(oneUserTask, runTaskKeyList, null, + null); + currentUserTaskList.forEach(item -> currentIds.add(item.getId())); + + // 规定:并行网关之前节点必须需存在唯一用户任务节点,如果出现多个任务节点,则并行网关节点默认为结束节点,原因为不考虑多对多情况 + if (targetIds.size() > 1 && currentIds.size() > 1) { + throw new ServiceException("任务出现多对多情况,无法撤回"); + } + + // 循环获取那些需要被撤回的节点的ID,用来设置驳回原因 + List currentTaskIds = new ArrayList<>(); + currentIds.forEach(currentId -> runTaskList.forEach(runTask -> { + if (currentId.equals(runTask.getTaskDefinitionKey())) { + currentTaskIds.add(runTask.getId()); + } + })); + // 设置驳回意见 + currentTaskIds.forEach(item -> taskService.addComment(item, task.getProcessInstanceId(), + FlowComment.REJECT.getType(), flowTaskVo.getComment())); + + try { + // 如果父级任务多于 1 个,说明当前节点不是并行节点,原因为不考虑多对多情况 + if (targetIds.size() > 1) { + // 1 对 多任务跳转,currentIds 当前节点(1),targetIds 跳转到的节点(多) + runtimeService.createChangeActivityStateBuilder() + .processInstanceId(task.getProcessInstanceId()) + .moveSingleActivityIdToActivityIds(currentIds.get(0), targetIds).changeState(); + } + // 如果父级任务只有一个,因此当前任务可能为网关中的任务 + if (targetIds.size() == 1) { + // 1 对 1 或 多 对 1 情况,currentIds 当前要跳转的节点列表(1或多),targetIds.get(0) 跳转到的节点(1) + runtimeService.createChangeActivityStateBuilder() + .processInstanceId(task.getProcessInstanceId()) + .moveActivityIdsToSingleActivityId(currentIds, targetIds.get(0)).changeState(); + } + } catch (FlowableObjectNotFoundException e) { + throw new ServiceException("未找到流程实例,流程可能已发生变化"); + } catch (FlowableException e) { + throw new ServiceException("无法取消或开始活动"); + } + + } + + /** + * 退回任务 + * + * @param flowTaskVo 请求实体参数 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void taskReturn(FlowTaskVo flowTaskVo) { + if (taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult().isSuspended()) { + throw new ServiceException("任务处于挂起状态"); + } + // 当前任务 task + Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult(); + // 获取流程定义信息 + ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() + .processDefinitionId(task.getProcessDefinitionId()).singleResult(); + // 获取所有节点信息 + Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0); + // 获取全部节点列表,包含子节点 + Collection allElements = FlowableUtils.getAllElements(process.getFlowElements(), null); + // 获取当前任务节点元素 + FlowElement source = null; + // 获取跳转的节点元素 + FlowElement target = null; + if (allElements != null) { + for (FlowElement flowElement : allElements) { + // 当前任务节点元素 + if (flowElement.getId().equals(task.getTaskDefinitionKey())) { + source = flowElement; + } + // 跳转的节点元素 + if (flowElement.getId().equals(flowTaskVo.getTargetKey())) { + target = flowElement; + } + } + } + + // 从当前节点向前扫描 + // 如果存在路线上不存在目标节点,说明目标节点是在网关上或非同一路线上,不可跳转 + // 否则目标节点相对于当前节点,属于串行 + Boolean isSequential = FlowableUtils.iteratorCheckSequentialReferTarget(source, flowTaskVo.getTargetKey(), null, + null); + if (!isSequential) { + throw new ServiceException("当前节点相对于目标节点,不属于串行关系,无法回退"); + } + + // 获取所有正常进行的任务节点 Key,这些任务不能直接使用,需要找出其中需要撤回的任务 + List runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list(); + List runTaskKeyList = new ArrayList<>(); + runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey())); + // 需退回任务列表 + List currentIds = new ArrayList<>(); + // 通过父级网关的出口连线,结合 runTaskList 比对,获取需要撤回的任务 + List currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(target, runTaskKeyList, null, + null); + currentUserTaskList.forEach(item -> currentIds.add(item.getId())); + + // 循环获取那些需要被撤回的节点的ID,用来设置驳回原因 + List currentTaskIds = new ArrayList<>(); + currentIds.forEach(currentId -> runTaskList.forEach(runTask -> { + if (currentId.equals(runTask.getTaskDefinitionKey())) { + currentTaskIds.add(runTask.getId()); + } + })); + // 设置回退意见 + currentTaskIds.forEach(currentTaskId -> taskService.addComment(currentTaskId, task.getProcessInstanceId(), + FlowComment.REBACK.getType(), flowTaskVo.getComment())); + + try { + // 1 对 1 或 多 对 1 情况,currentIds 当前要跳转的节点列表(1或多),targetKey 跳转到的节点(1) + runtimeService.createChangeActivityStateBuilder() + .processInstanceId(task.getProcessInstanceId()) + .moveActivityIdsToSingleActivityId(currentIds, flowTaskVo.getTargetKey()).changeState(); + } catch (FlowableObjectNotFoundException e) { + throw new ServiceException("未找到流程实例,流程可能已发生变化"); + } catch (FlowableException e) { + throw new ServiceException("无法取消或开始活动"); + } + } + + /** + * 获取所有可回退的节点 + * + * @param flowTaskVo + * @return + */ + @Override + public AjaxResult findReturnTaskList(FlowTaskVo flowTaskVo) { + // 当前任务 task + Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult(); + // 获取流程定义信息 + ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() + .processDefinitionId(task.getProcessDefinitionId()).singleResult(); + // 获取所有节点信息,暂不考虑子流程情况 + Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0); + Collection flowElements = process.getFlowElements(); + // 获取当前任务节点元素 + UserTask source = null; + if (flowElements != null) { + for (FlowElement flowElement : flowElements) { + // 类型为用户节点 + if (flowElement.getId().equals(task.getTaskDefinitionKey())) { + source = (UserTask) flowElement; + } + } + } + // 获取节点的所有路线 + List> roads = FlowableUtils.findRoad(source, null, null, null); + // 可回退的节点列表 + List userTaskList = new ArrayList<>(); + for (List road : roads) { + if (userTaskList.size() == 0) { + // 还没有可回退节点直接添加 + userTaskList = road; + } else { + // 如果已有回退节点,则比对取交集部分 + userTaskList.retainAll(road); + } + } + return AjaxResult.success(userTaskList); + } + + /** + * 删除任务 + * + * @param flowTaskVo 请求实体参数 + */ + @Override + public void deleteTask(FlowTaskVo flowTaskVo) { + // todo 待确认删除任务是物理删除任务 还是逻辑删除,让这个任务直接通过? + taskService.deleteTask(flowTaskVo.getTaskId(), flowTaskVo.getComment()); + } + + /** + * 认领/签收任务 + * 认领以后,这个用户就会成为任务的执行人,任务会从其他成员的任务列表中消失 + * + * @param flowTaskVo 请求实体参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void claim(FlowTaskVo flowTaskVo) { + taskService.claim(flowTaskVo.getTaskId(), flowTaskVo.getUserId()); + } + + /** + * 取消认领/签收任务 + * + * @param flowTaskVo 请求实体参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void unClaim(FlowTaskVo flowTaskVo) { + taskService.unclaim(flowTaskVo.getTaskId()); + } + + /** + * 委派任务 + * 任务委派只是委派人将当前的任务交给被委派人进行审批,处理任务后又重新回到委派人身上。 + * + * @param flowTaskVo 请求实体参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void delegateTask(FlowTaskVo flowTaskVo) { + taskService.delegateTask(flowTaskVo.getTaskId(), flowTaskVo.getAssignee()); + } + + /** + * 任务归还 + * 被委派人完成任务之后,将任务归还委派人 + * + * @param flowTaskVo 请求实体参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void resolveTask(FlowTaskVo flowTaskVo) { + taskService.resolveTask(flowTaskVo.getTaskId()); + } + + /** + * 转办任务 + * 直接将办理人换成别人,这时任务的拥有者不再是转办人 + * + * @param flowTaskVo 请求实体参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void assignTask(FlowTaskVo flowTaskVo) { + // 直接转派就可以覆盖掉之前的 + taskService.setAssignee(flowTaskVo.getTaskId(), flowTaskVo.getAssignee()); + // // 删除指派人重新指派 + // taskService.deleteCandidateUser(flowTaskVo.getTaskId(),flowTaskVo.getAssignee()); + // taskService.addCandidateUser(flowTaskVo.getTaskId(),flowTaskVo.getAssignee()); + // // 如果要查询转给他人处理的任务,可以同时将OWNER进行设置: + // taskService.setOwner(flowTaskVo.getTaskId(), flowTaskVo.getAssignee()); + + } + + /** + * 多实例加签 + * act_ru_task、act_ru_identitylink各生成一条记录 + * + * @param flowTaskVo + */ + @Override + public void addMultiInstanceExecution(FlowTaskVo flowTaskVo) { + managementService.executeCommand(new AddMultiInstanceExecutionCmd(flowTaskVo.getDefId(), + flowTaskVo.getInstanceId(), flowTaskVo.getVariables())); + } + + /** + * 多实例减签 + * act_ru_task减1、act_ru_identitylink不变 + * + * @param flowTaskVo + */ + @Override + public void deleteMultiInstanceExecution(FlowTaskVo flowTaskVo) { + managementService.executeCommand( + new DeleteMultiInstanceExecutionCmd(flowTaskVo.getCurrentChildExecutionId(), flowTaskVo.getFlag())); + } + + /** + * 我发起的流程 + * + * @param queryVo 请求参数 + * @return + */ + @Override + public List myProcess(FlowQueryVo queryVo) { + // List page = new Page<>(); + Long userId = SecurityUtils.getLoginUser().getUser().getUserId(); + HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery() + .startedBy(userId.toString()) + .orderByProcessInstanceStartTime() + .desc(); + List historicProcessInstances = historicProcessInstanceQuery + .listPage(queryVo.getPageSize() * (queryVo.getPageNum() - 1), queryVo.getPageSize()); + List flowList = new ArrayList<>(); + for (HistoricProcessInstance hisIns : historicProcessInstances) { + FlowTaskDto flowTask = new FlowTaskDto(); + flowTask.setCreateTime(hisIns.getStartTime()); + flowTask.setFinishTime(hisIns.getEndTime()); + flowTask.setProcInsId(hisIns.getId()); + + // 计算耗时 + if (Objects.nonNull(hisIns.getEndTime())) { + long time = hisIns.getEndTime().getTime() - hisIns.getStartTime().getTime(); + flowTask.setDuration(getDate(time)); + } else { + long time = System.currentTimeMillis() - hisIns.getStartTime().getTime(); + flowTask.setDuration(getDate(time)); + } + // 流程定义信息 + ProcessDefinition pd = repositoryService.createProcessDefinitionQuery() + .processDefinitionId(hisIns.getProcessDefinitionId()) + .singleResult(); + flowTask.setDeployId(pd.getDeploymentId()); + flowTask.setProcDefName(pd.getName()); + flowTask.setProcDefVersion(pd.getVersion()); + flowTask.setCategory(pd.getCategory()); + flowTask.setProcDefVersion(pd.getVersion()); + // 当前所处流程 + List taskList = taskService.createTaskQuery().processInstanceId(hisIns.getId()).list(); + if (CollectionUtils.isNotEmpty(taskList)) { + flowTask.setTaskId(taskList.get(0).getId()); + flowTask.setTaskName(taskList.get(0).getName()); + if (StringUtils.isNotBlank(taskList.get(0).getAssignee())) { + // 当前任务节点办理人信息 + SysUser sysUser = sysUserService.selectUserById(Long.parseLong(taskList.get(0).getAssignee())); + if (Objects.nonNull(sysUser)) { + flowTask.setAssigneeId(sysUser.getUserId()); + flowTask.setAssigneeName(sysUser.getNickName()); + flowTask.setAssigneeDeptName( + Objects.nonNull(sysUser.getDept()) ? sysUser.getDept().getDeptName() : ""); + } + } + } else { + List historicTaskInstance = historyService.createHistoricTaskInstanceQuery() + .processInstanceId(hisIns.getId()).orderByHistoricTaskInstanceEndTime().desc().list(); + flowTask.setTaskId(historicTaskInstance.get(0).getId()); + flowTask.setTaskName(historicTaskInstance.get(0).getName()); + if (StringUtils.isNotBlank(historicTaskInstance.get(0).getAssignee())) { + // 当前任务节点办理人信息 + SysUser sysUser = sysUserService + .selectUserById(Long.parseLong(historicTaskInstance.get(0).getAssignee())); + if (Objects.nonNull(sysUser)) { + flowTask.setAssigneeId(sysUser.getUserId()); + flowTask.setAssigneeName(sysUser.getNickName()); + flowTask.setAssigneeDeptName( + Objects.nonNull(sysUser.getDept()) ? sysUser.getDept().getDeptName() : ""); + } + } + } + flowList.add(flowTask); + } + + return flowList; + } + + /** + * 取消申请 + * 目前实现方式: 直接将当前流程变更为已完成 + * + * @param flowTaskVo + * @return + */ + @Override + public AjaxResult stopProcess(FlowTaskVo flowTaskVo) { + List task = taskService.createTaskQuery().processInstanceId(flowTaskVo.getInstanceId()).list(); + if (CollectionUtils.isEmpty(task)) { + throw new ServiceException("流程未启动或已执行完成,取消申请失败"); + } + // 获取当前流程实例 + ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() + .processInstanceId(flowTaskVo.getInstanceId()) + .singleResult(); + BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId()); + if (Objects.nonNull(bpmnModel)) { + Process process = bpmnModel.getMainProcess(); + List endNodes = process.findFlowElementsOfType(EndEvent.class, false); + if (CollectionUtils.isNotEmpty(endNodes)) { + SysUser loginUser = SecurityUtils.getLoginUser().getUser(); + Authentication.setAuthenticatedUserId(loginUser.getUserId().toString()); + taskService.addComment(null, processInstance.getProcessInstanceId(), + FlowComment.STOP.getType(), + StringUtils.isBlank(flowTaskVo.getComment()) ? "取消申请" : flowTaskVo.getComment()); + // 获取当前流程最后一个节点 + String endId = endNodes.get(0).getId(); + List executions = runtimeService.createExecutionQuery() + .parentId(processInstance.getProcessInstanceId()).list(); + List executionIds = new ArrayList<>(); + executions.forEach(execution -> executionIds.add(execution.getId())); + // 变更流程为已结束状态 + runtimeService.createChangeActivityStateBuilder() + .moveExecutionsToSingleActivityId(executionIds, endId).changeState(); + } + } + + return AjaxResult.success(); + } + + /** + * 撤回流程 目前存在错误 + * + * @param flowTaskVo + * @return + */ + @Override + public AjaxResult revokeProcess(FlowTaskVo flowTaskVo) { + Task task = taskService.createTaskQuery() + .processInstanceId(flowTaskVo.getInstanceId()) + .singleResult(); + if (task == null) { + throw new ServiceException("流程未启动或已执行完成,无法撤回"); + } + + SysUser loginUser = SecurityUtils.getLoginUser().getUser(); + List htiList = historyService.createHistoricTaskInstanceQuery() + .processInstanceId(task.getProcessInstanceId()) + .orderByTaskCreateTime() + .asc() + .list(); + String myTaskId = null; + for (HistoricTaskInstance hti : htiList) { + if (loginUser.getUserId().toString().equals(hti.getAssignee())) { + myTaskId = hti.getId(); + break; + } + } + if (null == myTaskId) { + throw new ServiceException("该任务非当前用户提交,无法撤回"); + } + List historicTaskInstanceList = historyService + .createHistoricTaskInstanceQuery() + .processInstanceId(task.getProcessInstanceId()) + .orderByHistoricTaskInstanceStartTime() + .asc() + .list(); + Iterator it = historicTaskInstanceList.iterator(); + // 循环节点,获取当前节点的上一节点的key + String tarKey = ""; + while (it.hasNext()) { + HistoricTaskInstance his = it.next(); + if (!task.getTaskDefinitionKey().equals(his.getTaskDefinitionKey())) { + tarKey = his.getTaskDefinitionKey(); + } + } + // 跳转节点 + runtimeService.createChangeActivityStateBuilder() + .processInstanceId(flowTaskVo.getInstanceId()) + .moveActivityIdTo(task.getTaskDefinitionKey(), tarKey) + .changeState(); + + return AjaxResult.success(); + } + + /** + * 代办任务列表 + * + * @param queryVo 请求参数 + * @return + */ + @Override + public List todoList(FlowQueryVo queryVo) { + SysUser sysUser = SecurityUtils.getLoginUser().getUser(); + TaskQuery taskQuery = taskService.createTaskQuery() + .active() + .includeProcessVariables() + .taskCandidateGroupIn(sysUser.getRoles().stream().map(role -> role.getRoleId().toString()) + .collect(Collectors.toList())) + .taskCandidateOrAssigned(sysUser.getUserId().toString()) + .orderByTaskCreateTime().desc(); + + if (StringUtils.isNotBlank(queryVo.getName())) { + String likePattern = "%" + queryVo.getName() + "%"; + taskQuery.processDefinitionNameLike(likePattern); + } + List taskList = taskQuery.listPage(queryVo.getPageSize() * (queryVo.getPageNum() - 1), + queryVo.getPageSize()); + List flowList = new ArrayList<>(); + for (Task task : taskList) { + FlowTaskDto flowTask = new FlowTaskDto(); + // 当前流程信息 + flowTask.setTaskId(task.getId()); + flowTask.setTaskDefKey(task.getTaskDefinitionKey()); + flowTask.setCreateTime(task.getCreateTime()); + flowTask.setProcDefId(task.getProcessDefinitionId()); + flowTask.setExecutionId(task.getExecutionId()); + flowTask.setTaskName(task.getName()); + // 流程定义信息 + ProcessDefinition pd = repositoryService.createProcessDefinitionQuery() + .processDefinitionId(task.getProcessDefinitionId()) + .singleResult(); + flowTask.setDeployId(pd.getDeploymentId()); + flowTask.setProcDefName(pd.getName()); + flowTask.setProcDefVersion(pd.getVersion()); + flowTask.setProcInsId(task.getProcessInstanceId()); + + // 流程发起人信息 + HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() + .processInstanceId(task.getProcessInstanceId()) + .singleResult(); + SysUser startUser = sysUserService.selectUserById(Long.parseLong(historicProcessInstance.getStartUserId())); + flowTask.setStartUserId(startUser.getUserId().toString()); + flowTask.setStartUserName(startUser.getNickName()); + flowTask.setStartDeptName(Objects.nonNull(startUser.getDept()) ? startUser.getDept().getDeptName() : ""); + flowList.add(flowTask); + } + return flowList; + } + + /** + * 已办任务列表 + * + * @param queryVo 请求参数 + * @return + */ + @Override + public List finishedList(FlowQueryVo queryVo) { + // List page = new ArrayList<>(); + Long userId = SecurityUtils.getLoginUser().getUser().getUserId(); + HistoricTaskInstanceQuery taskInstanceQuery = historyService.createHistoricTaskInstanceQuery() + .includeProcessVariables() + .finished() + .taskAssignee(userId.toString()) + .orderByHistoricTaskInstanceEndTime() + .desc(); + List historicTaskInstanceList = taskInstanceQuery + .listPage(queryVo.getPageSize() * (queryVo.getPageNum() - 1), queryVo.getPageSize()); + List hisTaskList = new ArrayList<>(); + for (HistoricTaskInstance histTask : historicTaskInstanceList) { + FlowTaskDto flowTask = new FlowTaskDto(); + // 当前流程信息 + flowTask.setTaskId(histTask.getId()); + // 审批人员信息 + flowTask.setCreateTime(histTask.getCreateTime()); + flowTask.setFinishTime(histTask.getEndTime()); + flowTask.setDuration(getDate(histTask.getDurationInMillis())); + flowTask.setProcDefId(histTask.getProcessDefinitionId()); + flowTask.setTaskDefKey(histTask.getTaskDefinitionKey()); + flowTask.setTaskName(histTask.getName()); + + // 流程定义信息 + ProcessDefinition pd = repositoryService.createProcessDefinitionQuery() + .processDefinitionId(histTask.getProcessDefinitionId()) + .singleResult(); + flowTask.setDeployId(pd.getDeploymentId()); + flowTask.setProcDefName(pd.getName()); + flowTask.setProcDefVersion(pd.getVersion()); + flowTask.setProcInsId(histTask.getProcessInstanceId()); + flowTask.setHisProcInsId(histTask.getProcessInstanceId()); + + // 流程发起人信息 + HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() + .processInstanceId(histTask.getProcessInstanceId()) + .singleResult(); + SysUser startUser = sysUserService.selectUserById(Long.parseLong(historicProcessInstance.getStartUserId())); + flowTask.setStartUserId(startUser.getNickName()); + flowTask.setStartUserName(startUser.getNickName()); + flowTask.setStartDeptName(Objects.nonNull(startUser.getDept()) ? startUser.getDept().getDeptName() : ""); + hisTaskList.add(flowTask); + } + return hisTaskList; + } + + // private static Predicate distinctByKey(Function + // keyExtractor) { + // Set seen = ConcurrentHashMap.newKeySet(); + // return t -> seen.add(keyExtractor.apply(t)); + // } + + /** + * 流程历史流转记录 + * + * @param procInsId 流程实例Id + * @return + */ + @Override + public AjaxResult flowRecord(String procInsId, String deployId) { + Map map = new HashMap(); + if (StringUtils.isNotBlank(procInsId)) { + List list = historyService + .createHistoricActivityInstanceQuery() + .processInstanceId(procInsId) + .orderByHistoricActivityInstanceStartTime() + .desc().list(); + List hisFlowList = new ArrayList<>(); + for (HistoricActivityInstance histIns : list) { + // 展示开始节点 + // if ("startEvent".equals(histIns.getActivityType())) { + // FlowTaskDto flowTask = new FlowTaskDto(); + // // 流程发起人信息 + // HistoricProcessInstance historicProcessInstance = + // historyService.createHistoricProcessInstanceQuery() + // .processInstanceId(histIns.getProcessInstanceId()) + // .singleResult(); + // SysUser startUser = + // sysUserService.selectUserById(Long.parseLong(historicProcessInstance.getStartUserId())); + // flowTask.setTaskName(startUser.getNickName() + "(" + + // startUser.getDept().getDeptName() + ")发起申请"); + // flowTask.setFinishTime(histIns.getEndTime()); + // hisFlowList.add(flowTask); + // } else if ("endEvent".equals(histIns.getActivityType())) { + // FlowTaskDto flowTask = new FlowTaskDto(); + // flowTask.setTaskName(StringUtils.isNotBlank(histIns.getActivityName()) ? + // histIns.getActivityName() : "结束"); + // flowTask.setFinishTime(histIns.getEndTime()); + // hisFlowList.add(flowTask); + // } else + if (StringUtils.isNotBlank(histIns.getTaskId())) { + FlowTaskDto flowTask = new FlowTaskDto(); + flowTask.setTaskId(histIns.getTaskId()); + flowTask.setTaskName(histIns.getActivityName()); + flowTask.setCreateTime(histIns.getStartTime()); + flowTask.setFinishTime(histIns.getEndTime()); + if (StringUtils.isNotBlank(histIns.getAssignee())) { + SysUser sysUser = sysUserService.selectUserById(Long.parseLong(histIns.getAssignee())); + flowTask.setAssigneeId(sysUser.getUserId()); + flowTask.setAssigneeName(sysUser.getNickName()); + flowTask.setDeptName(Objects.nonNull(sysUser.getDept()) ? sysUser.getDept().getDeptName() : ""); + } + // 展示审批人员 + List linksForTask = historyService + .getHistoricIdentityLinksForTask(histIns.getTaskId()); + StringBuilder stringBuilder = new StringBuilder(); + for (HistoricIdentityLink identityLink : linksForTask) { + // 获选人,候选组/角色(多个) + if ("candidate".equals(identityLink.getType())) { + if (StringUtils.isNotBlank(identityLink.getUserId())) { + SysUser sysUser = sysUserService + .selectUserById(Long.parseLong(identityLink.getUserId())); + stringBuilder.append(sysUser.getNickName()).append(","); + } + if (StringUtils.isNotBlank(identityLink.getGroupId())) { + SysRole sysRole = sysRoleService + .selectRoleById(Long.parseLong(identityLink.getGroupId())); + stringBuilder.append(sysRole.getRoleName()).append(","); + } + } + } + if (StringUtils.isNotBlank(stringBuilder)) { + flowTask.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1)); + } + + flowTask.setDuration( + histIns.getDurationInMillis() == null || histIns.getDurationInMillis() == 0 ? null + : getDate(histIns.getDurationInMillis())); + // 获取意见评论内容 + List commentList = taskService.getProcessInstanceComments(histIns.getProcessInstanceId()); + commentList.forEach(comment -> { + if (histIns.getTaskId().equals(comment.getTaskId())) { + flowTask.setComment(FlowCommentDto.builder().type(comment.getType()) + .comment(comment.getFullMessage()).build()); + } + }); + hisFlowList.add(flowTask); + } + } + map.put("flowList", hisFlowList); + } + // 第一次申请获取初始化表单 + if (StringUtils.isNotBlank(deployId)) { + FormTemplate sysForm = sysInstanceFormService.selectSysDeployFormByDeployId(deployId); + if (Objects.isNull(sysForm)) { + return AjaxResult.error("请先配置流程表单"); + } + map.put("formData", JSONObject.parseObject(sysForm.getFormSchema())); + } + return AjaxResult.success(map); + } + + /** + * 根据任务ID查询挂载的表单信息 + * + * @param taskId 任务Id + * @return + */ + @Override + public AjaxResult getTaskForm(String taskId) { + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + FormTemplate sysForm = formTemplateService.selectFormTemplateByFormId(Long.parseLong(task.getFormKey())); + return AjaxResult.success(sysForm.getFormSchema()); + } + + /** + * 获取流程过程图 + * + * @param processId + * @return + */ + @Override + public InputStream diagram(String processId) { + String processDefinitionId; + // 获取当前的流程实例 + ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processId) + .singleResult(); + // 如果流程已经结束,则得到结束节点 + if (Objects.isNull(processInstance)) { + HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery() + .processInstanceId(processId).singleResult(); + + processDefinitionId = pi.getProcessDefinitionId(); + } else {// 如果流程没有结束,则取当前活动节点 + // 根据流程实例ID获得当前处于活动状态的ActivityId合集 + ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId) + .singleResult(); + processDefinitionId = pi.getProcessDefinitionId(); + } + + // 获得活动的节点 + List highLightedFlowList = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list(); + + List highLightedFlows = new ArrayList<>(); + List highLightedNodes = new ArrayList<>(); + // 高亮线 + for (HistoricActivityInstance tempActivity : highLightedFlowList) { + if ("sequenceFlow".equals(tempActivity.getActivityType())) { + // 高亮线 + highLightedFlows.add(tempActivity.getActivityId()); + } else { + // 高亮节点 + highLightedNodes.add(tempActivity.getActivityId()); + } + } + + // 获取流程图 + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); + ProcessEngineConfiguration configuration = processEngine.getProcessEngineConfiguration(); + // 获取自定义图片生成器 + ProcessDiagramGenerator diagramGenerator = new CustomProcessDiagramGenerator(); + InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedNodes, highLightedFlows, + configuration.getActivityFontName(), + configuration.getLabelFontName(), configuration.getAnnotationFontName(), configuration.getClassLoader(), + 1.0, true); + return in; + + } + + /** + * 获取流程执行节点 + * + * @param procInsId 流程实例id + * @return + */ + @Override + public AjaxResult getFlowViewer(String procInsId, String executionId) { + List flowViewerList = new ArrayList<>(); + FlowViewerDto flowViewerDto; + // 获取任务开始节点(临时处理方式) + List startNodeList = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(procInsId) + .orderByHistoricActivityInstanceStartTime() + .asc().listPage(0, 3); + for (HistoricActivityInstance startInstance : startNodeList) { + if (!"sequenceFlow".equals(startInstance.getActivityType())) { + flowViewerDto = new FlowViewerDto(); + if (!"sequenceFlow".equals(startInstance.getActivityType())) { + flowViewerDto.setKey(startInstance.getActivityId()); + // 根据流程节点处理时间校验改节点是否已完成 + flowViewerDto.setCompleted(!Objects.isNull(startInstance.getEndTime())); + flowViewerList.add(flowViewerDto); + } + } + } + // 历史节点 + List hisActIns = historyService.createHistoricActivityInstanceQuery() + .executionId(executionId) + .orderByHistoricActivityInstanceStartTime() + .asc().list(); + for (HistoricActivityInstance activityInstance : hisActIns) { + if (!"sequenceFlow".equals(activityInstance.getActivityType())) { + flowViewerDto = new FlowViewerDto(); + flowViewerDto.setKey(activityInstance.getActivityId()); + // 根据流程节点处理时间校验改节点是否已完成 + flowViewerDto.setCompleted(!Objects.isNull(activityInstance.getEndTime())); + flowViewerList.add(flowViewerDto); + } + } + return AjaxResult.success(flowViewerList); + } + + /** + * 获取流程变量 + * + * @param taskId + * @return + */ + @Override + public AjaxResult processVariables(String taskId) { + // 流程变量 + HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery() + .includeProcessVariables().finished().taskId(taskId).singleResult(); + if (Objects.nonNull(historicTaskInstance)) { + return AjaxResult.success(historicTaskInstance.getProcessVariables()); + } else { + Map variables = taskService.getVariables(taskId); + return AjaxResult.success(variables); + } + } + + /** + * 审批任务获取下一节点 + * + * @param flowTaskVo 任务 + * @return + */ + @Override + public AjaxResult getNextFlowNode(FlowTaskVo flowTaskVo) { + // Step 1. 获取当前节点并找到下一步节点 + Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult(); + if (Objects.isNull(task)) { + return AjaxResult.error("任务不存在或已被审批!"); + } + // Step 2. 获取当前流程所有流程变量(网关节点时需要校验表达式) + Map variables = taskService.getVariables(task.getId()); + List nextUserTask = FindNextNodeUtil.getNextUserTasks(repositoryService, task, variables); + if (CollectionUtils.isEmpty(nextUserTask)) { + return AjaxResult.success("流程已完结!", null); + } + return getFlowAttribute(nextUserTask); + } + + /** + * 发起流程获取下一节点 + * + * @param flowTaskVo 任务 + * @return + */ + @Override + public AjaxResult getNextFlowNodeByStart(FlowTaskVo flowTaskVo) { + // Step 1. 查找流程定义信息 + ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() + .deploymentId(flowTaskVo.getDeploymentId()).singleResult(); + if (Objects.isNull(processDefinition)) { + return AjaxResult.error("流程信息不存在!"); + } + // Step 2. 获取下一任务节点(网关节点时需要校验表达式) + List nextUserTask = FindNextNodeUtil.getNextUserTasksByStart(repositoryService, processDefinition, + flowTaskVo.getVariables()); + if (CollectionUtils.isEmpty(nextUserTask)) { + return AjaxResult.error("暂未查找到下一任务,请检查流程设计是否正确!"); + } + return getFlowAttribute(nextUserTask); + } + + /** + * 获取任务节点属性,包含自定义属性等 + * + * @param nextUserTask + */ + private AjaxResult getFlowAttribute(List nextUserTask) { + FlowNextDto flowNextDto = new FlowNextDto(); + for (UserTask userTask : nextUserTask) { + MultiInstanceLoopCharacteristics multiInstance = userTask.getLoopCharacteristics(); + // 会签节点 + if (Objects.nonNull(multiInstance)) { + flowNextDto.setVars(multiInstance.getInputDataItem()); + flowNextDto.setType(ProcessConstants.PROCESS_MULTI_INSTANCE); + flowNextDto.setDataType(ProcessConstants.DYNAMIC); + } else { + // 读取自定义节点属性 判断是否是否需要动态指定任务接收人员、组 + String dataType = userTask.getAttributeValue(ProcessConstants.NAMASPASE, + ProcessConstants.PROCESS_CUSTOM_DATA_TYPE); + String userType = userTask.getAttributeValue(ProcessConstants.NAMASPASE, + ProcessConstants.PROCESS_CUSTOM_USER_TYPE); + flowNextDto.setVars(ProcessConstants.PROCESS_APPROVAL); + flowNextDto.setType(userType); + flowNextDto.setDataType(dataType); + } + } + return AjaxResult.success(flowNextDto); + } + + /** + * 流程初始化表单 + * + * @param deployId + * @return + */ + @Override + public AjaxResult flowFormData(String deployId) { + // 第一次申请获取初始化表单 + if (StringUtils.isNotBlank(deployId)) { + FormTemplate sysForm = sysInstanceFormService.selectSysDeployFormByDeployId(deployId); + if (Objects.isNull(sysForm)) { + return AjaxResult.error("请先配置流程表单!"); + } + return AjaxResult.success(JSONObject.parseObject(sysForm.getFormSchema())); + } else { + return AjaxResult.error("参数错误!"); + } + } + + /** + * 流程节点信息 + * + * @param procInsId + * @return + */ + @Override + public AjaxResult flowXmlAndNode(String procInsId, String deployId) { + try { + List flowViewerList = new ArrayList<>(); + // 获取已经完成的节点 + List listFinished = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(procInsId) + .finished() + .list(); + + // 保存已经完成的流程节点编号 + listFinished.forEach(s -> { + FlowViewerDto flowViewerDto = new FlowViewerDto(); + flowViewerDto.setKey(s.getActivityId()); + flowViewerDto.setCompleted(true); + // 退回节点不进行展示 + if (StringUtils.isBlank(s.getDeleteReason())) { + flowViewerList.add(flowViewerDto); + } + }); + + // 获取代办节点 + List listUnFinished = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(procInsId) + .unfinished() + .list(); + + // 保存需要代办的节点编号 + listUnFinished.forEach(s -> { + // 删除已退回节点 + flowViewerList.removeIf(task -> task.getKey().equals(s.getActivityId())); + FlowViewerDto flowViewerDto = new FlowViewerDto(); + flowViewerDto.setKey(s.getActivityId()); + flowViewerDto.setCompleted(false); + flowViewerList.add(flowViewerDto); + }); + Map result = new HashMap<>(); + // xmlData 数据 + ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deployId) + .singleResult(); + InputStream inputStream = repositoryService.getResourceAsStream(definition.getDeploymentId(), + definition.getResourceName()); + String xmlData = IOUtils.toString(inputStream, StandardCharsets.UTF_8); + result.put("nodeData", flowViewerList); + result.put("xmlData", xmlData); + return AjaxResult.success(result); + } catch (Exception e) { + return AjaxResult.error("高亮历史任务失败"); + } + } + + /** + * 流程节点表单 + * + * @param taskId 流程任务编号 + * @return + */ + @Override + public AjaxResult flowTaskForm(String taskId) throws Exception { + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + // 流程变量 + Map parameters = new HashMap<>(); + HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery() + .includeProcessVariables().finished().taskId(taskId).singleResult(); + if (Objects.nonNull(historicTaskInstance)) { + parameters = historicTaskInstance.getProcessVariables(); + } else { + parameters = taskService.getVariables(taskId); + } + JSONObject oldVariables = JSONObject.parseObject(JSON.toJSONString(parameters.get("formJson"))); + List oldFields = JSON.parseObject(JSON.toJSONString(oldVariables.get("widgetList")), + new TypeReference>() { + }); + // 设置已填写的表单为禁用状态 + for (JSONObject oldField : oldFields) { + JSONObject options = oldField.getJSONObject("options"); + options.put("disabled", true); + } + // 暂时只处理用户任务上的表单 + if (StringUtils.isNotBlank(task.getFormKey())) { + FormTemplate sysForm = formTemplateService.selectFormTemplateByFormId(Long.parseLong(task.getFormKey())); + if (Objects.isNull(sysForm)) { + throw new ServiceException("当前流程配置的表单不存在或已被删除"); + } + JSONObject data = JSONObject.parseObject(sysForm.getFormSchema()); + List newFields = JSON.parseObject( + JSON.toJSONString(data.get("widgetList")), + new TypeReference>() { + }); + // 表单回显时 加入子表单信息到流程变量中 + for (JSONObject newField : newFields) { + String key = newField.getString("id"); + // 处理图片上传组件回显问题 + if ("picture-upload".equals(newField.getString("type"))) { + parameters.put(key, new ArrayList<>()); + } else { + parameters.put(key, null); + } + } + oldFields.addAll(newFields); + } + oldVariables.put("widgetList", oldFields); + parameters.put("formJson", oldVariables); + return AjaxResult.success(parameters); + } + + /** + * 流程节点信息 + * + * @param procInsId + * @param elementId + * @return + */ + @Override + public AjaxResult flowTaskInfo(String procInsId, String elementId) { + List list = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(procInsId) + .activityId(elementId) + .list(); + // 退回任务后有多条数据 只取待办任务进行展示 + list.removeIf(task -> StringUtils.isNotBlank(task.getDeleteReason())); + if (CollectionUtils.isEmpty(list)) { + return AjaxResult.success(); + } + if (list.size() > 1) { + list.removeIf(task -> Objects.nonNull(task.getEndTime())); + } + HistoricActivityInstance histIns = list.get(0); + FlowTaskDto flowTask = new FlowTaskDto(); + flowTask.setTaskId(histIns.getTaskId()); + flowTask.setTaskName(histIns.getActivityName()); + flowTask.setCreateTime(histIns.getStartTime()); + flowTask.setFinishTime(histIns.getEndTime()); + if (StringUtils.isNotBlank(histIns.getAssignee())) { + SysUser sysUser = sysUserService.selectUserById(Long.parseLong(histIns.getAssignee())); + flowTask.setAssigneeId(sysUser.getUserId()); + flowTask.setAssigneeName(sysUser.getNickName()); + flowTask.setDeptName(Objects.nonNull(sysUser.getDept()) ? sysUser.getDept().getDeptName() : ""); + + } + // 流程变量信息 + // HistoricTaskInstance historicTaskInstance = + // historyService.createHistoricTaskInstanceQuery() + // .includeProcessVariables().finished().taskId(histIns.getTaskId()).singleResult(); + // flowTask.setVariables(historicTaskInstance.getProcessVariables()); + + // 展示审批人员 + List linksForTask = historyService.getHistoricIdentityLinksForTask(histIns.getTaskId()); + StringBuilder stringBuilder = new StringBuilder(); + for (HistoricIdentityLink identityLink : linksForTask) { + // 获选人,候选组/角色(多个) + if ("candidate".equals(identityLink.getType())) { + if (StringUtils.isNotBlank(identityLink.getUserId())) { + SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId())); + stringBuilder.append(sysUser.getNickName()).append(","); + } + if (StringUtils.isNotBlank(identityLink.getGroupId())) { + SysRole sysRole = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId())); + stringBuilder.append(sysRole.getRoleName()).append(","); + } + } + } + if (StringUtils.isNotBlank(stringBuilder)) { + flowTask.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1)); + } + + flowTask.setDuration(histIns.getDurationInMillis() == null || histIns.getDurationInMillis() == 0 ? null + : getDate(histIns.getDurationInMillis())); + // 获取意见评论内容 + List commentList = taskService.getProcessInstanceComments(histIns.getProcessInstanceId()); + commentList.forEach(comment -> { + if (histIns.getTaskId().equals(comment.getTaskId())) { + flowTask.setComment( + FlowCommentDto.builder().type(comment.getType()).comment(comment.getFullMessage()).build()); + } + }); + return AjaxResult.success(flowTask); + } + + /** + * 将Object类型的数据转化成Map + * + * @param obj + * @return + * @throws Exception + */ + public Map obj2Map(Object obj) throws Exception { + Map map = new HashMap(); + Field[] fields = obj.getClass().getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); + map.put(field.getName(), field.get(obj)); + } + return map; + } + + /** + * 流程完成时间处理 + * + * @param ms + * @return + */ + private String getDate(long ms) { + + long day = ms / (24 * 60 * 60 * 1000); + long hour = (ms / (60 * 60 * 1000) - day * 24); + long minute = ((ms / (60 * 1000)) - day * 24 * 60 - hour * 60); + long second = (ms / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60); + + if (day > 0) { + return day + "天" + hour + "小时" + minute + "分钟"; + } + if (hour > 0) { + return hour + "小时" + minute + "分钟"; + } + if (minute > 0) { + return minute + "分钟"; + } + if (second > 0) { + return second + "秒"; + } else { + return 0 + "秒"; + } + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/SysDeployFormServiceImpl.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/SysDeployFormServiceImpl.java new file mode 100644 index 0000000..fe581b6 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/SysDeployFormServiceImpl.java @@ -0,0 +1,106 @@ +package com.boyue.flowable.service.impl; + +import java.util.List; +import java.util.Objects; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.boyue.flowable.domain.SysDeployForm; +import com.boyue.flowable.mapper.SysDeployFormMapper; +import com.boyue.flowable.service.ISysDeployFormService; +import com.boyue.form.domain.FormTemplate; + +/** + * 流程实例关联表单Service业务层处理 + * + * @author Tony + * @date 2021-04-03 + */ +@Service +public class SysDeployFormServiceImpl implements ISysDeployFormService { + @Autowired + private SysDeployFormMapper sysDeployFormMapper; + + /** + * 查询流程实例关联表单 + * + * @param id 流程实例关联表单ID + * @return 流程实例关联表单 + */ + @Override + public SysDeployForm selectSysDeployFormById(Long id) { + return sysDeployFormMapper.selectSysDeployFormById(id); + } + + /** + * 查询流程实例关联表单列表 + * + * @param sysDeployForm 流程实例关联表单 + * @return 流程实例关联表单 + */ + @Override + public List selectSysDeployFormList(SysDeployForm sysDeployForm) { + return sysDeployFormMapper.selectSysDeployFormList(sysDeployForm); + } + + /** + * 新增流程实例关联表单 + * + * @param sysDeployForm 流程实例关联表单 + * @return 结果 + */ + @Override + public int insertSysDeployForm(SysDeployForm sysDeployForm) { + FormTemplate sysForm = sysDeployFormMapper.selectSysDeployFormByDeployId(sysDeployForm.getDeployId()); + if (Objects.isNull(sysForm)) { + return sysDeployFormMapper.insertSysDeployForm(sysDeployForm); + } else { + return updateSysDeployForm(sysDeployForm); + } + } + + /** + * 修改流程实例关联表单 + * + * @param sysDeployForm 流程实例关联表单 + * @return 结果 + */ + @Override + public int updateSysDeployForm(SysDeployForm sysDeployForm) { + return sysDeployFormMapper.updateSysDeployForm(sysDeployForm); + } + + /** + * 批量删除流程实例关联表单 + * + * @param ids 需要删除的流程实例关联表单ID + * @return 结果 + */ + @Override + public int deleteSysDeployFormByIds(Long[] ids) { + return sysDeployFormMapper.deleteSysDeployFormByIds(ids); + } + + /** + * 删除流程实例关联表单信息 + * + * @param id 流程实例关联表单ID + * @return 结果 + */ + @Override + public int deleteSysDeployFormById(Long id) { + return sysDeployFormMapper.deleteSysDeployFormById(id); + } + + /** + * 查询流程挂着的表单 + * + * @param deployId + * @return + */ + @Override + public FormTemplate selectSysDeployFormByDeployId(String deployId) { + return sysDeployFormMapper.selectSysDeployFormByDeployId(deployId); + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/SysExpressionServiceImpl.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/SysExpressionServiceImpl.java new file mode 100644 index 0000000..b7559f4 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/SysExpressionServiceImpl.java @@ -0,0 +1,98 @@ +package com.boyue.flowable.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.boyue.common.utils.DateUtils; +import com.boyue.flowable.domain.SysExpression; +import com.boyue.flowable.mapper.SysExpressionMapper; +import com.boyue.flowable.service.ISysExpressionService; + +/** + * 流程达式Service业务层处理 + * + * @author boyue + * @date 2022-12-12 + */ +@Service +public class SysExpressionServiceImpl implements ISysExpressionService +{ + @Autowired + private SysExpressionMapper sysExpressionMapper; + + /** + * 查询流程达式 + * + * @param id 流程达式主键 + * @return 流程达式 + */ + @Override + public SysExpression selectSysExpressionById(Long id) + { + return sysExpressionMapper.selectSysExpressionById(id); + } + + /** + * 查询流程达式列表 + * + * @param sysExpression 流程达式 + * @return 流程达式 + */ + @Override + public List selectSysExpressionList(SysExpression sysExpression) + { + return sysExpressionMapper.selectSysExpressionList(sysExpression); + } + + /** + * 新增流程达式 + * + * @param sysExpression 流程达式 + * @return 结果 + */ + @Override + public int insertSysExpression(SysExpression sysExpression) + { + sysExpression.setCreateTime(DateUtils.getNowDate()); + return sysExpressionMapper.insertSysExpression(sysExpression); + } + + /** + * 修改流程达式 + * + * @param sysExpression 流程达式 + * @return 结果 + */ + @Override + public int updateSysExpression(SysExpression sysExpression) + { + sysExpression.setUpdateTime(DateUtils.getNowDate()); + return sysExpressionMapper.updateSysExpression(sysExpression); + } + + /** + * 批量删除流程达式 + * + * @param ids 需要删除的流程达式主键 + * @return 结果 + */ + @Override + public int deleteSysExpressionByIds(Long[] ids) + { + return sysExpressionMapper.deleteSysExpressionByIds(ids); + } + + /** + * 删除流程达式信息 + * + * @param id 流程达式主键 + * @return 结果 + */ + @Override + public int deleteSysExpressionById(Long id) + { + return sysExpressionMapper.deleteSysExpressionById(id); + } +} diff --git a/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/SysListenerServiceImpl.java b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/SysListenerServiceImpl.java new file mode 100644 index 0000000..d961ba8 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/java/com/boyue/flowable/service/impl/SysListenerServiceImpl.java @@ -0,0 +1,98 @@ +package com.boyue.flowable.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.boyue.common.utils.DateUtils; +import com.boyue.flowable.domain.SysListener; +import com.boyue.flowable.mapper.SysListenerMapper; +import com.boyue.flowable.service.ISysListenerService; + +/** + * 流程监听Service业务层处理 + * + * @author Tony + * @date 2022-12-25 + */ +@Service +public class SysListenerServiceImpl implements ISysListenerService +{ + @Autowired + private SysListenerMapper sysListenerMapper; + + /** + * 查询流程监听 + * + * @param id 流程监听主键 + * @return 流程监听 + */ + @Override + public SysListener selectSysListenerById(Long id) + { + return sysListenerMapper.selectSysListenerById(id); + } + + /** + * 查询流程监听列表 + * + * @param sysListener 流程监听 + * @return 流程监听 + */ + @Override + public List selectSysListenerList(SysListener sysListener) + { + return sysListenerMapper.selectSysListenerList(sysListener); + } + + /** + * 新增流程监听 + * + * @param sysListener 流程监听 + * @return 结果 + */ + @Override + public int insertSysListener(SysListener sysListener) + { + sysListener.setCreateTime(DateUtils.getNowDate()); + return sysListenerMapper.insertSysListener(sysListener); + } + + /** + * 修改流程监听 + * + * @param sysListener 流程监听 + * @return 结果 + */ + @Override + public int updateSysListener(SysListener sysListener) + { + sysListener.setUpdateTime(DateUtils.getNowDate()); + return sysListenerMapper.updateSysListener(sysListener); + } + + /** + * 批量删除流程监听 + * + * @param ids 需要删除的流程监听主键 + * @return 结果 + */ + @Override + public int deleteSysListenerByIds(Long[] ids) + { + return sysListenerMapper.deleteSysListenerByIds(ids); + } + + /** + * 删除流程监听信息 + * + * @param id 流程监听主键 + * @return 结果 + */ + @Override + public int deleteSysListenerById(Long id) + { + return sysListenerMapper.deleteSysListenerById(id); + } +} diff --git a/boyue-models/boyue-flowable/src/main/resources/mapper/flowable/FlowDeployMapper.xml b/boyue-models/boyue-flowable/src/main/resources/mapper/flowable/FlowDeployMapper.xml new file mode 100644 index 0000000..b618a7f --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/resources/mapper/flowable/FlowDeployMapper.xml @@ -0,0 +1,31 @@ + + + + + + + + + \ No newline at end of file diff --git a/boyue-models/boyue-flowable/src/main/resources/mapper/flowable/SysDeployFormMapper.xml b/boyue-models/boyue-flowable/src/main/resources/mapper/flowable/SysDeployFormMapper.xml new file mode 100644 index 0000000..7808479 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/resources/mapper/flowable/SysDeployFormMapper.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + select id, form_id, deploy_id from sys_deploy_form + + + + + + + + + + insert into sys_deploy_form + + form_id, + deploy_id, + + + #{formId}, + #{deployId}, + + + + + update sys_deploy_form + + + form_id = #{formId}, + deploy_id = #{deployId}, + + where id = #{id} + + + + form_id = #{formId}, + + where deploy_id = #{deployId} + + + + + delete from sys_deploy_form where id = #{id} + + + + delete from sys_deploy_form where id in + + #{id} + + + \ No newline at end of file diff --git a/boyue-models/boyue-flowable/src/main/resources/mapper/flowable/SysExpressionMapper.xml b/boyue-models/boyue-flowable/src/main/resources/mapper/flowable/SysExpressionMapper.xml new file mode 100644 index 0000000..30e011b --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/resources/mapper/flowable/SysExpressionMapper.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + select id, name, expression, data_type,create_time, update_time, create_by, update_by, status, remark from sys_expression + + + + + + + + insert into sys_expression + + name, + expression, + data_type, + create_time, + update_time, + create_by, + update_by, + status, + remark, + + + #{name}, + #{expression}, + #{dataType}, + #{createTime}, + #{updateTime}, + #{createBy}, + #{updateBy}, + #{status}, + #{remark}, + + + + + update sys_expression + + name = #{name}, + expression = #{expression}, + data_type = #{dataType}, + create_time = #{createTime}, + update_time = #{updateTime}, + create_by = #{createBy}, + update_by = #{updateBy}, + status = #{status}, + remark = #{remark}, + + where id = #{id} + + + + delete from sys_expression where id = #{id} + + + + delete from sys_expression where id in + + #{id} + + + diff --git a/boyue-models/boyue-flowable/src/main/resources/mapper/flowable/SysListenerMapper.xml b/boyue-models/boyue-flowable/src/main/resources/mapper/flowable/SysListenerMapper.xml new file mode 100644 index 0000000..ef5f836 --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/resources/mapper/flowable/SysListenerMapper.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + select id, + name, + type, + event_type, + value_type, + value, + create_time, + update_time, + create_by, + update_by, + status, + remark + from sys_listener + + + + + + + + insert into sys_listener + + name, + type, + event_type, + value_type, + value, + create_time, + update_time, + create_by, + update_by, + status, + remark, + + + #{name}, + #{type}, + #{eventType}, + #{valueType}, + #{value}, + #{createTime}, + #{updateTime}, + #{createBy}, + #{updateBy}, + #{status}, + #{remark}, + + + + + update sys_listener + + name = #{name}, + type = #{type}, + event_type = #{eventType}, + value_type = #{valueType}, + value = #{value}, + create_time = #{createTime}, + update_time = #{updateTime}, + create_by = #{createBy}, + update_by = #{updateBy}, + status = #{status}, + remark = #{remark}, + + where id = #{id} + + + + delete + from sys_listener + where id = #{id} + + + + delete from sys_listener where id in + + #{id} + + + \ No newline at end of file diff --git a/boyue-models/boyue-flowable/src/main/resources/mapper/flowable/SysTaskFormMapper.xml b/boyue-models/boyue-flowable/src/main/resources/mapper/flowable/SysTaskFormMapper.xml new file mode 100644 index 0000000..e525c2e --- /dev/null +++ b/boyue-models/boyue-flowable/src/main/resources/mapper/flowable/SysTaskFormMapper.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + select id, form_id, task_id from sys_task_form + + + + + + + + insert into sys_task_form + + form_id, + task_id, + + + #{formId}, + #{taskId}, + + + + + update sys_task_form + + form_id = #{formId}, + task_id = #{taskId}, + + where id = #{id} + + + + delete from sys_task_form where id = #{id} + + + + delete from sys_task_form where id in + + #{id} + + + \ No newline at end of file diff --git a/boyue-models/boyue-form/pom.xml b/boyue-models/boyue-form/pom.xml new file mode 100644 index 0000000..075dbf3 --- /dev/null +++ b/boyue-models/boyue-form/pom.xml @@ -0,0 +1,27 @@ + + + + boyue-models + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-form + + + form表单 + + + + + + + com.boyue + boyue-common + + + + + \ No newline at end of file diff --git a/boyue-models/boyue-form/src/main/java/com/boyue/form/controller/FormDataController.java b/boyue-models/boyue-form/src/main/java/com/boyue/form/controller/FormDataController.java new file mode 100644 index 0000000..fd5ac59 --- /dev/null +++ b/boyue-models/boyue-form/src/main/java/com/boyue/form/controller/FormDataController.java @@ -0,0 +1,118 @@ +package com.boyue.form.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.form.domain.FormData; +import com.boyue.form.service.IFormDataService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 单数据Controller + * + * @author boyue + * @date 2025-05-12 + */ +@RestController +@RequestMapping("/form/data") +@Tag(name = "【单数据】管理") +public class FormDataController extends BaseController +{ + @Autowired + private IFormDataService formDataService; + + /** + * 查询单数据列表 + */ + @Operation(summary = "查询单数据列表") + @PreAuthorize("@ss.hasPermi('form:data:list')") + @GetMapping("/list") + public TableDataInfo list(FormData formData) + { + startPage(); + List list = formDataService.selectFormDataList(formData); + return getDataTable(list); + } + + /** + * 导出单数据列表 + */ + @Operation(summary = "导出单数据列表") + @PreAuthorize("@ss.hasPermi('form:data:export')") + @Log(title = "单数据", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, FormData formData) + { + List list = formDataService.selectFormDataList(formData); + ExcelUtil util = new ExcelUtil(FormData.class); + util.exportExcel(response, list, "单数据数据"); + } + + /** + * 获取单数据详细信息 + */ + @Operation(summary = "获取单数据详细信息") + @PreAuthorize("@ss.hasPermi('form:data:query')") + @GetMapping(value = "/{dataId}") + public AjaxResult getInfo(@PathVariable("dataId") Long dataId) + { + return success(formDataService.selectFormDataByDataId(dataId)); + } + + /** + * 新增单数据 + */ + @Operation(summary = "新增单数据") + @PreAuthorize("@ss.hasPermi('form:data:add')") + @Log(title = "单数据", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody FormData formData) + { + formData.setCreateBy(getUsername()); + return toAjax(formDataService.insertFormData(formData)); + } + + /** + * 修改单数据 + */ + @Operation(summary = "修改单数据") + @PreAuthorize("@ss.hasPermi('form:data:edit')") + @Log(title = "单数据", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody FormData formData) + { + formData.setUpdateBy(getUsername()); + return toAjax(formDataService.updateFormData(formData)); + } + + /** + * 删除单数据 + */ + @Operation(summary = "删除单数据") + @PreAuthorize("@ss.hasPermi('form:data:remove')") + @Log(title = "单数据", businessType = BusinessType.DELETE) + @DeleteMapping("/{dataIds}") + public AjaxResult remove(@PathVariable( name = "dataIds" ) Long[] dataIds) + { + return toAjax(formDataService.deleteFormDataByDataIds(dataIds)); + } +} diff --git a/boyue-models/boyue-form/src/main/java/com/boyue/form/controller/FormTemplateController.java b/boyue-models/boyue-form/src/main/java/com/boyue/form/controller/FormTemplateController.java new file mode 100644 index 0000000..c2f939f --- /dev/null +++ b/boyue-models/boyue-form/src/main/java/com/boyue/form/controller/FormTemplateController.java @@ -0,0 +1,113 @@ +package com.boyue.form.controller; + +import java.util.List; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.enums.BusinessType; +import com.boyue.form.domain.FormTemplate; +import com.boyue.form.service.IFormTemplateService; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.common.core.page.TableDataInfo; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; + +/** + * 单模板Controller + * + * @author boyue + * @date 2025-05-12 + */ +@RestController +@RequestMapping("/form/template") +@Tag(name = "【单模板】管理") +public class FormTemplateController extends BaseController +{ + @Autowired + private IFormTemplateService formTemplateService; + + /** + * 查询单模板列表 + */ + @Operation(summary = "查询单模板列表") + @PreAuthorize("@ss.hasPermi('form:template:list')") + @GetMapping("/list") + public TableDataInfo list(FormTemplate formTemplate) + { + startPage(); + List list = formTemplateService.selectFormTemplateList(formTemplate); + return getDataTable(list); + } + + /** + * 导出单模板列表 + */ + @Operation(summary = "导出单模板列表") + @PreAuthorize("@ss.hasPermi('form:template:export')") + @Log(title = "单模板", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, FormTemplate formTemplate) + { + List list = formTemplateService.selectFormTemplateList(formTemplate); + ExcelUtil util = new ExcelUtil(FormTemplate.class); + util.exportExcel(response, list, "单模板数据"); + } + + /** + * 获取单模板详细信息 + */ + @Operation(summary = "获取单模板详细信息") + @PreAuthorize("@ss.hasPermi('form:template:query')") + @GetMapping(value = "/{formId}") + public AjaxResult getInfo(@PathVariable("formId") Long formId) + { + return success(formTemplateService.selectFormTemplateByFormId(formId)); + } + + /** + * 新增单模板 + */ + @Operation(summary = "新增单模板") + @PreAuthorize("@ss.hasPermi('form:template:add')") + @Log(title = "单模板", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody FormTemplate formTemplate) + { + return toAjax(formTemplateService.insertFormTemplate(formTemplate)); + } + + /** + * 修改单模板 + */ + @Operation(summary = "修改单模板") + @PreAuthorize("@ss.hasPermi('form:template:edit')") + @Log(title = "单模板", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody FormTemplate formTemplate) + { + return toAjax(formTemplateService.updateFormTemplate(formTemplate)); + } + + /** + * 删除单模板 + */ + @Operation(summary = "删除单模板") + @PreAuthorize("@ss.hasPermi('form:template:remove')") + @Log(title = "单模板", businessType = BusinessType.DELETE) + @DeleteMapping("/{formIds}") + public AjaxResult remove(@PathVariable( name = "formIds" ) Long[] formIds) + { + return toAjax(formTemplateService.deleteFormTemplateByFormIds(formIds)); + } +} diff --git a/boyue-models/boyue-form/src/main/java/com/boyue/form/domain/FormData.java b/boyue-models/boyue-form/src/main/java/com/boyue/form/domain/FormData.java new file mode 100644 index 0000000..3e03d92 --- /dev/null +++ b/boyue-models/boyue-form/src/main/java/com/boyue/form/domain/FormData.java @@ -0,0 +1,140 @@ +package com.boyue.form.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 单数据对象 form_data + * + * @author boyue + * @date 2025-05-12 + */ +@Schema(description = "单数据对象") +public class FormData extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** 数据ID */ + @Schema(title = "数据ID") + private Long dataId; + + /** 关联的表单ID */ + @Schema(title = "关联的表单ID") + @Excel(name = "关联的表单ID") + private Long formId; + + /** 表单版本(与模板表版本一致) */ + @Schema(title = "表单版本(与模板表版本一致)") + @Excel(name = "表单版本", readConverterExp = "与=模板表版本一致") + private String formVersion; + + /** 表单数据内容(JSON格式) */ + @Schema(title = "表单数据内容(JSON格式)") + @Excel(name = "表单数据内容", readConverterExp = "J=SON格式") + private String dataContent; + + /** 数据状态(draft, submitted, approved, rejected) */ + @Schema(title = "数据状态(draft, submitted, approved, rejected)") + @Excel(name = "数据状态", readConverterExp = "d=raft,,s=ubmitted,,a=pproved,,r=ejected") + private String status; + + /** 删除标志(0代表存在 2代表删除) */ + @Schema(title = "删除标志(0代表存在 2代表删除)") + private String delFlag; + + /** 表单名称 */ + @Schema(title = "表单名称") + @Excel(name = "表单名称") + private String formName; + + /** 表单JSON Schema(vForm配置) */ + @Schema(title = "表单JSON Schema(vForm配置)") + @Excel(name = "表单JSON Schema", readConverterExp = "v=Form配置") + private String formSchema; + + public void setDataId(Long dataId) { + this.dataId = dataId; + } + + public Long getDataId() { + return dataId; + } + + public String getFormSchema() { + return formSchema; + } + + public void setFormSchema(String formSchema) { + this.formSchema = formSchema; + } + + public void setFormId(Long formId) { + this.formId = formId; + } + + public Long getFormId() { + return formId; + } + + public void setFormVersion(String formVersion) { + this.formVersion = formVersion; + } + + public String getFormVersion() { + return formVersion; + } + + public void setDataContent(String dataContent) { + this.dataContent = dataContent; + } + + public String getDataContent() { + return dataContent; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getStatus() { + return status; + } + + public void setDelFlag(String delFlag) { + this.delFlag = delFlag; + } + + public String getDelFlag() { + return delFlag; + } + + public void setFormName(String formName) { + this.formName = formName; + } + + public String getFormName() { + return formName; + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("dataId", getDataId()) + .append("formId", getFormId()) + .append("formVersion", getFormVersion()) + .append("dataContent", getDataContent()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .append("delFlag", getDelFlag()) + .append("formName", getFormName()) + .toString(); + } +} diff --git a/boyue-models/boyue-form/src/main/java/com/boyue/form/domain/FormTemplate.java b/boyue-models/boyue-form/src/main/java/com/boyue/form/domain/FormTemplate.java new file mode 100644 index 0000000..c485f4a --- /dev/null +++ b/boyue-models/boyue-form/src/main/java/com/boyue/form/domain/FormTemplate.java @@ -0,0 +1,131 @@ +package com.boyue.form.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.boyue.common.annotation.Excel; +import com.boyue.common.core.domain.BaseEntity; + +/** + * 单模板对象 form_template + * + * @author boyue + * @date 2025-05-12 + */ +@Schema(description = "单模板对象") +public class FormTemplate extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + + /** 表单ID */ + @Schema(title = "表单ID") + private Long formId; + + /** 表单名称 */ + @Schema(title = "表单名称") + @Excel(name = "表单名称") + private String formName; + + /** 表单JSON Schema(vForm配置) */ + @Schema(title = "表单JSON Schema(vForm配置)") + @Excel(name = "表单JSON Schema", readConverterExp = "v=Form配置") + private String formSchema; + + /** 表单版本(语义化版本) */ + @Schema(title = "表单版本(语义化版本)") + @Excel(name = "表单版本", readConverterExp = "语=义化版本") + private String formVersion; + + /** 发布状态(0: 草稿, 1: 已发布, 2: 已停用) */ + @Schema(title = "发布状态(0: 草稿, 1: 已发布, 2: 已停用)") + @Excel(name = "发布状态", readConverterExp = "0=:,草=稿,,1=:,已=发布,,2=:,已=停用") + private String formStatus; + + /** 删除标志(0代表存在 2代表删除) */ + @Schema(title = "删除标志(0代表存在 2代表删除)") + private String delFlag; + public void setFormId(Long formId) + { + this.formId = formId; + } + + public Long getFormId() + { + return formId; + } + + + public void setFormName(String formName) + { + this.formName = formName; + } + + public String getFormName() + { + return formName; + } + + + public void setFormSchema(String formSchema) + { + this.formSchema = formSchema; + } + + public String getFormSchema() + { + return formSchema; + } + + + public void setFormVersion(String formVersion) + { + this.formVersion = formVersion; + } + + public String getFormVersion() + { + return formVersion; + } + + + public void setFormStatus(String formStatus) + { + this.formStatus = formStatus; + } + + public String getFormStatus() + { + return formStatus; + } + + + public void setDelFlag(String delFlag) + { + this.delFlag = delFlag; + } + + public String getDelFlag() + { + return delFlag; + } + + + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("formId", getFormId()) + .append("formName", getFormName()) + .append("formSchema", getFormSchema()) + .append("formVersion", getFormVersion()) + .append("formStatus", getFormStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .append("delFlag", getDelFlag()) + .toString(); + } +} diff --git a/boyue-models/boyue-form/src/main/java/com/boyue/form/mapper/FormDataMapper.java b/boyue-models/boyue-form/src/main/java/com/boyue/form/mapper/FormDataMapper.java new file mode 100644 index 0000000..80884ce --- /dev/null +++ b/boyue-models/boyue-form/src/main/java/com/boyue/form/mapper/FormDataMapper.java @@ -0,0 +1,61 @@ +package com.boyue.form.mapper; + +import java.util.List; +import com.boyue.form.domain.FormData; + +/** + * 单数据Mapper接口 + * + * @author boyue + * @date 2025-05-12 + */ +public interface FormDataMapper +{ + /** + * 查询单数据 + * + * @param dataId 单数据主键 + * @return 单数据 + */ + public FormData selectFormDataByDataId(Long dataId); + + /** + * 查询单数据列表 + * + * @param formData 单数据 + * @return 单数据集合 + */ + public List selectFormDataList(FormData formData); + + /** + * 新增单数据 + * + * @param formData 单数据 + * @return 结果 + */ + public int insertFormData(FormData formData); + + /** + * 修改单数据 + * + * @param formData 单数据 + * @return 结果 + */ + public int updateFormData(FormData formData); + + /** + * 删除单数据 + * + * @param dataId 单数据主键 + * @return 结果 + */ + public int deleteFormDataByDataId(Long dataId); + + /** + * 批量删除单数据 + * + * @param dataIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteFormDataByDataIds(Long[] dataIds); +} diff --git a/boyue-models/boyue-form/src/main/java/com/boyue/form/mapper/FormTemplateMapper.java b/boyue-models/boyue-form/src/main/java/com/boyue/form/mapper/FormTemplateMapper.java new file mode 100644 index 0000000..0190635 --- /dev/null +++ b/boyue-models/boyue-form/src/main/java/com/boyue/form/mapper/FormTemplateMapper.java @@ -0,0 +1,61 @@ +package com.boyue.form.mapper; + +import java.util.List; +import com.boyue.form.domain.FormTemplate; + +/** + * 单模板Mapper接口 + * + * @author boyue + * @date 2025-05-12 + */ +public interface FormTemplateMapper +{ + /** + * 查询单模板 + * + * @param formId 单模板主键 + * @return 单模板 + */ + public FormTemplate selectFormTemplateByFormId(Long formId); + + /** + * 查询单模板列表 + * + * @param formTemplate 单模板 + * @return 单模板集合 + */ + public List selectFormTemplateList(FormTemplate formTemplate); + + /** + * 新增单模板 + * + * @param formTemplate 单模板 + * @return 结果 + */ + public int insertFormTemplate(FormTemplate formTemplate); + + /** + * 修改单模板 + * + * @param formTemplate 单模板 + * @return 结果 + */ + public int updateFormTemplate(FormTemplate formTemplate); + + /** + * 删除单模板 + * + * @param formId 单模板主键 + * @return 结果 + */ + public int deleteFormTemplateByFormId(Long formId); + + /** + * 批量删除单模板 + * + * @param formIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteFormTemplateByFormIds(Long[] formIds); +} diff --git a/boyue-models/boyue-form/src/main/java/com/boyue/form/service/IFormDataService.java b/boyue-models/boyue-form/src/main/java/com/boyue/form/service/IFormDataService.java new file mode 100644 index 0000000..a4e5718 --- /dev/null +++ b/boyue-models/boyue-form/src/main/java/com/boyue/form/service/IFormDataService.java @@ -0,0 +1,61 @@ +package com.boyue.form.service; + +import java.util.List; +import com.boyue.form.domain.FormData; + +/** + * 单数据Service接口 + * + * @author boyue + * @date 2025-05-12 + */ +public interface IFormDataService +{ + /** + * 查询单数据 + * + * @param dataId 单数据主键 + * @return 单数据 + */ + public FormData selectFormDataByDataId(Long dataId); + + /** + * 查询单数据列表 + * + * @param formData 单数据 + * @return 单数据集合 + */ + public List selectFormDataList(FormData formData); + + /** + * 新增单数据 + * + * @param formData 单数据 + * @return 结果 + */ + public int insertFormData(FormData formData); + + /** + * 修改单数据 + * + * @param formData 单数据 + * @return 结果 + */ + public int updateFormData(FormData formData); + + /** + * 批量删除单数据 + * + * @param dataIds 需要删除的单数据主键集合 + * @return 结果 + */ + public int deleteFormDataByDataIds(Long[] dataIds); + + /** + * 删除单数据信息 + * + * @param dataId 单数据主键 + * @return 结果 + */ + public int deleteFormDataByDataId(Long dataId); +} diff --git a/boyue-models/boyue-form/src/main/java/com/boyue/form/service/IFormTemplateService.java b/boyue-models/boyue-form/src/main/java/com/boyue/form/service/IFormTemplateService.java new file mode 100644 index 0000000..ecc6f05 --- /dev/null +++ b/boyue-models/boyue-form/src/main/java/com/boyue/form/service/IFormTemplateService.java @@ -0,0 +1,61 @@ +package com.boyue.form.service; + +import java.util.List; +import com.boyue.form.domain.FormTemplate; + +/** + * 单模板Service接口 + * + * @author boyue + * @date 2025-05-12 + */ +public interface IFormTemplateService +{ + /** + * 查询单模板 + * + * @param formId 单模板主键 + * @return 单模板 + */ + public FormTemplate selectFormTemplateByFormId(Long formId); + + /** + * 查询单模板列表 + * + * @param formTemplate 单模板 + * @return 单模板集合 + */ + public List selectFormTemplateList(FormTemplate formTemplate); + + /** + * 新增单模板 + * + * @param formTemplate 单模板 + * @return 结果 + */ + public int insertFormTemplate(FormTemplate formTemplate); + + /** + * 修改单模板 + * + * @param formTemplate 单模板 + * @return 结果 + */ + public int updateFormTemplate(FormTemplate formTemplate); + + /** + * 批量删除单模板 + * + * @param formIds 需要删除的单模板主键集合 + * @return 结果 + */ + public int deleteFormTemplateByFormIds(Long[] formIds); + + /** + * 删除单模板信息 + * + * @param formId 单模板主键 + * @return 结果 + */ + public int deleteFormTemplateByFormId(Long formId); +} diff --git a/boyue-models/boyue-form/src/main/java/com/boyue/form/service/impl/FormDataServiceImpl.java b/boyue-models/boyue-form/src/main/java/com/boyue/form/service/impl/FormDataServiceImpl.java new file mode 100644 index 0000000..50abb44 --- /dev/null +++ b/boyue-models/boyue-form/src/main/java/com/boyue/form/service/impl/FormDataServiceImpl.java @@ -0,0 +1,96 @@ +package com.boyue.form.service.impl; + +import java.util.List; +import com.boyue.common.utils.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.boyue.form.mapper.FormDataMapper; +import com.boyue.form.domain.FormData; +import com.boyue.form.service.IFormDataService; + +/** + * 单数据Service业务层处理 + * + * @author boyue + * @date 2025-05-12 + */ +@Service +public class FormDataServiceImpl implements IFormDataService +{ + @Autowired + private FormDataMapper formDataMapper; + + /** + * 查询单数据 + * + * @param dataId 单数据主键 + * @return 单数据 + */ + @Override + public FormData selectFormDataByDataId(Long dataId) + { + return formDataMapper.selectFormDataByDataId(dataId); + } + + /** + * 查询单数据列表 + * + * @param formData 单数据 + * @return 单数据 + */ + @Override + public List selectFormDataList(FormData formData) + { + return formDataMapper.selectFormDataList(formData); + } + + /** + * 新增单数据 + * + * @param formData 单数据 + * @return 结果 + */ + @Override + public int insertFormData(FormData formData) + { + formData.setCreateTime(DateUtils.getNowDate()); + return formDataMapper.insertFormData(formData); + } + + /** + * 修改单数据 + * + * @param formData 单数据 + * @return 结果 + */ + @Override + public int updateFormData(FormData formData) + { + formData.setUpdateTime(DateUtils.getNowDate()); + return formDataMapper.updateFormData(formData); + } + + /** + * 批量删除单数据 + * + * @param dataIds 需要删除的单数据主键 + * @return 结果 + */ + @Override + public int deleteFormDataByDataIds(Long[] dataIds) + { + return formDataMapper.deleteFormDataByDataIds(dataIds); + } + + /** + * 删除单数据信息 + * + * @param dataId 单数据主键 + * @return 结果 + */ + @Override + public int deleteFormDataByDataId(Long dataId) + { + return formDataMapper.deleteFormDataByDataId(dataId); + } +} diff --git a/boyue-models/boyue-form/src/main/java/com/boyue/form/service/impl/FormTemplateServiceImpl.java b/boyue-models/boyue-form/src/main/java/com/boyue/form/service/impl/FormTemplateServiceImpl.java new file mode 100644 index 0000000..ba73d5d --- /dev/null +++ b/boyue-models/boyue-form/src/main/java/com/boyue/form/service/impl/FormTemplateServiceImpl.java @@ -0,0 +1,96 @@ +package com.boyue.form.service.impl; + +import java.util.List; +import com.boyue.common.utils.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.boyue.form.mapper.FormTemplateMapper; +import com.boyue.form.domain.FormTemplate; +import com.boyue.form.service.IFormTemplateService; + +/** + * 单模板Service业务层处理 + * + * @author boyue + * @date 2025-05-12 + */ +@Service +public class FormTemplateServiceImpl implements IFormTemplateService +{ + @Autowired + private FormTemplateMapper formTemplateMapper; + + /** + * 查询单模板 + * + * @param formId 单模板主键 + * @return 单模板 + */ + @Override + public FormTemplate selectFormTemplateByFormId(Long formId) + { + return formTemplateMapper.selectFormTemplateByFormId(formId); + } + + /** + * 查询单模板列表 + * + * @param formTemplate 单模板 + * @return 单模板 + */ + @Override + public List selectFormTemplateList(FormTemplate formTemplate) + { + return formTemplateMapper.selectFormTemplateList(formTemplate); + } + + /** + * 新增单模板 + * + * @param formTemplate 单模板 + * @return 结果 + */ + @Override + public int insertFormTemplate(FormTemplate formTemplate) + { + formTemplate.setCreateTime(DateUtils.getNowDate()); + return formTemplateMapper.insertFormTemplate(formTemplate); + } + + /** + * 修改单模板 + * + * @param formTemplate 单模板 + * @return 结果 + */ + @Override + public int updateFormTemplate(FormTemplate formTemplate) + { + formTemplate.setUpdateTime(DateUtils.getNowDate()); + return formTemplateMapper.updateFormTemplate(formTemplate); + } + + /** + * 批量删除单模板 + * + * @param formIds 需要删除的单模板主键 + * @return 结果 + */ + @Override + public int deleteFormTemplateByFormIds(Long[] formIds) + { + return formTemplateMapper.deleteFormTemplateByFormIds(formIds); + } + + /** + * 删除单模板信息 + * + * @param formId 单模板主键 + * @return 结果 + */ + @Override + public int deleteFormTemplateByFormId(Long formId) + { + return formTemplateMapper.deleteFormTemplateByFormId(formId); + } +} diff --git a/boyue-models/boyue-form/src/main/resources/mapper/form/FormDataMapper.xml b/boyue-models/boyue-form/src/main/resources/mapper/form/FormDataMapper.xml new file mode 100644 index 0000000..5ac84c2 --- /dev/null +++ b/boyue-models/boyue-form/src/main/resources/mapper/form/FormDataMapper.xml @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + select + fd.data_id, + fd.form_id, + fd.form_version, + fd.data_content, + fd.status, + fd.create_by, + fd.create_time, + fd.update_by, + fd.update_time, + fd.remark, + fd.del_flag, + ft.form_name + from form_data fd + left join form_template ft on ft.form_id = fd.form_id + left join sys_user su on su.user_name = fd.create_by + + + + + + + + insert into form_data + + form_id, + form_version, + data_content, + status, + create_by, + create_time, + update_by, + update_time, + remark, + del_flag, + + + #{formId}, + #{formVersion}, + #{dataContent}, + #{status}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + #{delFlag}, + + + + + update form_data + + form_id = #{formId}, + form_version = #{formVersion}, + data_content = #{dataContent}, + status = #{status}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + del_flag = #{delFlag}, + + where form_data.data_id = #{dataId} + + + + delete from form_data where data_id = #{dataId} + + + + delete from form_data where data_id in + + #{dataId} + + + \ No newline at end of file diff --git a/boyue-models/boyue-form/src/main/resources/mapper/form/FormTemplateMapper.xml b/boyue-models/boyue-form/src/main/resources/mapper/form/FormTemplateMapper.xml new file mode 100644 index 0000000..183dde2 --- /dev/null +++ b/boyue-models/boyue-form/src/main/resources/mapper/form/FormTemplateMapper.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + select + ft.form_id, + ft.form_name, + ft.form_schema, + ft.form_version, + ft.form_status, + ft.create_by, + ft.create_time, + ft.update_by, + ft.update_time, + ft.remark, + ft.del_flag + from form_template ft + left join sys_user su on su.user_name = ft.create_by + + + + + + + + insert into form_template + + form_name, + form_schema, + form_version, + form_status, + create_by, + create_time, + update_by, + update_time, + remark, + del_flag, + + + #{formName}, + #{formSchema}, + #{formVersion}, + #{formStatus}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + #{delFlag}, + + + + + update form_template + + form_name = #{formName}, + form_schema = #{formSchema}, + form_version = #{formVersion}, + form_status = #{formStatus}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + del_flag = #{delFlag}, + + where form_template.form_id = #{formId} + + + + delete from form_template where form_id = #{formId} + + + + delete from form_template where form_id in + + #{formId} + + + \ No newline at end of file diff --git a/boyue-models/boyue-generator/pom.xml b/boyue-models/boyue-generator/pom.xml new file mode 100644 index 0000000..883ed79 --- /dev/null +++ b/boyue-models/boyue-generator/pom.xml @@ -0,0 +1,40 @@ + + + + boyue-models + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-generator + + + generator代码生成 + + + + + + + org.apache.velocity + velocity-engine-core + + + + + com.boyue + boyue-common + + + + + com.alibaba + druid-spring-boot-3-starter + + + + + \ No newline at end of file diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/config/GenConfig.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/config/GenConfig.java new file mode 100644 index 0000000..77a3ca9 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/config/GenConfig.java @@ -0,0 +1,73 @@ +package com.boyue.generator.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +/** + * 读取代码生成相关配置 + * + * @author boyue + */ +@Component +@ConfigurationProperties(prefix = "gen") +@PropertySource(value = { "classpath:generator.yml" }) +public class GenConfig +{ + /** 作者 */ + public static String author; + + /** 生成包路径 */ + public static String packageName; + + /** 自动去除表前缀,默认是false */ + public static boolean autoRemovePre; + + /** 表前缀(类名不会包含表前缀) */ + public static String tablePrefix; + + public static String getAuthor() + { + return author; + } + + @Value("${author}") + public void setAuthor(String author) + { + GenConfig.author = author; + } + + public static String getPackageName() + { + return packageName; + } + + @Value("${packageName}") + public void setPackageName(String packageName) + { + GenConfig.packageName = packageName; + } + + public static boolean getAutoRemovePre() + { + return autoRemovePre; + } + + @Value("${autoRemovePre}") + public void setAutoRemovePre(boolean autoRemovePre) + { + GenConfig.autoRemovePre = autoRemovePre; + } + + public static String getTablePrefix() + { + return tablePrefix; + } + + @Value("${tablePrefix}") + public void setTablePrefix(String tablePrefix) + { + GenConfig.tablePrefix = tablePrefix; + } +} diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/constant/GenConstants.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/constant/GenConstants.java new file mode 100644 index 0000000..d742fac --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/constant/GenConstants.java @@ -0,0 +1,129 @@ +package com.boyue.generator.constant; + +/** + * 代码生成通用常量 + * + * @author boyue + */ +public class GenConstants +{ + /** 单表(增删改查) */ + public static final String TPL_CRUD = "crud"; + + /** 树表(增删改查) */ + public static final String TPL_TREE = "tree"; + + /** 主子表(增删改查) */ + public static final String TPL_SUB = "sub"; + + /** 树编码字段 */ + public static final String TREE_CODE = "treeCode"; + + /** 树父编码字段 */ + public static final String TREE_PARENT_CODE = "treeParentCode"; + + /** 树名称字段 */ + public static final String TREE_NAME = "treeName"; + + /** 上级菜单ID字段 */ + public static final String PARENT_MENU_ID = "parentMenuId"; + + /** 上级菜单名称字段 */ + public static final String PARENT_MENU_NAME = "parentMenuName"; + + /** 数据库字符串类型 */ + public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2" }; + + /** 数据库文本类型 */ + public static final String[] COLUMNTYPE_TEXT = { "tinytext", "text", "mediumtext", "longtext" }; + + /** 数据库时间类型 */ + public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" }; + + /** 数据库数字类型 */ + public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer", + "bit", "bigint", "float", "double", "decimal" }; + + /** 页面不需要编辑字段 */ + public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" }; + + /** 页面不需要显示的列表字段 */ + public static final String[] COLUMNNAME_NOT_LIST = { "id", "create_by", "create_time", "del_flag", "update_by", + "update_time" }; + + /** 页面不需要查询字段 */ + public static final String[] COLUMNNAME_NOT_QUERY = { "id", "create_by", "create_time", "del_flag", "update_by", + "update_time", "remark" }; + + /** Entity基类字段 */ + public static final String[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" }; + + /** Tree基类字段 */ + public static final String[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors", "children" }; + + /** 文本框 */ + public static final String HTML_INPUT = "input"; + + /** 文本域 */ + public static final String HTML_TEXTAREA = "textarea"; + + /** 下拉框 */ + public static final String HTML_SELECT = "select"; + + /** 单选框 */ + public static final String HTML_RADIO = "radio"; + + /** 复选框 */ + public static final String HTML_CHECKBOX = "checkbox"; + + /** 日期控件 */ + public static final String HTML_DATE = "date"; + + /** 时间控件 */ + public static final String HTML_TIME = "time"; + + /** 日期时间控件 */ + public static final String HTML_DATETIME = "datetime"; + + /** 图片上传控件 */ + public static final String HTML_IMAGE_UPLOAD = "imageUpload"; + + /** 文件上传控件 */ + public static final String HTML_FILE_UPLOAD = "fileUpload"; + + /** 富文本控件 */ + public static final String HTML_EDITOR = "editor"; + + /** 字符串类型 */ + public static final String TYPE_STRING = "String"; + + /** 整型 */ + public static final String TYPE_INTEGER = "Integer"; + + /** 长整型 */ + public static final String TYPE_LONG = "Long"; + + /** 浮点型 */ + public static final String TYPE_DOUBLE = "Double"; + + /** 高精度计算类型 */ + public static final String TYPE_BIGDECIMAL = "BigDecimal"; + + /** 日期类型 */ + public static final String TYPE_DATE = "LocalDate"; + + /** 时间类型 */ + public static final String TYPE_TIME = "LocalTime"; + + /** 日期时间类型 */ + public static final String TYPE_DATETIME = "LocalDateTime"; + + /** 模糊查询 */ + public static final String QUERY_LIKE = "LIKE"; + + /** 相等查询 */ + public static final String QUERY_EQ = "EQ"; + + /** 需要 */ + public static final String REQUIRE = "1"; +} diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/controller/GenController.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/controller/GenController.java new file mode 100644 index 0000000..6555fb2 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/controller/GenController.java @@ -0,0 +1,267 @@ +package com.boyue.generator.controller; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.alibaba.druid.DbType; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.core.text.Convert; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.sql.SqlUtil; +import com.boyue.generator.domain.GenJoinTable; +import com.boyue.generator.domain.GenTable; +import com.boyue.generator.domain.GenTableColumn; +import com.boyue.generator.domain.vo.GenTableVo; +import com.boyue.generator.service.IGenJoinTableService; +import com.boyue.generator.service.IGenTableColumnService; +import com.boyue.generator.service.IGenTableService; + +import jakarta.servlet.http.HttpServletResponse; + +/** + * 代码生成 操作处理 + * + * @author boyue + */ +@RestController +@RequestMapping("/tool/gen") +public class GenController extends BaseController { + @Autowired + private IGenTableService genTableService; + + @Autowired + private IGenTableColumnService genTableColumnService; + + @Autowired + private IGenJoinTableService genJoinTableService; + + /** + * 查询代码生成列表 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:list')") + @GetMapping("/list") + public TableDataInfo genList(GenTable genTable) { + startPage(); + List list = genTableService.selectGenTableList(genTable); + return getDataTable(list); + } + + /** + * 修改代码生成业务 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:query')") + @GetMapping(value = "/{tableId}") + public AjaxResult getInfo(@PathVariable(name = "tableId") Long tableId) { + GenTable table = genTableService.selectGenTableById(tableId); + GenTableVo genTableVo = new GenTableVo(); + genTableVo.setTable(table); + genTableVo.setColumns(table.getColumns()); + GenJoinTable genJoinTable = new GenJoinTable(); + genJoinTable.setTableId(tableId); + List selectGenJoinTableList = genJoinTableService.selectGenJoinTableList(genJoinTable); + genTableVo.setJoinTablesMate(selectGenJoinTableList); + Map joinTableMap = new HashMap(); + joinTableMap.put(tableId, table); + selectGenJoinTableList.forEach(i -> { + if(Objects.isNull(joinTableMap.get(i.getLeftTableId()))) { + joinTableMap.put(i.getLeftTableId(), genTableService.selectGenTableById(i.getLeftTableId())); + } + if(Objects.isNull(joinTableMap.get(i.getRightTableId()))) { + joinTableMap.put(i.getRightTableId(), genTableService.selectGenTableById(i.getRightTableId())); + } + }); + genTableVo.setJoinTables(joinTableMap.values()); + return success(genTableVo); + } + + /** + * 查询数据库列表 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:list')") + @GetMapping("/db/list") + public TableDataInfo dataList(GenTable genTable) { + startPage(); + List list = genTableService.selectDbTableList(genTable); + return getDataTable(list); + } + + /** + * 查询数据表字段列表 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:list')") + @GetMapping(value = "/column/{tableId}") + public TableDataInfo columnList(@PathVariable(name = "tableId") Long tableId) { + TableDataInfo dataInfo = new TableDataInfo(); + List list = genTableColumnService.selectGenTableColumnListByTableId(tableId); + dataInfo.setRows(list); + dataInfo.setTotal(list.size()); + return dataInfo; + } + + /** + * 导入表结构(保存) + */ + @PreAuthorize("@ss.hasPermi('tool:gen:import')") + @Log(title = "代码生成", businessType = BusinessType.IMPORT) + @PostMapping("/importTable") + public AjaxResult importTableSave(@RequestParam("tables") String tables) { + String[] tableNames = Convert.toStrArray(tables); + // 查询表信息 + List tableList = genTableService.selectDbTableListByNames(tableNames); + genTableService.importGenTable(tableList, SecurityUtils.getUsername()); + return success(); + } + + /** + * 创建表结构(保存) + */ + @PreAuthorize("@ss.hasRole('admin')") + @Log(title = "创建表", businessType = BusinessType.OTHER) + @PostMapping("/createTable") + public AjaxResult createTableSave(String sql) { + try { + SqlUtil.filterKeyword(sql); + List sqlStatements = SQLUtils.parseStatements(sql, DbType.mysql); + List tableNames = new ArrayList<>(); + for (SQLStatement sqlStatement : sqlStatements) { + if (sqlStatement instanceof MySqlCreateTableStatement) { + MySqlCreateTableStatement createTableStatement = (MySqlCreateTableStatement) sqlStatement; + if (genTableService.createTable(createTableStatement.toString())) { + String tableName = createTableStatement.getTableName().replaceAll("`", ""); + tableNames.add(tableName); + } + } + } + List tableList = genTableService + .selectDbTableListByNames(tableNames.toArray(new String[tableNames.size()])); + String operName = SecurityUtils.getUsername(); + genTableService.importGenTable(tableList, operName); + return AjaxResult.success(); + } catch (Exception e) { + logger.error(e.getMessage(), e); + return AjaxResult.error("创建表结构异常"); + } + } + + /** + * 修改保存代码生成业务 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:edit')") + @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult editSave(@Validated @RequestBody GenTableVo genTableVo) { + GenTable genTable = genTableVo.getTable(); + genTableService.validateEdit(genTable); + genTableService.updateGenTable(genTable); + genJoinTableService.deleteGenJoinTableByTableId(genTable.getTableId()); + genTableVo.getJoinTablesMate().forEach(i -> { + genJoinTableService.insertGenJoinTable(i); + }); + return success(); + } + + /** + * 删除代码生成 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:remove')") + @Log(title = "代码生成", businessType = BusinessType.DELETE) + @DeleteMapping("/{tableIds}") + public AjaxResult remove(@PathVariable(name = "tableIds") Long[] tableIds) { + genTableService.deleteGenTableByIds(tableIds); + return success(); + } + + /** + * 预览代码 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:preview')") + @GetMapping("/preview/{tableId}") + public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException { + Map dataMap = genTableService.previewCode(tableId); + return success(dataMap); + } + + /** + * 生成代码(下载方式) + */ + @PreAuthorize("@ss.hasPermi('tool:gen:code')") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/download/{tableName}") + public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException { + byte[] data = genTableService.downloadCode(tableName); + genCode(response, data); + } + + /** + * 生成代码(自定义路径) + */ + @PreAuthorize("@ss.hasPermi('tool:gen:code')") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/genCode/{tableName}") + public AjaxResult genCode(@PathVariable("tableName") String tableName) { + genTableService.generatorCode(tableName); + return success(); + } + + /** + * 同步数据库 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:edit')") + @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @GetMapping("/synchDb/{tableName}") + public AjaxResult synchDb(@PathVariable("tableName") String tableName) { + genTableService.synchDb(tableName); + return success(); + } + + /** + * 批量生成代码 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:code')") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/batchGenCode") + public void batchGenCode(HttpServletResponse response, @RequestParam(name = "tables") String tables) + throws IOException { + String[] tableNames = Convert.toStrArray(tables); + byte[] data = genTableService.downloadCode(tableNames); + genCode(response, data); + } + + /** + * 生成zip文件 + */ + private void genCode(HttpServletResponse response, byte[] data) throws IOException { + response.reset(); + response.addHeader("Access-Control-Allow-Origin", "*"); + response.addHeader("Access-Control-Expose-Headers", "Content-Disposition"); + response.setHeader("Content-Disposition", "attachment; filename=\"boyue.zip\""); + response.addHeader("Content-Length", "" + data.length); + response.setContentType("application/octet-stream; charset=UTF-8"); + IOUtils.write(data, response.getOutputStream()); + } +} \ No newline at end of file diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/domain/GenJoinTable.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/domain/GenJoinTable.java new file mode 100644 index 0000000..af34090 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/domain/GenJoinTable.java @@ -0,0 +1,45 @@ +package com.boyue.generator.domain; + +import java.util.List; + +import com.boyue.common.core.domain.BaseEntity; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GenJoinTable extends BaseEntity { + + /** 表编号 */ + private Long tableId; + + private Long leftTableId; + + /** 关联表编号 */ + private Long rightTableId; + + /** 新引入的表 */ + private Long newTableId; + + /** 主表别名 */ + private String leftTableAlias; + + /** 关联表别名 */ + private String rightTableAlias; + + /** 主表外键 */ + private Long leftTableFk; + + /** 关联表外键 */ + private Long rightTableFk; + + /** 连接类型 */ + private String joinType; + + /** 关联字段 */ + private List joinColumns; + + private Long orderNum; + +} diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/domain/GenTable.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/domain/GenTable.java new file mode 100644 index 0000000..b7ec585 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/domain/GenTable.java @@ -0,0 +1,149 @@ +package com.boyue.generator.domain; + +import java.util.List; + +import org.apache.commons.lang3.ArrayUtils; + +import com.boyue.common.core.domain.BaseEntity; +import com.boyue.common.utils.StringUtils; +import com.boyue.generator.constant.GenConstants; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 业务表 gen_table + * + * @author boyue + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class GenTable extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** 编号 */ + private Long tableId; + + /** 表名称 */ + @NotBlank(message = "表名称不能为空") + private String tableName; + + /** 表别名 */ + private String tableAlias; + + /** 表描述 */ + @NotBlank(message = "表描述不能为空") + private String tableComment; + + /** 关联父表的表名 */ + private String subTableName; + + /** 本表关联父表的外键名 */ + private String subTableFkName; + + /** 实体类名称(首字母大写) */ + @NotBlank(message = "实体类名称不能为空") + private String className; + + /** 使用的模板(crud单表操作 tree树表操作 sub主子表操作) */ + private String tplCategory; + + /** 前端类型(element-ui模版 element-plus模版) */ + private String tplWebType; + + /** 生成包路径 */ + @NotBlank(message = "生成包路径不能为空") + private String packageName; + + /** 生成模块名 */ + @NotBlank(message = "生成模块名不能为空") + private String moduleName; + + /** 生成业务名 */ + @NotBlank(message = "生成业务名不能为空") + private String businessName; + + /** 生成功能名 */ + @NotBlank(message = "生成功能名不能为空") + private String functionName; + + /** 生成作者 */ + @NotBlank(message = "作者不能为空") + private String functionAuthor; + + /** 生成代码方式(0zip压缩包 1自定义路径) */ + private String genType; + + /** 生成路径(不填默认项目路径) */ + private String genPath; + + /** 主键信息 */ + private GenTableColumn pkColumn; + + /** 子表信息 */ + private GenTable subTable; + + /** 表列信息 */ + @Valid + private List columns; + + /** 其它生成选项 */ + private String options; + + /** 树编码字段 */ + private String treeCode; + + /** 树父编码字段 */ + private String treeParentCode; + + /** 树名称字段 */ + private String treeName; + + /** 上级菜单ID字段 */ + private String parentMenuId; + + /** 上级菜单名称字段 */ + private String parentMenuName; + + /** 是否含有关联字段 */ + @Deprecated + private String haveSubColumn; + + public boolean isSub() { + return isSub(this.tplCategory); + } + + public static boolean isSub(String tplCategory) { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_SUB, tplCategory); + } + + public boolean isTree() { + return isTree(this.tplCategory); + } + + public static boolean isTree(String tplCategory) { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory); + } + + public boolean isCrud() { + return isCrud(this.tplCategory); + } + + public static boolean isCrud(String tplCategory) { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory); + } + + public boolean isSuperColumn(String javaField) { + return isSuperColumn(this.tplCategory, javaField); + } + + public static boolean isSuperColumn(String tplCategory, String javaField) { + if (isTree(tplCategory)) { + return StringUtils.equalsAnyIgnoreCase(javaField, + ArrayUtils.addAll(GenConstants.TREE_ENTITY, GenConstants.BASE_ENTITY)); + } + return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY); + } +} \ No newline at end of file diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/domain/GenTableColumn.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/domain/GenTableColumn.java new file mode 100644 index 0000000..ce16360 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/domain/GenTableColumn.java @@ -0,0 +1,194 @@ +package com.boyue.generator.domain; + +import com.boyue.common.core.domain.BaseEntity; +import com.boyue.common.utils.StringUtils; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 代码生成业务字段表 gen_table_column + * + * @author boyue + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class GenTableColumn extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** 编号 */ + private Long columnId; + + /** 归属表编号 */ + private Long tableId; + + /** 列名称 */ + private String columnName; + + /** 列描述 */ + private String columnComment; + + /** 列类型 */ + private String columnType; + + /** JAVA类型 */ + private String javaType; + + /** JAVA字段名 */ + @NotBlank(message = "Java属性不能为空") + private String javaField; + + /** 是否主键(1是) */ + private String isPk; + + /** 是否自增(1是) */ + private String isIncrement; + + /** 是否必填(1是) */ + private String isRequired; + + /** 是否为插入字段(1是) */ + private String isInsert; + + /** 是否编辑字段(1是) */ + private String isEdit; + + /** 是否列表字段(1是) */ + private String isList; + + /** 是否查询字段(1是) */ + private String isQuery; + + /** 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围) */ + private String queryType; + + /** + * 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、image图片上传控件、upload文件上传控件、editor富文本控件) + */ + private String htmlType; + + /** 字典类型 */ + private String dictType; + + /** 排序 */ + private Integer sort; + + /** 关联表名称 */ + @Deprecated + private String subColumnTableName; + + /** 关联字段名称 */ + @Deprecated + private String subColumnFkName; + + /** 映射字段名称 */ + @Deprecated + private String subColumnName; + + /** 映射字段Java字段名 */ + @Deprecated + private String subColumnJavaField; + + /** 映射字段Java类型 */ + @Deprecated + private String subColumnJavaType; + + public String getCapJavaField() { + return StringUtils.capitalize(javaField); + } + + public boolean isPk() { + return isPk(this.isPk); + } + + public boolean isPk(String isPk) { + return isPk != null && StringUtils.equals("1", isPk); + } + + public boolean isIncrement() { + return isIncrement(this.isIncrement); + } + + public boolean isIncrement(String isIncrement) { + return isIncrement != null && StringUtils.equals("1", isIncrement); + } + + public boolean isRequired() { + return isRequired(this.isRequired); + } + + public boolean isRequired(String isRequired) { + return isRequired != null && StringUtils.equals("1", isRequired); + } + + public boolean isInsert() { + return isInsert(this.isInsert); + } + + public boolean isInsert(String isInsert) { + return isInsert != null && StringUtils.equals("1", isInsert); + } + + public boolean isEdit() { + return isInsert(this.isEdit); + } + + public boolean isEdit(String isEdit) { + return isEdit != null && StringUtils.equals("1", isEdit); + } + + public boolean isList() { + return isList(this.isList); + } + + public boolean isList(String isList) { + return isList != null && StringUtils.equals("1", isList); + } + + public boolean isQuery() { + return isQuery(this.isQuery); + } + + public boolean isQuery(String isQuery) { + return isQuery != null && StringUtils.equals("1", isQuery); + } + + public boolean isSuperColumn() { + return isSuperColumn(this.javaField); + } + + public static boolean isSuperColumn(String javaField) { + return StringUtils.equalsAnyIgnoreCase(javaField, + // BaseEntity + "createBy", "createTime", "updateBy", "updateTime", "remark", + // TreeEntity + "parentName", "parentId", "orderNum", "ancestors"); + } + + public boolean isUsableColumn() { + return isUsableColumn(javaField); + } + + public static boolean isUsableColumn(String javaField) { + // isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单 + return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark"); + } + + public String readConverterExp() { + String remarks = StringUtils.substringBetween(this.columnComment, "(", ")"); + StringBuffer sb = new StringBuffer(); + if (StringUtils.isNotEmpty(remarks)) { + for (String value : remarks.split(" ")) { + if (StringUtils.isNotEmpty(value)) { + Object startStr = value.subSequence(0, 1); + String endStr = value.substring(1); + sb.append("").append(startStr).append("=").append(endStr).append(","); + } + } + return sb.deleteCharAt(sb.length() - 1).toString(); + } else { + return this.columnComment; + } + } +} diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/domain/vo/GenTableVo.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/domain/vo/GenTableVo.java new file mode 100644 index 0000000..c477385 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/domain/vo/GenTableVo.java @@ -0,0 +1,108 @@ +package com.boyue.generator.domain.vo; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.boyue.common.core.domain.BaseEntity; +import com.boyue.generator.domain.GenJoinTable; +import com.boyue.generator.domain.GenTable; +import com.boyue.generator.domain.GenTableColumn; + +import jakarta.validation.Valid; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Setter; + +/** + * 业务表 gen_table + * + * @author boyue + */ +@Data +@Setter +@EqualsAndHashCode(callSuper = true) +public class GenTableVo extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** 业务表 */ + @Valid + private GenTable table; + + /** 业务表的列 */ + @Valid + private List columns; + + /** 关联信息 */ + @Valid + private List joinTablesMate; + + /** 参与关联的表 */ + private Collection joinTables; + + /** 参与关联的列 */ + private List joinColumns; + + public List getAllGenTables() { + List allGenTables = new ArrayList<>(); + allGenTables.add(table); + allGenTables.addAll(joinTables); + return allGenTables; + } + + public List getAllGenTableColumns() { + List allGenTableColumns = new ArrayList<>(); + if (columns != null) { + allGenTableColumns.addAll(columns); + } + if (joinColumns != null) { + allGenTableColumns.addAll(joinColumns); + } + return allGenTableColumns; + } + + public Map getTableMap() { + Map tableMap = new HashMap<>(); + if (table != null) { + tableMap.put(table.getTableId(), table); + } + if (joinTables != null) { + for (GenTable genTable : joinTables) { + if (genTable != null) { + tableMap.put(genTable.getTableId(), genTable); + } + } + } + return tableMap; + } + + public Map getTableAliasMap() { + Map tableMap = new HashMap<>(); + if (table != null) { + tableMap.put(table.getTableId(), table.getTableAlias()); + } + if (joinTablesMate != null) { + for (GenJoinTable genTable : joinTablesMate) { + if (genTable != null) { + tableMap.put(genTable.getLeftTableId(), genTable.getLeftTableAlias()); + tableMap.put(genTable.getRightTableId(), genTable.getRightTableAlias()); + } + } + } + return tableMap; + } + + public Map getColumnMap() { + Map columnMap = new HashMap<>(); + List genTables = getAllGenTables(); + for (GenTable genTable : genTables) { + for (GenTableColumn genTableColumn : genTable.getColumns()) { + columnMap.put(genTableColumn.getColumnId(), genTableColumn); + } + } + return columnMap; + } + +} \ No newline at end of file diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/mapper/GenJoinTableMapper.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/mapper/GenJoinTableMapper.java new file mode 100644 index 0000000..99a52ad --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/mapper/GenJoinTableMapper.java @@ -0,0 +1,40 @@ +package com.boyue.generator.mapper; + +import java.util.List; + +import com.boyue.generator.domain.GenJoinTable; + +/** + * 代码生成关联字段Mapper接口 + * + * @author boyue + * @date 2025-02-19 + */ +public interface GenJoinTableMapper { + /** + * 查询代码生成关联字段列表 + * + * @param genJoinTable 代码生成关联字段 + * @return 代码生成关联字段集合 + */ + public List selectGenJoinTableList(GenJoinTable genJoinTable); + + /** + * 新增代码生成关联字段 + * + * @param genJoinTable 代码生成关联字段 + * @return 结果 + */ + public int insertGenJoinTable(GenJoinTable genJoinTable); + + /** + * 修改代码生成关联字段 + * + * @param genJoinTable 代码生成关联字段 + * @return 结果 + */ + public int updateGenJoinTable(GenJoinTable genJoinTable); + + public int deleteGenJoinTableByTableId(Long tableId); + +} diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/mapper/GenTableColumnMapper.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/mapper/GenTableColumnMapper.java new file mode 100644 index 0000000..3267b06 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/mapper/GenTableColumnMapper.java @@ -0,0 +1,60 @@ +package com.boyue.generator.mapper; + +import java.util.List; +import com.boyue.generator.domain.GenTableColumn; + +/** + * 业务字段 数据层 + * + * @author boyue + */ +public interface GenTableColumnMapper +{ + /** + * 根据表名称查询列信息 + * + * @param tableName 表名称 + * @return 列信息 + */ + public List selectDbTableColumnsByName(String tableName); + + /** + * 查询业务字段列表 + * + * @param tableId 业务字段编号 + * @return 业务字段集合 + */ + public List selectGenTableColumnListByTableId(Long tableId); + + /** + * 新增业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int insertGenTableColumn(GenTableColumn genTableColumn); + + /** + * 修改业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int updateGenTableColumn(GenTableColumn genTableColumn); + + /** + * 删除业务字段 + * + * @param genTableColumns 列数据 + * @return 结果 + */ + public int deleteGenTableColumns(List genTableColumns); + + /** + * 批量删除业务字段 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteGenTableColumnByIds(Long[] ids); +} diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/mapper/GenTableMapper.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/mapper/GenTableMapper.java new file mode 100644 index 0000000..f6b0328 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/mapper/GenTableMapper.java @@ -0,0 +1,90 @@ +package com.boyue.generator.mapper; + +import java.util.List; +import com.boyue.generator.domain.GenTable; + +/** + * 业务 数据层 + * + * @author boyue + */ +public interface GenTableMapper { + /** + * 查询业务列表 + * + * @param genTable 业务信息 + * @return 业务集合 + */ + public List selectGenTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param genTable 业务信息 + * @return 数据库表集合 + */ + public List selectDbTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + public List selectDbTableListByNames(String[] tableNames); + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + public List selectGenTableAll(); + + /** + * 查询表ID业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + public GenTable selectGenTableById(Long id); + + /** + * 查询表名称业务信息 + * + * @param tableName 表名称 + * @return 业务信息 + */ + public GenTable selectGenTableByName(String tableName); + + /** + * 新增业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + public int insertGenTable(GenTable genTable); + + /** + * 修改业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + public int updateGenTable(GenTable genTable); + + /** + * 批量删除业务 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteGenTableByIds(Long[] ids); + + /** + * 创建表 + * + * @param sql 表结构 + * @return 结果 + */ + public int createTable(String sql); +} diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/GenJoinTableServiceImpl.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/GenJoinTableServiceImpl.java new file mode 100644 index 0000000..3f81e85 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/GenJoinTableServiceImpl.java @@ -0,0 +1,145 @@ +package com.boyue.generator.service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.DateUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.generator.constant.GenConstants; +import com.boyue.generator.domain.GenJoinTable; +import com.boyue.generator.domain.GenTable; +import com.boyue.generator.domain.GenTableColumn; +import com.boyue.generator.domain.vo.GenTableVo; +import com.boyue.generator.mapper.GenJoinTableMapper; +import com.boyue.generator.mapper.GenTableMapper; + +/** + * 代码生成关联字段Service业务层处理 + * + * @author boyue + * @date 2025-02-19 + */ +@Service +public class GenJoinTableServiceImpl implements IGenJoinTableService { + @Autowired + private GenJoinTableMapper genJoinTableMapper; + + @Autowired + private GenTableMapper genTableMapper; + + /** + * 查询代码生成关联字段列表 + * + * @param genJoinTable 代码生成关联字段 + * @return 代码生成关联字段 + */ + @Override + public List selectGenJoinTableList(GenJoinTable genJoinTable) { + return genJoinTableMapper.selectGenJoinTableList(genJoinTable); + } + + public GenTable selectGenTableById(Long id) { + GenTable genTable = genTableMapper.selectGenTableById(id); + setTableFromOptions(genTable); + return genTable; + } + + /** + * 设置代码生成其他选项值 + * + * @param genTable 设置后的生成对象 + */ + public void setTableFromOptions(GenTable genTable) { + JSONObject paramsObj = JSON.parseObject(genTable.getOptions()); + if (StringUtils.isNotNull(paramsObj)) { + String treeCode = paramsObj.getString(GenConstants.TREE_CODE); + String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE); + String treeName = paramsObj.getString(GenConstants.TREE_NAME); + String parentMenuId = paramsObj.getString(GenConstants.PARENT_MENU_ID); + String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME); + + genTable.setTreeCode(treeCode); + genTable.setTreeParentCode(treeParentCode); + genTable.setTreeName(treeName); + genTable.setParentMenuId(parentMenuId); + genTable.setParentMenuName(parentMenuName); + } + } + + @Override + public GenTableVo selectGenJoinTableVoListByGenTable(GenTable table) { + GenTableVo genTableVo = new GenTableVo(); + genTableVo.setTable(table); + genTableVo.setColumns(table.getColumns()); + + GenJoinTable genJoinTable = new GenJoinTable(); + genJoinTable.setTableId(table.getTableId()); + List selectGenJoinTableList = this.selectGenJoinTableList(genJoinTable); + genTableVo.setJoinTablesMate(selectGenJoinTableList); + + List joinColumns = new ArrayList(); + Map joinTableMap = new HashMap(); + joinTableMap.put(table.getTableId(), table); + selectGenJoinTableList.forEach(i -> { + if (Objects.isNull(joinTableMap.get(i.getLeftTableId()))) { + joinTableMap.put(i.getLeftTableId(), this.selectGenTableById(i.getLeftTableId())); + } + if (Objects.isNull(joinTableMap.get(i.getRightTableId()))) { + joinTableMap.put(i.getRightTableId(), this.selectGenTableById(i.getRightTableId())); + } + GenTable newTable = joinTableMap.get(i.getNewTableId()); + if(Objects.isNull(newTable)) throw new ServiceException("关联表不存在"); + List joinColumnNames = i.getJoinColumns(); + if(Objects.isNull(joinColumnNames)) return; + newTable.getColumns().forEach(j -> { + if (joinColumnNames.contains(j.getColumnName())) { + joinColumns.add(j); + } + }); + }); + genTableVo.setJoinColumns(joinColumns); + genTableVo.setJoinTables(joinTableMap.values()); + return genTableVo; + } + + /** + * 新增代码生成关联字段 + * + * @param genJoinTable 代码生成关联字段 + * @return 结果 + */ + @Override + public int insertGenJoinTable(GenJoinTable genJoinTable) { + genJoinTable.setCreateTime(DateUtils.getNowDate()); + return genJoinTableMapper.insertGenJoinTable(genJoinTable); + } + + /** + * 修改代码生成关联字段 + * + * @param genJoinTable 代码生成关联字段 + * @return 结果 + */ + @Override + public int updateGenJoinTable(GenJoinTable genJoinTable) { + genJoinTable.setUpdateTime(DateUtils.getNowDate()); + return genJoinTableMapper.updateGenJoinTable(genJoinTable); + } + + /** + * 根据tableId删除字段关联 + */ + public int deleteGenJoinTableByTableId(Long tableId) { + return genJoinTableMapper.deleteGenJoinTableByTableId(tableId); + } + +} diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/GenTableColumnServiceImpl.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/GenTableColumnServiceImpl.java new file mode 100644 index 0000000..c4f0bf8 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/GenTableColumnServiceImpl.java @@ -0,0 +1,68 @@ +package com.boyue.generator.service; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.boyue.common.core.text.Convert; +import com.boyue.generator.domain.GenTableColumn; +import com.boyue.generator.mapper.GenTableColumnMapper; + +/** + * 业务字段 服务层实现 + * + * @author boyue + */ +@Service +public class GenTableColumnServiceImpl implements IGenTableColumnService +{ + @Autowired + private GenTableColumnMapper genTableColumnMapper; + + /** + * 查询业务字段列表 + * + * @param tableId 业务字段编号 + * @return 业务字段集合 + */ + @Override + public List selectGenTableColumnListByTableId(Long tableId) + { + return genTableColumnMapper.selectGenTableColumnListByTableId(tableId); + } + + /** + * 新增业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + @Override + public int insertGenTableColumn(GenTableColumn genTableColumn) + { + return genTableColumnMapper.insertGenTableColumn(genTableColumn); + } + + /** + * 修改业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + @Override + public int updateGenTableColumn(GenTableColumn genTableColumn) + { + return genTableColumnMapper.updateGenTableColumn(genTableColumn); + } + + /** + * 删除业务字段对象 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + @Override + public int deleteGenTableColumnByIds(String ids) + { + return genTableColumnMapper.deleteGenTableColumnByIds(Convert.toLongArray(ids)); + } +} diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/GenTableServiceImpl.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/GenTableServiceImpl.java new file mode 100644 index 0000000..99fc804 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/GenTableServiceImpl.java @@ -0,0 +1,497 @@ +package com.boyue.generator.service; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.boyue.common.constant.Constants; +import com.boyue.common.core.text.CharsetKit; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.StringUtils; +import com.boyue.generator.constant.GenConstants; +import com.boyue.generator.domain.GenTable; +import com.boyue.generator.domain.GenTableColumn; +import com.boyue.generator.domain.vo.GenTableVo; +import com.boyue.generator.mapper.GenTableColumnMapper; +import com.boyue.generator.mapper.GenTableMapper; +import com.boyue.generator.util.GenUtils; +import com.boyue.generator.util.VelocityInitializer; +import com.boyue.generator.util.VelocityUtils; + +/** + * 业务 服务层实现 + * + * @author boyue + */ +@Service +public class GenTableServiceImpl implements IGenTableService { + private static final Logger log = LoggerFactory.getLogger(GenTableServiceImpl.class); + + @Autowired + private GenTableMapper genTableMapper; + + @Autowired + private GenTableColumnMapper genTableColumnMapper; + + @Autowired + private IGenJoinTableService genJoinTableService; + + /** + * 查询业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + @Override + public GenTable selectGenTableById(Long id) { + GenTable genTable = genTableMapper.selectGenTableById(id); + setTableFromOptions(genTable); + return genTable; + } + + /** + * 查询业务列表 + * + * @param genTable 业务信息 + * @return 业务集合 + */ + @Override + public List selectGenTableList(GenTable genTable) { + return genTableMapper.selectGenTableList(genTable); + } + + /** + * 查询据库列表 + * + * @param genTable 业务信息 + * @return 数据库表集合 + */ + @Override + public List selectDbTableList(GenTable genTable) { + return genTableMapper.selectDbTableList(genTable); + } + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + @Override + public List selectDbTableListByNames(String[] tableNames) { + List genTables = genTableMapper.selectDbTableListByNames(tableNames); + genTables.forEach(i -> i.setTableAlias(generateTableAlias(i.getTableName()))); + return genTables; + } + + public static String generateTableAlias(String tableName) { + if (StringUtils.isEmpty(tableName)) { + return "t"; + } + + // 改进的正则表达式,更准确地处理所有三种情况 + Pattern pattern = Pattern.compile("([A-Z][a-z0-9]*)|([a-z0-9]+)(?=[A-Z])|([a-z0-9]+)(?=_)|([a-z0-9]+)$"); + Matcher matcher = pattern.matcher(tableName); + StringBuilder alias = new StringBuilder(); + + while (matcher.find()) { + String word = matcher.group(); + if (!word.isEmpty()) { + alias.append(word.charAt(0)); + } + } + + return alias.toString().toLowerCase(); + } + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + @Override + public List selectGenTableAll() { + return genTableMapper.selectGenTableAll(); + } + + /** + * 修改业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + @Override + @Transactional + public void updateGenTable(GenTable genTable) { + String options = JSON.toJSONString(genTable.getParams()); + genTable.setOptions(options); + int row = genTableMapper.updateGenTable(genTable); + if (row > 0) { + for (GenTableColumn cenTableColumn : genTable.getColumns()) { + genTableColumnMapper.updateGenTableColumn(cenTableColumn); + } + } + } + + /** + * 删除业务对象 + * + * @param tableIds 需要删除的数据ID + * @return 结果 + */ + @Override + @Transactional + public void deleteGenTableByIds(Long[] tableIds) { + genTableMapper.deleteGenTableByIds(tableIds); + genTableColumnMapper.deleteGenTableColumnByIds(tableIds); + } + + /** + * 创建表 + * + * @param sql 创建表语句 + * @return 结果 + */ + @Override + public boolean createTable(String sql) { + return genTableMapper.createTable(sql) == 0; + } + + /** + * 导入表结构 + * + * @param tableList 导入表列表 + */ + @Override + @Transactional + public void importGenTable(List tableList, String operName) { + try { + for (GenTable table : tableList) { + String tableName = table.getTableName(); + GenUtils.initTable(table, operName); + int row = genTableMapper.insertGenTable(table); + if (row > 0) { + // 保存列信息 + List genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); + for (GenTableColumn column : genTableColumns) { + GenUtils.initColumnField(column, table); + genTableColumnMapper.insertGenTableColumn(column); + } + } + } + } catch (Exception e) { + throw new ServiceException("导入失败:" + e.getMessage()); + } + } + + /** + * 预览代码 + * + * @param tableId 表编号 + * @return 预览数据列表 + */ + @Override + public Map previewCode(Long tableId) { + Map dataMap = new LinkedHashMap<>(); + // 查询表信息 + GenTable table = genTableMapper.selectGenTableById(tableId); + // 设置主子表信息 + setSubTable(table); + // 设置主键列信息 + setPkColumn(table); + VelocityInitializer.initVelocity(); + GenTableVo genTableVo = genJoinTableService.selectGenJoinTableVoListByGenTable(table); + + VelocityContext context = VelocityUtils.prepareContext(genTableVo); + + // 获取模板列表 + List templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType()); + for (String template : templates) { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + dataMap.put(template, sw.toString()); + } + return dataMap; + } + + /** + * 生成代码(下载方式) + * + * @param tableName 表名称 + * @return 数据 + */ + @Override + public byte[] downloadCode(String tableName) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipOutputStream zip = new ZipOutputStream(outputStream); + generatorCode(tableName, zip); + IOUtils.closeQuietly(zip); + return outputStream.toByteArray(); + } + + /** + * 生成代码(自定义路径) + * + * @param tableName 表名称 + */ + @Override + public void generatorCode(String tableName) { + // 查询表信息 + GenTable table = genTableMapper.selectGenTableByName(tableName); + // 设置主子表信息 + setSubTable(table); + // 设置主键列信息 + setPkColumn(table); + + VelocityInitializer.initVelocity(); + GenTableVo genTableVo = genJoinTableService.selectGenJoinTableVoListByGenTable(table); + + VelocityContext context = VelocityUtils.prepareContext(genTableVo); + + // 获取模板列表 + List templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType()); + for (String template : templates) { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + try { + String path = getGenPath(table, template); + FileUtils.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8); + } catch (IOException e) { + throw new ServiceException("渲染模板失败,表名:" + table.getTableName()); + } + } + } + + /** + * 同步数据库 + * + * @param tableName 表名称 + */ + @Override + @Transactional + public void synchDb(String tableName) { + GenTable table = genTableMapper.selectGenTableByName(tableName); + List tableColumns = table.getColumns(); + Map tableColumnMap = tableColumns.stream() + .collect(Collectors.toMap(GenTableColumn::getColumnName, Function.identity())); + + List dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); + if (StringUtils.isEmpty(dbTableColumns)) { + throw new ServiceException("同步数据失败,原表结构不存在"); + } + List dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName) + .collect(Collectors.toList()); + + dbTableColumns.forEach(column -> { + GenUtils.initColumnField(column, table); + if (tableColumnMap.containsKey(column.getColumnName())) { + GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName()); + column.setColumnId(prevColumn.getColumnId()); + if (column.isList()) { + // 如果是列表,继续保留查询方式/字典类型选项 + column.setDictType(prevColumn.getDictType()); + column.setQueryType(prevColumn.getQueryType()); + } + if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk() + && (column.isInsert() || column.isEdit()) + && ((column.isUsableColumn()) || (!column.isSuperColumn()))) { + // 如果是(新增/修改&非主键/非忽略及父属性),继续保留必填/显示类型选项 + column.setIsRequired(prevColumn.getIsRequired()); + column.setHtmlType(prevColumn.getHtmlType()); + } + genTableColumnMapper.updateGenTableColumn(column); + } else { + genTableColumnMapper.insertGenTableColumn(column); + } + }); + + List delColumns = tableColumns.stream() + .filter(column -> !dbTableColumnNames.contains(column.getColumnName())).collect(Collectors.toList()); + if (StringUtils.isNotEmpty(delColumns)) { + genTableColumnMapper.deleteGenTableColumns(delColumns); + } + } + + /** + * 批量生成代码(下载方式) + * + * @param tableNames 表数组 + * @return 数据 + */ + @Override + public byte[] downloadCode(String[] tableNames) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipOutputStream zip = new ZipOutputStream(outputStream); + for (String tableName : tableNames) { + generatorCode(tableName, zip); + } + IOUtils.closeQuietly(zip); + return outputStream.toByteArray(); + } + + /** + * 查询表信息并生成代码 + */ + private void generatorCode(String tableName, ZipOutputStream zip) { + // 查询表信息 + GenTable table = genTableMapper.selectGenTableByName(tableName); + // 设置主子表信息 + setSubTable(table); + // 设置主键列信息 + setPkColumn(table); + + VelocityInitializer.initVelocity(); + GenTableVo genTableVo = genJoinTableService.selectGenJoinTableVoListByGenTable(table); + VelocityContext context = VelocityUtils.prepareContext(genTableVo); + + // 获取模板列表 + List templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType()); + for (String template : templates) { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + try { + // 添加到zip + zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table))); + IOUtils.write(sw.toString(), zip, Constants.UTF8); + IOUtils.closeQuietly(sw); + zip.flush(); + zip.closeEntry(); + } catch (IOException e) { + log.error("渲染模板失败,表名:" + table.getTableName(), e); + } + } + } + + /** + * 修改保存参数校验 + * + * @param genTable 业务信息 + */ + @Override + public void validateEdit(GenTable genTable) { + if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) { + String options = JSON.toJSONString(genTable.getParams()); + JSONObject paramsObj = JSON.parseObject(options); + if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE))) { + throw new ServiceException("树编码字段不能为空"); + } else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE))) { + throw new ServiceException("树父编码字段不能为空"); + } else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME))) { + throw new ServiceException("树名称字段不能为空"); + } else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory())) { + if (StringUtils.isEmpty(genTable.getSubTableName())) { + throw new ServiceException("关联子表的表名不能为空"); + } else if (StringUtils.isEmpty(genTable.getSubTableFkName())) { + throw new ServiceException("子表关联的外键名不能为空"); + } + } + } + } + + /** + * 设置主键列信息 + * + * @param table 业务表信息 + */ + public void setPkColumn(GenTable table) { + for (GenTableColumn column : table.getColumns()) { + if (column.isPk()) { + table.setPkColumn(column); + break; + } + } + if (StringUtils.isNull(table.getPkColumn())) { + table.setPkColumn(table.getColumns().get(0)); + } + if (GenConstants.TPL_SUB.equals(table.getTplCategory())) { + for (GenTableColumn column : table.getSubTable().getColumns()) { + if (column.isPk()) { + table.getSubTable().setPkColumn(column); + break; + } + } + if (StringUtils.isNull(table.getSubTable().getPkColumn())) { + table.getSubTable().setPkColumn(table.getSubTable().getColumns().get(0)); + } + } + } + + /** + * 设置主子表信息 + * + * @param table 业务表信息 + */ + public void setSubTable(GenTable table) { + String subTableName = table.getSubTableName(); + if (StringUtils.isNotEmpty(subTableName)) { + table.setSubTable(genTableMapper.selectGenTableByName(subTableName)); + } + } + + /** + * 设置代码生成其他选项值 + * + * @param genTable 设置后的生成对象 + */ + public void setTableFromOptions(GenTable genTable) { + JSONObject paramsObj = JSON.parseObject(genTable.getOptions()); + if (StringUtils.isNotNull(paramsObj)) { + String treeCode = paramsObj.getString(GenConstants.TREE_CODE); + String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE); + String treeName = paramsObj.getString(GenConstants.TREE_NAME); + String parentMenuId = paramsObj.getString(GenConstants.PARENT_MENU_ID); + String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME); + + genTable.setTreeCode(treeCode); + genTable.setTreeParentCode(treeParentCode); + genTable.setTreeName(treeName); + genTable.setParentMenuId(parentMenuId); + genTable.setParentMenuName(parentMenuName); + } + } + + /** + * 获取代码生成地址 + * + * @param table 业务表信息 + * @param template 模板文件路径 + * @return 生成地址 + */ + public static String getGenPath(GenTable table, String template) { + String genPath = table.getGenPath(); + if (StringUtils.equals(genPath, "/")) { + return System.getProperty("user.dir") + File.separator + "src" + File.separator + + VelocityUtils.getFileName(template, table); + } + return genPath + File.separator + VelocityUtils.getFileName(template, table); + } +} \ No newline at end of file diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/IGenJoinTableService.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/IGenJoinTableService.java new file mode 100644 index 0000000..10aa305 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/IGenJoinTableService.java @@ -0,0 +1,46 @@ +package com.boyue.generator.service; + +import java.util.List; + +import com.boyue.generator.domain.GenJoinTable; +import com.boyue.generator.domain.GenTable; +import com.boyue.generator.domain.vo.GenTableVo; + +/** + * 代码生成关联字段Service接口 + * + * @author boyue + * @date 2025-02-19 + */ +public interface IGenJoinTableService { + /** + * 查询代码生成关联字段列表 + * + * @param genJoinTable 代码生成关联字段 + * @return 代码生成关联字段集合 + */ + public List selectGenJoinTableList(GenJoinTable genJoinTable); + + /** + * 新增代码生成关联字段 + * + * @param genJoinTable 代码生成关联字段 + * @return 结果 + */ + public int insertGenJoinTable(GenJoinTable genJoinTable); + + /** + * 修改代码生成关联字段 + * + * @param genJoinTable 代码生成关联字段 + * @return 结果 + */ + public int updateGenJoinTable(GenJoinTable genJoinTable); + + /** + * 根据tableId删除字段关联 + */ + public int deleteGenJoinTableByTableId(Long tableId); + + public GenTableVo selectGenJoinTableVoListByGenTable(GenTable table); +} diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/IGenTableColumnService.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/IGenTableColumnService.java new file mode 100644 index 0000000..e895fb6 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/IGenTableColumnService.java @@ -0,0 +1,44 @@ +package com.boyue.generator.service; + +import java.util.List; +import com.boyue.generator.domain.GenTableColumn; + +/** + * 业务字段 服务层 + * + * @author boyue + */ +public interface IGenTableColumnService +{ + /** + * 查询业务字段列表 + * + * @param tableId 业务字段编号 + * @return 业务字段集合 + */ + public List selectGenTableColumnListByTableId(Long tableId); + + /** + * 新增业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int insertGenTableColumn(GenTableColumn genTableColumn); + + /** + * 修改业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int updateGenTableColumn(GenTableColumn genTableColumn); + + /** + * 删除业务字段信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteGenTableColumnByIds(String ids); +} diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/IGenTableService.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/IGenTableService.java new file mode 100644 index 0000000..647d257 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/service/IGenTableService.java @@ -0,0 +1,128 @@ +package com.boyue.generator.service; + +import java.util.List; +import java.util.Map; +import com.boyue.generator.domain.GenTable; + +/** + * 业务 服务层 + * + * @author boyue + */ +public interface IGenTableService { + /** + * 查询业务列表 + * + * @param genTable 业务信息 + * @return 业务集合 + */ + public List selectGenTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param genTable 业务信息 + * @return 数据库表集合 + */ + public List selectDbTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + public List selectDbTableListByNames(String[] tableNames); + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + public List selectGenTableAll(); + + /** + * 查询业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + public GenTable selectGenTableById(Long id); + + /** + * 修改业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + public void updateGenTable(GenTable genTable); + + /** + * 删除业务信息 + * + * @param tableIds 需要删除的表数据ID + * @return 结果 + */ + public void deleteGenTableByIds(Long[] tableIds); + + /** + * 创建表 + * + * @param sql 创建表语句 + * @return 结果 + */ + public boolean createTable(String sql); + + /** + * 导入表结构 + * + * @param tableList 导入表列表 + */ + public void importGenTable(List tableList, String operName); + + /** + * 预览代码 + * + * @param tableId 表编号 + * @return 预览数据列表 + */ + public Map previewCode(Long tableId); + + /** + * 生成代码(下载方式) + * + * @param tableName 表名称 + * @return 数据 + */ + public byte[] downloadCode(String tableName); + + /** + * 生成代码(自定义路径) + * + * @param tableName 表名称 + * @return 数据 + */ + public void generatorCode(String tableName); + + /** + * 同步数据库 + * + * @param tableName 表名称 + */ + public void synchDb(String tableName); + + /** + * 批量生成代码(下载方式) + * + * @param tableNames 表数组 + * @return 数据 + */ + public byte[] downloadCode(String[] tableNames); + + /** + * 修改保存参数校验 + * + * @param genTable 业务信息 + */ + public void validateEdit(GenTable genTable); +} diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/util/GenUtils.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/util/GenUtils.java new file mode 100644 index 0000000..eecbc59 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/util/GenUtils.java @@ -0,0 +1,257 @@ +package com.boyue.generator.util; + +import java.util.Arrays; +import org.apache.commons.lang3.RegExUtils; +import com.boyue.generator.constant.GenConstants; +import com.boyue.common.utils.StringUtils; +import com.boyue.generator.config.GenConfig; +import com.boyue.generator.domain.GenTable; +import com.boyue.generator.domain.GenTableColumn; + +/** + * 代码生成器 工具类 + * + * @author boyue + */ +public class GenUtils +{ + /** + * 初始化表信息 + */ + public static void initTable(GenTable genTable, String operName) + { + genTable.setClassName(convertClassName(genTable.getTableName())); + genTable.setPackageName(GenConfig.getPackageName()); + genTable.setModuleName(getModuleName(GenConfig.getPackageName())); + genTable.setBusinessName(getBusinessName(genTable.getTableName())); + genTable.setFunctionName(replaceText(genTable.getTableComment())); + genTable.setFunctionAuthor(GenConfig.getAuthor()); + genTable.setCreateBy(operName); + } + + /** + * 初始化列属性字段 + */ + public static void initColumnField(GenTableColumn column, GenTable table) + { + String dataType = getDbType(column.getColumnType()); + String columnName = column.getColumnName(); + column.setTableId(table.getTableId()); + column.setCreateBy(table.getCreateBy()); + // 设置java字段名 + column.setJavaField(StringUtils.toCamelCase(columnName)); + // 设置默认类型 + column.setJavaType(GenConstants.TYPE_STRING); + column.setQueryType(GenConstants.QUERY_EQ); + + if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) + { + // 字符串长度超过500设置为文本域 + Integer columnLength = getColumnLength(column.getColumnType()); + String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT; + column.setHtmlType(htmlType); + } + else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) + { + column.setJavaType(GenConstants.TYPE_DATE); + column.setHtmlType(GenConstants.HTML_DATETIME); + } + else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) + { + column.setHtmlType(GenConstants.HTML_INPUT); + + // 如果是浮点型 统一用BigDecimal + String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ","); + if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) + { + column.setJavaType(GenConstants.TYPE_BIGDECIMAL); + } + // 如果是整形 + else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) + { + column.setJavaType(GenConstants.TYPE_INTEGER); + } + // 长整形 + else + { + column.setJavaType(GenConstants.TYPE_LONG); + } + } + + // 插入字段(默认所有字段都需要插入) + column.setIsInsert(GenConstants.REQUIRE); + + // 编辑字段 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName) && !column.isPk()) + { + column.setIsEdit(GenConstants.REQUIRE); + } + // 列表字段 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName) && !column.isPk()) + { + column.setIsList(GenConstants.REQUIRE); + } + // 查询字段 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk()) + { + column.setIsQuery(GenConstants.REQUIRE); + } + + // 查询字段类型 + if (StringUtils.endsWithIgnoreCase(columnName, "name")) + { + column.setQueryType(GenConstants.QUERY_LIKE); + } + // 状态字段设置单选框 + if (StringUtils.endsWithIgnoreCase(columnName, "status")) + { + column.setHtmlType(GenConstants.HTML_RADIO); + } + // 类型&性别字段设置下拉框 + else if (StringUtils.endsWithIgnoreCase(columnName, "type") + || StringUtils.endsWithIgnoreCase(columnName, "sex")) + { + column.setHtmlType(GenConstants.HTML_SELECT); + } + // 图片字段设置图片上传控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "image")) + { + column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD); + } + // 文件字段设置文件上传控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "file")) + { + column.setHtmlType(GenConstants.HTML_FILE_UPLOAD); + } + // 内容字段设置富文本控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "content")) + { + column.setHtmlType(GenConstants.HTML_EDITOR); + } + } + + /** + * 校验数组是否包含指定值 + * + * @param arr 数组 + * @param targetValue 值 + * @return 是否包含 + */ + public static boolean arraysContains(String[] arr, String targetValue) + { + return Arrays.asList(arr).contains(targetValue); + } + + /** + * 获取模块名 + * + * @param packageName 包名 + * @return 模块名 + */ + public static String getModuleName(String packageName) + { + int lastIndex = packageName.lastIndexOf("."); + int nameLength = packageName.length(); + return StringUtils.substring(packageName, lastIndex + 1, nameLength); + } + + /** + * 获取业务名 + * + * @param tableName 表名 + * @return 业务名 + */ + public static String getBusinessName(String tableName) + { + int lastIndex = tableName.lastIndexOf("_"); + int nameLength = tableName.length(); + return StringUtils.substring(tableName, lastIndex + 1, nameLength); + } + + /** + * 表名转换成Java类名 + * + * @param tableName 表名称 + * @return 类名 + */ + public static String convertClassName(String tableName) + { + boolean autoRemovePre = GenConfig.getAutoRemovePre(); + String tablePrefix = GenConfig.getTablePrefix(); + if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix)) + { + String[] searchList = StringUtils.split(tablePrefix, ","); + tableName = replaceFirst(tableName, searchList); + } + return StringUtils.convertToCamelCase(tableName); + } + + /** + * 批量替换前缀 + * + * @param replacementm 替换值 + * @param searchList 替换列表 + * @return + */ + public static String replaceFirst(String replacementm, String[] searchList) + { + String text = replacementm; + for (String searchString : searchList) + { + if (replacementm.startsWith(searchString)) + { + text = replacementm.replaceFirst(searchString, ""); + break; + } + } + return text; + } + + /** + * 关键字替换 + * + * @param text 需要被替换的名字 + * @return 替换后的名字 + */ + public static String replaceText(String text) + { + return RegExUtils.replaceAll(text, "(?:表|若依)", ""); + } + + /** + * 获取数据库类型字段 + * + * @param columnType 列类型 + * @return 截取后的列类型 + */ + public static String getDbType(String columnType) + { + if (StringUtils.indexOf(columnType, "(") > 0) + { + return StringUtils.substringBefore(columnType, "("); + } + else + { + return columnType; + } + } + + /** + * 获取字段长度 + * + * @param columnType 列类型 + * @return 截取后的列类型 + */ + public static Integer getColumnLength(String columnType) + { + if (StringUtils.indexOf(columnType, "(") > 0) + { + String length = StringUtils.substringBetween(columnType, "(", ")"); + return Integer.valueOf(length); + } + else + { + return 0; + } + } +} diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/util/VelocityInitializer.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/util/VelocityInitializer.java new file mode 100644 index 0000000..fcec463 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/util/VelocityInitializer.java @@ -0,0 +1,34 @@ +package com.boyue.generator.util; + +import java.util.Properties; +import org.apache.velocity.app.Velocity; +import com.boyue.common.constant.Constants; + +/** + * VelocityEngine工厂 + * + * @author boyue + */ +public class VelocityInitializer +{ + /** + * 初始化vm方法 + */ + public static void initVelocity() + { + Properties p = new Properties(); + try + { + // 加载classpath目录下的vm文件 + p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + // 定义字符集 + p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8); + // 初始化Velocity引擎,指定配置Properties + Velocity.init(p); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } +} diff --git a/boyue-models/boyue-generator/src/main/java/com/boyue/generator/util/VelocityUtils.java b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/util/VelocityUtils.java new file mode 100644 index 0000000..81679b2 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/java/com/boyue/generator/util/VelocityUtils.java @@ -0,0 +1,448 @@ +package com.boyue.generator.util; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.velocity.VelocityContext; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.boyue.common.utils.DateUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.generator.constant.GenConstants; +import com.boyue.generator.domain.GenTable; +import com.boyue.generator.domain.GenTableColumn; +import com.boyue.generator.domain.vo.GenTableVo; + +/** + * 模板处理工具类 + * + * @author boyue + */ +public class VelocityUtils +{ + /** 项目空间路径 */ + private static final String PROJECT_PATH = "main/java"; + + /** mybatis空间路径 */ + private static final String MYBATIS_PATH = "main/resources/mapper"; + + /** 默认上级菜单,系统工具 */ + private static final String DEFAULT_PARENT_MENU_ID = "3"; + + /** + * 设置模板变量信息 + * + * @return 模板列表 + */ + public static VelocityContext prepareContext(GenTableVo genTableVo) + { + GenTable genTable = genTableVo.getTable(); + String moduleName = genTable.getModuleName(); + String businessName = genTable.getBusinessName(); + String packageName = genTable.getPackageName(); + String tplCategory = genTable.getTplCategory(); + String functionName = genTable.getFunctionName(); + + VelocityContext velocityContext = new VelocityContext(); + velocityContext.put("tplCategory", genTable.getTplCategory()); + velocityContext.put("tableName", genTable.getTableName()); + velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】"); + velocityContext.put("ClassName", genTable.getClassName()); + velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName())); + velocityContext.put("moduleName", genTable.getModuleName()); + velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName())); + velocityContext.put("businessName", genTable.getBusinessName()); + velocityContext.put("basePackage", getPackagePrefix(packageName)); + velocityContext.put("packageName", packageName); + velocityContext.put("author", genTable.getFunctionAuthor()); + velocityContext.put("datetime", DateUtils.getDate()); + velocityContext.put("pkColumn", genTable.getPkColumn()); + velocityContext.put("importList", getImportList(genTable)); + velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName)); + velocityContext.put("columns", genTable.getColumns()); + velocityContext.put("table", genTable); + velocityContext.put("tableMap", genTableVo.getTableMap()); + velocityContext.put("tableAliasMap", genTableVo.getTableAliasMap()); + velocityContext.put("columnMap", genTableVo.getColumnMap()); + velocityContext.put("allColumns", genTableVo.getAllGenTableColumns()); + velocityContext.put("joinColunms", genTableVo.getJoinColumns()); + velocityContext.put("joinTablesMate", genTableVo.getJoinTablesMate()); + velocityContext.put("dicts", getDicts(genTable)); + setMenuVelocityContext(velocityContext, genTable); + if (GenConstants.TPL_TREE.equals(tplCategory)) + { + setTreeVelocityContext(velocityContext, genTable); + } + if (GenConstants.TPL_SUB.equals(tplCategory)) + { + setSubVelocityContext(velocityContext, genTable); + } + return velocityContext; + } + + public static void setMenuVelocityContext(VelocityContext context, GenTable genTable) + { + String options = genTable.getOptions(); + JSONObject paramsObj = JSON.parseObject(options); + String parentMenuId = getParentMenuId(paramsObj); + context.put("parentMenuId", parentMenuId); + } + + public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) + { + String options = genTable.getOptions(); + JSONObject paramsObj = JSON.parseObject(options); + String treeCode = getTreecode(paramsObj); + String treeParentCode = getTreeParentCode(paramsObj); + String treeName = getTreeName(paramsObj); + + context.put("treeCode", treeCode); + context.put("treeParentCode", treeParentCode); + context.put("treeName", treeName); + context.put("expandColumn", getExpandColumn(genTable)); + if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) + { + context.put("tree_parent_code", paramsObj.getString(GenConstants.TREE_PARENT_CODE)); + } + if (paramsObj.containsKey(GenConstants.TREE_NAME)) + { + context.put("tree_name", paramsObj.getString(GenConstants.TREE_NAME)); + } + } + + public static void setSubVelocityContext(VelocityContext context, GenTable genTable) + { + GenTable subTable = genTable.getSubTable(); + String subTableName = genTable.getSubTableName(); + String subTableFkName = genTable.getSubTableFkName(); + String subClassName = genTable.getSubTable().getClassName(); + String subTableFkClassName = StringUtils.convertToCamelCase(subTableFkName); + + context.put("subTable", subTable); + context.put("subTableName", subTableName); + context.put("subTableFkName", subTableFkName); + context.put("subTableFkClassName", subTableFkClassName); + context.put("subTableFkclassName", StringUtils.uncapitalize(subTableFkClassName)); + context.put("subClassName", subClassName); + context.put("subclassName", StringUtils.uncapitalize(subClassName)); + context.put("subImportList", getImportList(genTable.getSubTable())); + } + + /** + * 获取模板信息 + * + * @return 模板列表 + */ + public static List getTemplateList(String tplCategory, String tplWebType) + { + String useWebType = "vm/vue/v2"; + if ("element-plus".equals(tplWebType)) + { + useWebType = "vm/vue/v3"; + } + List templates = new ArrayList(); + templates.add("vm/java/domain.java.vm"); + templates.add("vm/java/mapper.java.vm"); + templates.add("vm/java/service.java.vm"); + templates.add("vm/java/serviceImpl.java.vm"); + templates.add("vm/java/controller.java.vm"); + templates.add("vm/xml/mapper.xml.vm"); + templates.add("vm/sql/sql.vm"); + templates.add("vm/js/api.js.vm"); + if (GenConstants.TPL_CRUD.equals(tplCategory)) + { + templates.add(useWebType + "/index.vue.vm"); + } + else if (GenConstants.TPL_TREE.equals(tplCategory)) + { + templates.add(useWebType + "/index-tree.vue.vm"); + } + else if (GenConstants.TPL_SUB.equals(tplCategory)) + { + templates.add(useWebType + "/index.vue.vm"); + templates.add("vm/java/sub-domain.java.vm"); + } + + templates.add("vm/uniapp/edit.vue.vm"); + templates.add("vm/uniapp/list.vue.vm"); + templates.add("vm/uniapp/show.vue.vm"); + return templates; + } + + /** + * 获取文件名 + */ + public static String getFileName(String template, GenTable genTable) + { + // 文件名称 + String fileName = ""; + // 包路径 + String packageName = genTable.getPackageName(); + // 模块名 + String moduleName = genTable.getModuleName(); + // 大写类名 + String className = genTable.getClassName(); + // 业务名称 + String businessName = genTable.getBusinessName(); + + String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/"); + String mybatisPath = MYBATIS_PATH + "/" + moduleName; + String vuePath = "vue"; + String uniPath = "uniapp"; + + if (template.contains("domain.java.vm")) + { + fileName = StringUtils.format("{}/domain/{}.java", javaPath, className); + } + if (template.contains("sub-domain.java.vm") && StringUtils.equals(GenConstants.TPL_SUB, genTable.getTplCategory())) + { + fileName = StringUtils.format("{}/domain/{}.java", javaPath, genTable.getSubTable().getClassName()); + } + else if (template.contains("mapper.java.vm")) + { + fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className); + } + else if (template.contains("service.java.vm")) + { + fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className); + } + else if (template.contains("serviceImpl.java.vm")) + { + fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className); + } + else if (template.contains("controller.java.vm")) + { + fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className); + } + else if (template.contains("mapper.xml.vm")) + { + fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className); + } + else if (template.contains("sql.vm")) + { + fileName = businessName + "Menu.sql"; + } + else if (template.contains("api.js.vm")) + { + fileName = StringUtils.format("{}/api/{}/{}.js", vuePath, moduleName, businessName); + } + else if (template.contains("index.vue.vm")) + { + fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); + } + else if (template.contains("index-tree.vue.vm")) + { + fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); + } + else if (template.contains("entity.js.vm")) + { + fileName = StringUtils.format("{}/entity/{}/{}.js", vuePath, moduleName, businessName); + } + else if (template.contains("edit.vue.vm")) + { + fileName = StringUtils.format("{}/pages/{}/{}/edit.vue", uniPath, moduleName, businessName); + } + else if (template.contains("list.vue.vm")) + { + fileName = StringUtils.format("{}/pages/{}/{}/list.vue", uniPath, moduleName, businessName); + } + else if (template.contains("show.vue.vm")) + { + fileName = StringUtils.format("{}/pages/{}/{}/show.vue", uniPath, moduleName, businessName); + } + return fileName; + } + + /** + * 获取包前缀 + * + * @param packageName 包名称 + * @return 包前缀名称 + */ + public static String getPackagePrefix(String packageName) + { + int lastIndex = packageName.lastIndexOf("."); + return StringUtils.substring(packageName, 0, lastIndex); + } + + /** + * 根据列类型获取导入包 + * + * @param genTable 业务表对象 + * @return 返回需要导入的包列表 + */ + public static HashSet getImportList(GenTable genTable) + { + List columns = genTable.getColumns(); + GenTable subGenTable = genTable.getSubTable(); + HashSet importList = new HashSet(); + if (StringUtils.isNotNull(subGenTable)) + { + importList.add("java.util.List"); + } + for (GenTableColumn column : columns) + { + if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType())) + { + importList.add("java.time.LocalDate"); + importList.add("com.fasterxml.jackson.annotation.JsonFormat"); + } + else if (!column.isSuperColumn() && GenConstants.TYPE_TIME.equals(column.getJavaType())) + { + importList.add("java.time.LocalTime"); + importList.add("com.fasterxml.jackson.annotation.JsonFormat"); + } + else if (!column.isSuperColumn() && GenConstants.TYPE_DATETIME.equals(column.getJavaType())) + { + importList.add("java.time.LocalDateTime"); + importList.add("com.fasterxml.jackson.annotation.JsonFormat"); + } + else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) + { + importList.add("java.math.BigDecimal"); + } + } + return importList; + } + + /** + * 根据列类型获取字典组 + * + * @param genTable 业务表对象 + * @return 返回字典组 + */ + public static String getDicts(GenTable genTable) + { + List columns = genTable.getColumns(); + Set dicts = new HashSet(); + addDicts(dicts, columns); + if (StringUtils.isNotNull(genTable.getSubTable())) + { + List subColumns = genTable.getSubTable().getColumns(); + addDicts(dicts, subColumns); + } + return StringUtils.join(dicts, ", "); + } + + /** + * 添加字典列表 + * + * @param dicts 字典列表 + * @param columns 列集合 + */ + public static void addDicts(Set dicts, List columns) + { + for (GenTableColumn column : columns) + { + if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny( + column.getHtmlType(), + new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX })) + { + dicts.add("'" + column.getDictType() + "'"); + } + } + } + + /** + * 获取权限前缀 + * + * @param moduleName 模块名称 + * @param businessName 业务名称 + * @return 返回权限前缀 + */ + public static String getPermissionPrefix(String moduleName, String businessName) + { + return StringUtils.format("{}:{}", moduleName, businessName); + } + + /** + * 获取上级菜单ID字段 + * + * @param paramsObj 生成其他选项 + * @return 上级菜单ID字段 + */ + public static String getParentMenuId(JSONObject paramsObj) + { + if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID) + && StringUtils.isNotEmpty(paramsObj.getString(GenConstants.PARENT_MENU_ID))) + { + return paramsObj.getString(GenConstants.PARENT_MENU_ID); + } + return DEFAULT_PARENT_MENU_ID; + } + + /** + * 获取树编码 + * + * @param paramsObj 生成其他选项 + * @return 树编码 + */ + public static String getTreecode(JSONObject paramsObj) + { + if (paramsObj.containsKey(GenConstants.TREE_CODE)) + { + return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_CODE)); + } + return StringUtils.EMPTY; + } + + /** + * 获取树父编码 + * + * @param paramsObj 生成其他选项 + * @return 树父编码 + */ + public static String getTreeParentCode(JSONObject paramsObj) + { + if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) + { + return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_PARENT_CODE)); + } + return StringUtils.EMPTY; + } + + /** + * 获取树名称 + * + * @param paramsObj 生成其他选项 + * @return 树名称 + */ + public static String getTreeName(JSONObject paramsObj) + { + if (paramsObj.containsKey(GenConstants.TREE_NAME)) + { + return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_NAME)); + } + return StringUtils.EMPTY; + } + + /** + * 获取需要在哪一列上面显示展开按钮 + * + * @param genTable 业务表对象 + * @return 展开按钮列序号 + */ + public static int getExpandColumn(GenTable genTable) + { + String options = genTable.getOptions(); + JSONObject paramsObj = JSON.parseObject(options); + String treeName = paramsObj.getString(GenConstants.TREE_NAME); + int num = 0; + for (GenTableColumn column : genTable.getColumns()) + { + if (column.isList()) + { + num++; + String columnName = column.getColumnName(); + if (columnName.equals(treeName)) + { + break; + } + } + } + return num; + } +} diff --git a/boyue-models/boyue-generator/src/main/resources/generator.yml b/boyue-models/boyue-generator/src/main/resources/generator.yml new file mode 100644 index 0000000..cf4f07f --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/generator.yml @@ -0,0 +1,10 @@ +# 基础配置 +gen: + # 作者 + author: boyue + # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool + packageName: com.boyue.system + # 自动去除表前缀,默认是false + autoRemovePre: false + # 表前缀(生成类名不会包含表前缀,多个用逗号分隔) + tablePrefix: sys_ diff --git a/boyue-models/boyue-generator/src/main/resources/mapper/generator/GenJoinTableMapper.xml b/boyue-models/boyue-generator/src/main/resources/mapper/generator/GenJoinTableMapper.xml new file mode 100644 index 0000000..b1a057e --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/mapper/generator/GenJoinTableMapper.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + select table_id, left_table_id, right_table_id, left_table_alias, right_table_alias, left_table_fk, right_table_fk, join_type, join_columns, order_num, new_table_id from gen_join_table + + + + + + insert into gen_join_table + + table_id, + left_table_id, + right_table_id, + left_table_alias, + right_table_alias, + left_table_fk, + right_table_fk, + join_type, + join_columns, + order_num, + new_table_id, + + + #{tableId}, + #{leftTableId}, + #{rightTableId}, + #{leftTableAlias}, + #{rightTableAlias}, + #{leftTableFk}, + #{rightTableFk}, + #{joinType}, + #{joinColumns,typeHandler=com.boyue.common.handler.GenericListTypeHandler$StringList}, + #{orderNum}, + #{newTableId}, + + + + + update gen_join_table + + left_table_id = #{leftTableId}, + right_table_id = #{rightTableId}, + left_table_alias = #{leftTableAlias}, + right_table_alias = #{rightTableAlias}, + left_table_fk = #{leftTableFk}, + right_table_fk = #{rightTableFk}, + join_type = #{joinType}, + join_columns = #{joinColumns,typeHandler=com.boyue.common.handler.GenericListTypeHandler$StringList}, + order_num = #{orderNum}, + new_table_id = #{newTableId}, + + where gen_join_table.table_id = #{tableId} and gen_join_table.right_table_id = #{rightTableId} + + + + delete from gen_join_table where table_id = #{tableId} + + \ No newline at end of file diff --git a/boyue-models/boyue-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml b/boyue-models/boyue-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml new file mode 100644 index 0000000..c3cd889 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select column_id, table_id, column_name, column_comment, column_type, java_type, java_field, is_pk, is_increment, is_required, is_insert, is_edit, is_list, is_query, query_type, html_type, dict_type, sort,sub_column_table_name,sub_column_fk_name,sub_column_name,sub_column_java_type,sub_column_java_field, create_by, create_time, update_by, update_time from gen_table_column + + + + + + + + insert into gen_table_column ( + table_id, + column_name, + column_comment, + column_type, + java_type, + java_field, + is_pk, + is_increment, + is_required, + is_insert, + is_edit, + is_list, + is_query, + query_type, + html_type, + dict_type, + sort, + sub_column_table_name, + sub_column_fk_name, + sub_column_name, + sub_column_java_field, + sub_column_java_type, + create_by, + create_time + )values( + #{tableId}, + #{columnName}, + #{columnComment}, + #{columnType}, + #{javaType}, + #{javaField}, + #{isPk}, + #{isIncrement}, + #{isRequired}, + #{isInsert}, + #{isEdit}, + #{isList}, + #{isQuery}, + #{queryType}, + #{htmlType}, + #{dictType}, + #{sort}, + #{subColumnTableName}, + #{subColumnFkName}, + #{subColumnName}, + #{subColumnJavaField}, + #{subColumnJavaType}, + #{createBy}, + sysdate() + ) + + + + update gen_table_column + + column_comment = #{columnComment}, + java_type = #{javaType}, + java_field = #{javaField}, + is_insert = #{isInsert}, + is_edit = #{isEdit}, + is_list = #{isList}, + is_query = #{isQuery}, + is_required = #{isRequired}, + query_type = #{queryType}, + html_type = #{htmlType}, + dict_type = #{dictType}, + sort = #{sort}, + sub_column_table_name = #{subColumnTableName}, + sub_column_fk_name = #{subColumnFkName}, + sub_column_name = #{subColumnName}, + sub_column_java_field = #{subColumnJavaField}, + sub_column_java_type = #{subColumnJavaType}, + update_by = #{updateBy}, + update_time = sysdate() + + where column_id = #{columnId} + + + + delete from gen_table_column where table_id in + + #{tableId} + + + + + delete from gen_table_column where column_id in + + #{item.columnId} + + + + \ No newline at end of file diff --git a/boyue-models/boyue-generator/src/main/resources/mapper/generator/GenTableMapper.xml b/boyue-models/boyue-generator/src/main/resources/mapper/generator/GenTableMapper.xml new file mode 100644 index 0000000..0b8dcce --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/mapper/generator/GenTableMapper.xml @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select table_id, table_name,table_alias, table_comment, sub_table_name, sub_table_fk_name, class_name, tpl_category, tpl_web_type, package_name, module_name, business_name, function_name, function_author, gen_type, gen_path, options, have_sub_column,create_by, create_time, update_by, update_time, remark from gen_table + + + + + + + + + + + + + + + + + + insert into gen_table ( + table_name, + table_alias, + table_comment, + class_name, + tpl_category, + tpl_web_type, + package_name, + module_name, + business_name, + function_name, + function_author, + gen_type, + gen_path, + remark, + create_by, + have_sub_column, + create_time + )values( + #{tableName}, + #{tableAlias}, + #{tableComment}, + #{className}, + #{tplCategory}, + #{tplWebType}, + #{packageName}, + #{moduleName}, + #{businessName}, + #{functionName}, + #{functionAuthor}, + #{genType}, + #{genPath}, + #{remark}, + #{haveSubColumn}, + #{createBy}, + sysdate() + ) + + + + ${sql} + + + + update gen_table + + table_name = #{tableName}, + table_alias = #{tableAlias}, + table_comment = #{tableComment}, + sub_table_name = #{subTableName}, + sub_table_fk_name = #{subTableFkName}, + class_name = #{className}, + function_author = #{functionAuthor}, + gen_type = #{genType}, + gen_path = #{genPath}, + tpl_category = #{tplCategory}, + tpl_web_type = #{tplWebType}, + package_name = #{packageName}, + module_name = #{moduleName}, + business_name = #{businessName}, + function_name = #{functionName}, + options = #{options}, + update_by = #{updateBy}, + remark = #{remark}, + have_sub_column = #{haveSubColumn}, + update_time = sysdate() + + where table_id = #{tableId} + + + + delete from gen_table where table_id in + + #{tableId} + + + + \ No newline at end of file diff --git a/boyue-models/boyue-generator/src/main/resources/vm/java/controller.java.vm b/boyue-models/boyue-generator/src/main/resources/vm/java/controller.java.vm new file mode 100644 index 0000000..b37c887 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/java/controller.java.vm @@ -0,0 +1,124 @@ +package ${packageName}.controller; + +import java.util.List; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.enums.BusinessType; +import ${packageName}.domain.${ClassName}; +import ${packageName}.service.I${ClassName}Service; +import com.boyue.common.utils.poi.ExcelUtil; +#if($table.crud || $table.sub) +import com.boyue.common.core.page.TableDataInfo; +#elseif($table.tree) +#end +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; + +/** + * ${functionName}Controller + * + * @author ${author} + * @date ${datetime} + */ +@RestController +@RequestMapping("/${moduleName}/${businessName}") +@Tag(name = "【${functionName}】管理") +public class ${ClassName}Controller extends BaseController +{ + @Autowired + private I${ClassName}Service ${className}Service; + + /** + * 查询${functionName}列表 + */ + @Operation(summary = "查询${functionName}列表") + @PreAuthorize("@ss.hasPermi('${permissionPrefix}:list')") + @GetMapping("/list") +#if($table.crud || $table.sub) + public TableDataInfo list(${ClassName} ${className}) + { + startPage(); + List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); + return getDataTable(list); + } +#elseif($table.tree) + public AjaxResult list(${ClassName} ${className}) + { + List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); + return success(list); + } +#end + + /** + * 导出${functionName}列表 + */ + @Operation(summary = "导出${functionName}列表") + @PreAuthorize("@ss.hasPermi('${permissionPrefix}:export')") + @Log(title = "${functionName}", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, ${ClassName} ${className}) + { + List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); + ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class); + util.exportExcel(response, list, "${functionName}数据"); + } + + /** + * 获取${functionName}详细信息 + */ + @Operation(summary = "获取${functionName}详细信息") + @PreAuthorize("@ss.hasPermi('${permissionPrefix}:query')") + @GetMapping(value = "/{${pkColumn.javaField}}") + public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField}) + { + return success(${className}Service.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField})); + } + + /** + * 新增${functionName} + */ + @Operation(summary = "新增${functionName}") + @PreAuthorize("@ss.hasPermi('${permissionPrefix}:add')") + @Log(title = "${functionName}", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody ${ClassName} ${className}) + { + return toAjax(${className}Service.insert${ClassName}(${className})); + } + + /** + * 修改${functionName} + */ + @Operation(summary = "修改${functionName}") + @PreAuthorize("@ss.hasPermi('${permissionPrefix}:edit')") + @Log(title = "${functionName}", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody ${ClassName} ${className}) + { + return toAjax(${className}Service.update${ClassName}(${className})); + } + + /** + * 删除${functionName} + */ + @Operation(summary = "删除${functionName}") + @PreAuthorize("@ss.hasPermi('${permissionPrefix}:remove')") + @Log(title = "${functionName}", businessType = BusinessType.DELETE) + @DeleteMapping("/{${pkColumn.javaField}s}") + public AjaxResult remove(@PathVariable( name = "${pkColumn.javaField}s" ) ${pkColumn.javaType}[] ${pkColumn.javaField}s) + { + return toAjax(${className}Service.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s)); + } +} diff --git a/boyue-models/boyue-generator/src/main/resources/vm/java/domain.java.vm b/boyue-models/boyue-generator/src/main/resources/vm/java/domain.java.vm new file mode 100644 index 0000000..4073221 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/java/domain.java.vm @@ -0,0 +1,143 @@ +package ${packageName}.domain; + +#foreach ($import in $importList) +import ${import}; +#end +import io.swagger.v3.oas.annotations.media.Schema; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.boyue.common.annotation.Excel; +#if($table.crud || $table.sub) +#elseif($table.tree) +#end + +/** + * ${functionName}对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +#if($table.crud || $table.sub) +#set($Entity="BaseEntity") +#elseif($table.tree) +#set($Entity="TreeEntity") +#end +@Schema(description = "${functionName}对象") +public class ${ClassName} extends ${Entity} +{ + private static final long serialVersionUID = 1L; + +#foreach ($column in $allColumns) +#if(!$table.isSuperColumn($column.javaField)) + + /** $column.columnComment */ + @Schema(title = "$column.columnComment") +#if($column.list) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($parentheseIndex != -1) + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") +#elseif($column.javaType == 'Date') + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd") +#elseif($column.javaType == 'Time') + @JsonFormat(pattern = "HH:mm:ss") + @Excel(name = "${comment}", width = 30, dateFormat = "HH:mm:ss") +#elseif($column.javaType == 'DateTime') + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") +#else + @Excel(name = "${comment}") +#end +#end + private $column.javaType $column.javaField; +#if($column.subColumnTableName && $table.haveSubColumn == '1') + + /** $column.javaField 到 $column.subColumnTableName 映射 */ + private $column.subColumnJavaType $column.subColumnJavaField; +#end +#end +#end +#if($table.sub) + /** $table.subTable.functionName信息 */ + private List<${subClassName}> ${subclassName}List; + +#end +#foreach ($column in $allColumns) +#if(!$table.isSuperColumn($column.javaField)) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.javaField) +#else +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#end + public void set${AttrName}($column.javaType $column.javaField) + { + this.$column.javaField = $column.javaField; + } + + public $column.javaType get${AttrName}() + { + return $column.javaField; + } + +#if($column.subColumnTableName && $table.haveSubColumn == '1') +#if($column.subColumnJavaField.length() > 2 && $column.subColumnJavaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.subColumnJavaField) +#else +#set($AttrName=$column.subColumnJavaField.substring(0,1).toUpperCase() + ${column.subColumnJavaField.substring(1)}) +#end + public void set${AttrName}($column.subColumnJavaType $column.subColumnJavaField) + { + this.$column.subColumnJavaField = $column.subColumnJavaField; + } + + public $column.subColumnJavaType get${AttrName}() + { + return $column.subColumnJavaField; + } +#end + +#end +#end + +#if($table.sub) + public List<${subClassName}> get${subClassName}List() + { + return ${subclassName}List; + } + + public void set${subClassName}List(List<${subClassName}> ${subclassName}List) + { + this.${subclassName}List = ${subclassName}List; + } + +#end + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) +#foreach ($column in $allColumns) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.javaField) +#else +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#end + .append("${column.javaField}", get${AttrName}()) +#if($column.subColumnTableName && $table.haveSubColumn == '1') +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.subColumnJavaField) +#else +#set($AttrName=$column.subColumnJavaField.substring(0,1).toUpperCase() + ${column.subColumnJavaField.substring(1)}) +#end + .append("${column.subColumnJavaField}", get${AttrName}()) +#end +#end +#if($table.sub) + .append("${subclassName}List", get${subClassName}List()) +#end + .toString(); + } +} diff --git a/boyue-models/boyue-generator/src/main/resources/vm/java/mapper.java.vm b/boyue-models/boyue-generator/src/main/resources/vm/java/mapper.java.vm new file mode 100644 index 0000000..7e7d7c2 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/java/mapper.java.vm @@ -0,0 +1,91 @@ +package ${packageName}.mapper; + +import java.util.List; +import ${packageName}.domain.${ClassName}; +#if($table.sub) +import ${packageName}.domain.${subClassName}; +#end + +/** + * ${functionName}Mapper接口 + * + * @author ${author} + * @date ${datetime} + */ +public interface ${ClassName}Mapper +{ + /** + * 查询${functionName} + * + * @param ${pkColumn.javaField} ${functionName}主键 + * @return ${functionName} + */ + public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}); + + /** + * 查询${functionName}列表 + * + * @param ${className} ${functionName} + * @return ${functionName}集合 + */ + public List<${ClassName}> select${ClassName}List(${ClassName} ${className}); + + /** + * 新增${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ + public int insert${ClassName}(${ClassName} ${className}); + + /** + * 修改${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ + public int update${ClassName}(${ClassName} ${className}); + + /** + * 删除${functionName} + * + * @param ${pkColumn.javaField} ${functionName}主键 + * @return 结果 + */ + public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}); + + /** + * 批量删除${functionName} + * + * @param ${pkColumn.javaField}s 需要删除的数据主键集合 + * @return 结果 + */ + public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s); +#if($table.sub) + + /** + * 批量删除${subTable.functionName} + * + * @param ${pkColumn.javaField}s 需要删除的数据主键集合 + * @return 结果 + */ + public int delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaType}[] ${pkColumn.javaField}s); + + /** + * 批量新增${subTable.functionName} + * + * @param ${subclassName}List ${subTable.functionName}列表 + * @return 结果 + */ + public int batch${subClassName}(List<${subClassName}> ${subclassName}List); + + + /** + * 通过${functionName}主键删除${subTable.functionName}信息 + * + * @param ${pkColumn.javaField} ${functionName}ID + * @return 结果 + */ + public int delete${subClassName}By${subTableFkClassName}(${pkColumn.javaType} ${pkColumn.javaField}); +#end +} diff --git a/boyue-models/boyue-generator/src/main/resources/vm/java/service.java.vm b/boyue-models/boyue-generator/src/main/resources/vm/java/service.java.vm new file mode 100644 index 0000000..264882b --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/java/service.java.vm @@ -0,0 +1,61 @@ +package ${packageName}.service; + +import java.util.List; +import ${packageName}.domain.${ClassName}; + +/** + * ${functionName}Service接口 + * + * @author ${author} + * @date ${datetime} + */ +public interface I${ClassName}Service +{ + /** + * 查询${functionName} + * + * @param ${pkColumn.javaField} ${functionName}主键 + * @return ${functionName} + */ + public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}); + + /** + * 查询${functionName}列表 + * + * @param ${className} ${functionName} + * @return ${functionName}集合 + */ + public List<${ClassName}> select${ClassName}List(${ClassName} ${className}); + + /** + * 新增${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ + public int insert${ClassName}(${ClassName} ${className}); + + /** + * 修改${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ + public int update${ClassName}(${ClassName} ${className}); + + /** + * 批量删除${functionName} + * + * @param ${pkColumn.javaField}s 需要删除的${functionName}主键集合 + * @return 结果 + */ + public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s); + + /** + * 删除${functionName}信息 + * + * @param ${pkColumn.javaField} ${functionName}主键 + * @return 结果 + */ + public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}); +} diff --git a/boyue-models/boyue-generator/src/main/resources/vm/java/serviceImpl.java.vm b/boyue-models/boyue-generator/src/main/resources/vm/java/serviceImpl.java.vm new file mode 100644 index 0000000..419362a --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/java/serviceImpl.java.vm @@ -0,0 +1,169 @@ +package ${packageName}.service.impl; + +import java.util.List; +#foreach ($column in $columns) +#if($column.javaField == 'createTime' || $column.javaField == 'updateTime') +import com.boyue.common.utils.DateUtils; +#break +#end +#end +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +#if($table.sub) +import java.util.ArrayList; +import com.boyue.common.utils.StringUtils; +import org.springframework.transaction.annotation.Transactional; +import ${packageName}.domain.${subClassName}; +#end +import ${packageName}.mapper.${ClassName}Mapper; +import ${packageName}.domain.${ClassName}; +import ${packageName}.service.I${ClassName}Service; + +/** + * ${functionName}Service业务层处理 + * + * @author ${author} + * @date ${datetime} + */ +@Service +public class ${ClassName}ServiceImpl implements I${ClassName}Service +{ + @Autowired + private ${ClassName}Mapper ${className}Mapper; + + /** + * 查询${functionName} + * + * @param ${pkColumn.javaField} ${functionName}主键 + * @return ${functionName} + */ + @Override + public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}) + { + return ${className}Mapper.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}); + } + + /** + * 查询${functionName}列表 + * + * @param ${className} ${functionName} + * @return ${functionName} + */ + @Override + public List<${ClassName}> select${ClassName}List(${ClassName} ${className}) + { + return ${className}Mapper.select${ClassName}List(${className}); + } + + /** + * 新增${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ +#if($table.sub) + @Transactional +#end + @Override + public int insert${ClassName}(${ClassName} ${className}) + { +#foreach ($column in $columns) +#if($column.javaField == 'createTime') + ${className}.setCreateTime(DateUtils.getNowDate()); +#end +#end +#if($table.sub) + int rows = ${className}Mapper.insert${ClassName}(${className}); + insert${subClassName}(${className}); + return rows; +#else + return ${className}Mapper.insert${ClassName}(${className}); +#end + } + + /** + * 修改${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ +#if($table.sub) + @Transactional +#end + @Override + public int update${ClassName}(${ClassName} ${className}) + { +#foreach ($column in $columns) +#if($column.javaField == 'updateTime') + ${className}.setUpdateTime(DateUtils.getNowDate()); +#end +#end +#if($table.sub) + ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${className}.get${pkColumn.capJavaField}()); + insert${subClassName}(${className}); +#end + return ${className}Mapper.update${ClassName}(${className}); + } + + /** + * 批量删除${functionName} + * + * @param ${pkColumn.javaField}s 需要删除的${functionName}主键 + * @return 结果 + */ +#if($table.sub) + @Transactional +#end + @Override + public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s) + { +#if($table.sub) + ${className}Mapper.delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaField}s); +#end + return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s); + } + + /** + * 删除${functionName}信息 + * + * @param ${pkColumn.javaField} ${functionName}主键 + * @return 结果 + */ +#if($table.sub) + @Transactional +#end + @Override + public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}) + { +#if($table.sub) + ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${pkColumn.javaField}); +#end + return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}); + } +#if($table.sub) + + /** + * 新增${subTable.functionName}信息 + * + * @param ${className} ${functionName}对象 + */ + public void insert${subClassName}(${ClassName} ${className}) + { + List<${subClassName}> ${subclassName}List = ${className}.get${subClassName}List(); + ${pkColumn.javaType} ${pkColumn.javaField} = ${className}.get${pkColumn.capJavaField}(); + if (StringUtils.isNotNull(${subclassName}List)) + { + List<${subClassName}> list = new ArrayList<${subClassName}>(); + for (${subClassName} ${subclassName} : ${subclassName}List) + { + ${subclassName}.set${subTableFkClassName}(${pkColumn.javaField}); + list.add(${subclassName}); + } + if (list.size() > 0) + { + ${className}Mapper.batch${subClassName}(list); + } + } + } +#end +} diff --git a/boyue-models/boyue-generator/src/main/resources/vm/java/sub-domain.java.vm b/boyue-models/boyue-generator/src/main/resources/vm/java/sub-domain.java.vm new file mode 100644 index 0000000..7c63236 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/java/sub-domain.java.vm @@ -0,0 +1,75 @@ +package ${packageName}.domain; + +#foreach ($import in $subImportList) +import ${import}; +#end +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.boyue.common.annotation.Excel; + +/** + * ${subTable.functionName}对象 ${subTableName} + * + * @author ${author} + * @date ${datetime} + */ +public class ${subClassName} extends BaseEntity +{ + private static final long serialVersionUID = 1L; + +#foreach ($column in $subTable.columns) +#if(!$table.isSuperColumn($column.javaField)) + /** $column.columnComment */ +#if($column.list) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($parentheseIndex != -1) + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") +#elseif($column.javaType == 'Date') + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd") +#else + @Excel(name = "${comment}") +#end +#end + private $column.javaType $column.javaField; + +#end +#end +#foreach ($column in $subTable.columns) +#if(!$table.isSuperColumn($column.javaField)) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.javaField) +#else +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#end + public void set${AttrName}($column.javaType $column.javaField) + { + this.$column.javaField = $column.javaField; + } + + public $column.javaType get${AttrName}() + { + return $column.javaField; + } +#end +#end + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) +#foreach ($column in $subTable.columns) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.javaField) +#else +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#end + .append("${column.javaField}", get${AttrName}()) +#end + .toString(); + } +} diff --git a/boyue-models/boyue-generator/src/main/resources/vm/js/api.js.vm b/boyue-models/boyue-generator/src/main/resources/vm/js/api.js.vm new file mode 100644 index 0000000..9295524 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/js/api.js.vm @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询${functionName}列表 +export function list${BusinessName}(query) { + return request({ + url: '/${moduleName}/${businessName}/list', + method: 'get', + params: query + }) +} + +// 查询${functionName}详细 +export function get${BusinessName}(${pkColumn.javaField}) { + return request({ + url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, + method: 'get' + }) +} + +// 新增${functionName} +export function add${BusinessName}(data) { + return request({ + url: '/${moduleName}/${businessName}', + method: 'post', + data: data + }) +} + +// 修改${functionName} +export function update${BusinessName}(data) { + return request({ + url: '/${moduleName}/${businessName}', + method: 'put', + data: data + }) +} + +// 删除${functionName} +export function del${BusinessName}(${pkColumn.javaField}) { + return request({ + url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, + method: 'delete' + }) +} diff --git a/boyue-models/boyue-generator/src/main/resources/vm/sql/sql.vm b/boyue-models/boyue-generator/src/main/resources/vm/sql/sql.vm new file mode 100644 index 0000000..0575583 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/sql/sql.vm @@ -0,0 +1,22 @@ +-- 菜单 SQL +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate(), '', null, '${functionName}菜单'); + +-- 按钮父菜单ID +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}查询', @parentId, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', sysdate(), '', null, ''); + +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}新增', @parentId, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', sysdate(), '', null, ''); + +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}修改', @parentId, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', sysdate(), '', null, ''); + +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}删除', @parentId, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', sysdate(), '', null, ''); + +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}导出', @parentId, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', sysdate(), '', null, ''); \ No newline at end of file diff --git a/boyue-models/boyue-generator/src/main/resources/vm/uniapp/edit.vue.vm b/boyue-models/boyue-generator/src/main/resources/vm/uniapp/edit.vue.vm new file mode 100644 index 0000000..c0b02a8 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/uniapp/edit.vue.vm @@ -0,0 +1,155 @@ + + + diff --git a/boyue-models/boyue-generator/src/main/resources/vm/uniapp/list.vue.vm b/boyue-models/boyue-generator/src/main/resources/vm/uniapp/list.vue.vm new file mode 100644 index 0000000..98acb4e --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/uniapp/list.vue.vm @@ -0,0 +1,140 @@ + + + diff --git a/boyue-models/boyue-generator/src/main/resources/vm/uniapp/show.vue.vm b/boyue-models/boyue-generator/src/main/resources/vm/uniapp/show.vue.vm new file mode 100644 index 0000000..1b4a86e --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/uniapp/show.vue.vm @@ -0,0 +1,85 @@ + + + diff --git a/boyue-models/boyue-generator/src/main/resources/vm/vue/v2/index-tree.vue.vm b/boyue-models/boyue-generator/src/main/resources/vm/vue/v2/index-tree.vue.vm new file mode 100644 index 0000000..b4059ff --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/vue/v2/index-tree.vue.vm @@ -0,0 +1,575 @@ + + + diff --git a/boyue-models/boyue-generator/src/main/resources/vm/vue/v2/index.vue.vm b/boyue-models/boyue-generator/src/main/resources/vm/vue/v2/index.vue.vm new file mode 100644 index 0000000..77ddd15 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/vue/v2/index.vue.vm @@ -0,0 +1,672 @@ + + + diff --git a/boyue-models/boyue-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm b/boyue-models/boyue-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm new file mode 100644 index 0000000..7bbd2fc --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm @@ -0,0 +1,474 @@ + + + diff --git a/boyue-models/boyue-generator/src/main/resources/vm/vue/v3/index.vue.vm b/boyue-models/boyue-generator/src/main/resources/vm/vue/v3/index.vue.vm new file mode 100644 index 0000000..ceef8d4 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/vue/v3/index.vue.vm @@ -0,0 +1,642 @@ + + + diff --git a/boyue-models/boyue-generator/src/main/resources/vm/xml/mapper.xml.vm b/boyue-models/boyue-generator/src/main/resources/vm/xml/mapper.xml.vm new file mode 100644 index 0000000..f7866f4 --- /dev/null +++ b/boyue-models/boyue-generator/src/main/resources/vm/xml/mapper.xml.vm @@ -0,0 +1,167 @@ + + + + + +#foreach ($column in $columns) + +#end +#if($joinColunms) +#foreach ($column in $joinColunms) + +#end +#end + +#if($table.sub) + + + + + + +#foreach ($column in $subTable.columns) + +#end + +#end + + + select +#foreach ($column in $allColumns) +#set($columnName=$columnMap[$column.columnId].columnName) +#set($tableAlias=$tableAliasMap[$column.tableId]) + $tableAlias.$columnName#if($foreach.hasNext),#end +#end + from $table.tableName $table.tableAlias +#if($joinTablesMate) +#foreach($joinTable in $joinTablesMate) +#set($leftColumnName=$columnMap[$joinTable.leftTableFk].columnName) +#set($leftTableAlias=$joinTable.leftTableAlias) +#set($rightColumnName=$columnMap[$joinTable.rightTableFk].columnName) +#set($rightTableAlias=$joinTable.rightTableAlias) +#set($newTableName=$tableMap[$joinTable.newTableId].tableName) +#set($newTableAlias=$tableAliasMap[$joinTable.newTableId]) + ${joinTable.joinType} join $newTableName $newTableAlias on $rightTableAlias.$rightColumnName = $leftTableAlias.$leftColumnName +#end +#end + + + + + + + + insert into ${tableName} + +#foreach($column in $columns) +#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment) + $column.columnName, +#end +#end + + +#foreach($column in $columns) +#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment) + #{$column.javaField}, +#end +#end + + + + + update ${tableName} + +#foreach($column in $columns) +#if($column.columnName != $pkColumn.columnName) + $column.columnName = #{$column.javaField}, +#end +#end + +#if($table.haveSubColumn == '1') + where ${pkColumn.columnName} = #{${pkColumn.javaField}} +#else + where ${tableName}.${pkColumn.columnName} = #{${pkColumn.javaField}} +#end + + + + delete from ${tableName} where ${pkColumn.columnName} = #{${pkColumn.javaField}} + + + + delete from ${tableName} where ${pkColumn.columnName} in + + #{${pkColumn.javaField}} + + +#if($table.sub) + + + delete from ${subTableName} where ${subTableFkName} in + + #{${subTableFkclassName}} + + + + + delete from ${subTableName} where ${subTableFkName} = #{${subTableFkclassName}} + + + + insert into ${subTableName}(#foreach($column in $subTable.columns) $column.columnName#if($foreach.count != $subTable.columns.size()),#end#end) values + + (#foreach($column in $subTable.columns) #{item.$column.javaField}#if($foreach.count != $subTable.columns.size()),#end#end) + + +#end + \ No newline at end of file diff --git a/boyue-models/boyue-hasfj/pom.xml b/boyue-models/boyue-hasfj/pom.xml new file mode 100644 index 0000000..1a07eb3 --- /dev/null +++ b/boyue-models/boyue-hasfj/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + com.boyue + boyue-models + 3.8.9-G + + + boyue-hasfj + + + 21 + 21 + UTF-8 + + + 淮安市司法局模块 + + + + + + com.boyue + boyue-framework + + + + + com.boyue + boyue-common + + + + \ No newline at end of file diff --git a/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/controller/ApiController.java b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/controller/ApiController.java new file mode 100644 index 0000000..368031c --- /dev/null +++ b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/controller/ApiController.java @@ -0,0 +1,46 @@ +package com.boyue.hasfj.controller; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.hasfj.domain.HtmlPages; +import com.boyue.hasfj.service.IHtmlPagesService; +import com.github.pagehelper.PageHelper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +/** + * 司法局前端API接口 + * + * @author boyue + */ +@RestController +@RequestMapping("/api/hasfj") +@Tag(name = "司法局前端API接口") +public class ApiController extends BaseController +{ + @Autowired + private IHtmlPagesService htmlPagesService; + + /** + * 获取二维码数据列表 + */ + @Operation(summary = "获取二维码数据列表") + @GetMapping("/qrcodes") + public TableDataInfo getQRCodes( + @RequestParam(value = "type", required = false, defaultValue = "law") String type, + @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum, + @RequestParam(value = "pageSize", required = false, defaultValue = "6") Integer pageSize) { + PageHelper.startPage(pageNum, pageSize); + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setPageType(type); + htmlPages.setStatus(1); // 只查询启用状态的 + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + return getDataTable(list); + } +} \ No newline at end of file diff --git a/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/controller/FrontendController.java b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/controller/FrontendController.java new file mode 100644 index 0000000..6992b60 --- /dev/null +++ b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/controller/FrontendController.java @@ -0,0 +1,47 @@ +package com.boyue.hasfj.controller; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.constant.HttpStatus; +import com.boyue.hasfj.domain.HtmlPages; +import com.boyue.hasfj.service.IHtmlPagesService; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import io.swagger.v3.oas.annotations.Operation; + +@RestController +@RequestMapping("/frontend") +public class FrontendController extends BaseController +{ + @Autowired + private IHtmlPagesService htmlPagesService; + + /** + * 获取二维码数据列表 + */ + @Operation(summary = "获取二维码数据列表") + @GetMapping("/qrcodes") + public AjaxResult getQRCodes( + @RequestParam(value = "type", required = false, defaultValue = "law") String type, + @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum, + @RequestParam(value = "pageSize", required = false, defaultValue = "6") Integer pageSize) { + PageHelper.startPage(pageNum, pageSize); + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setPageType(type); + htmlPages.setStatus(1); // 只查询启用状态的 + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + TableDataInfo tableDataInfo = new TableDataInfo(); + tableDataInfo.setCode(HttpStatus.SUCCESS); + tableDataInfo.setMsg("查询成功"); + tableDataInfo.setRows(list); + tableDataInfo.setTotal(new PageInfo(list).getTotal()); + return success(tableDataInfo); + } +} \ No newline at end of file diff --git a/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/controller/HtmlPageApiController.java b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/controller/HtmlPageApiController.java new file mode 100644 index 0000000..6315371 --- /dev/null +++ b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/controller/HtmlPageApiController.java @@ -0,0 +1,569 @@ +package com.boyue.hasfj.controller; + +import java.util.List; +import java.util.ArrayList; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.hasfj.domain.HtmlPages; +import com.boyue.hasfj.service.IHtmlPagesService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +import jakarta.servlet.http.HttpServletRequest; + +/** + * 页面API控制器 + * + * @author boyue + */ +@RestController +@RequestMapping("/api/hasfj") +@Tag(name = "页面API接口") +public class HtmlPageApiController extends BaseController { + + @Autowired + private IHtmlPagesService htmlPagesService; + + /** + * 获取页面详情 + */ + @GetMapping("/page") + @Operation(summary = "获取页面详情") + public AjaxResult getPageDetail(@RequestParam(value = "type", required = true) String pageType, + @RequestParam(value = "formatId", required = true) String formatId) { + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setPageType(pageType); + htmlPages.setFormatId(formatId); + htmlPages.setStatus(Integer.valueOf(1)); // 只查询启用状态的 + + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + if (list != null && !list.isEmpty()) { + HtmlPages page = list.get(0); + // 使用专门的方法更新浏览次数 + htmlPagesService.updateHtmlPagesViewCount(page.getId()); + // 重新查询最新数据 + page = htmlPagesService.selectHtmlPagesById(page.getId()); + + return AjaxResult.success(page); + } + + return AjaxResult.error("未找到相关页面"); + } + + /** + * 根据ID获取页面 - 增加类型检查防止非数字字符串作为ID传入 + */ + @GetMapping("/page/{id}") + @Operation(summary = "根据ID获取页面") + public AjaxResult getPageById(@PathVariable(value = "id", required = true) String idStr) { + // 添加参数验证,确保ID是有效的数字 + try { + // 尝试将ID转换为Long类型 + Long id = Long.valueOf(idStr); + HtmlPages htmlPages = htmlPagesService.selectHtmlPagesById(id); + if (htmlPages != null) { + // 使用专门的方法更新浏览次数 + htmlPagesService.updateHtmlPagesViewCount(htmlPages.getId()); + // 重新查询最新数据 + htmlPages = htmlPagesService.selectHtmlPagesById(htmlPages.getId()); + + return AjaxResult.success(htmlPages); + } + return AjaxResult.error("未找到ID为" + id + "的页面"); + } catch (NumberFormatException e) { + // 如果ID不是有效的数字,返回错误信息 + return AjaxResult.error("无效的页面ID: " + idStr + ",请提供有效的数字ID"); + } + } + + /** + * 获取页面列表 + */ + @GetMapping("/pages") + @Operation(summary = "获取页面列表") + public AjaxResult getPages(@RequestParam(value = "type", required = false) String pageType) { + HtmlPages htmlPages = new HtmlPages(); + if (pageType != null && !pageType.isEmpty()) { + htmlPages.setPageType(pageType); + } + htmlPages.setStatus(Integer.valueOf(1)); // 只查询启用状态的 + + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + return AjaxResult.success(list); + } + + /** + * 根据类型获取页面列表 + */ + @GetMapping("/hasfjpages/listByType/{pageType}") + @Operation(summary = "根据类型获取页面列表") + public AjaxResult getPagesByType(@PathVariable("pageType") String pageType) { + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setPageType(pageType); + htmlPages.setStatus(Integer.valueOf(1)); // 只查询启用状态的 + + startPage(); // 使用不带参数的分页方法,会自动从请求参数中获取分页信息 + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + return AjaxResult.success(getDataTable(list)); + } + + /** + * 获取法律规定列表 + */ + @GetMapping("/laws") + @Operation(summary = "获取法律规定列表") + public AjaxResult getLaws() { + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setPageType("law"); + htmlPages.setStatus(Integer.valueOf(1)); + + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + return AjaxResult.success(list); + } + + /** + * 获取典型案例列表 + */ + @GetMapping("/cases") + @Operation(summary = "获取典型案例列表") + public AjaxResult getCases() { + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setPageType("case"); + htmlPages.setStatus(Integer.valueOf(1)); + + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + return AjaxResult.success(list); + } + + /** + * 获取表单下载列表 + */ + @GetMapping("/forms") + @Operation(summary = "获取表单下载列表") + public AjaxResult getForms() { + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setPageType("form"); + htmlPages.setStatus(Integer.valueOf(1)); + + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + return AjaxResult.success(list); + } + + /** + * 搜索API + */ + @GetMapping("/search") + @Operation(summary = "搜索内容") + public AjaxResult search( + @RequestParam(value = "keyword", required = false) String keyword, + @RequestParam(value = "q", required = false) String q, + @RequestParam(value = "content", required = false) String content, + @RequestParam(value = "type", required = false) String pageType) { + + // 按优先级选择搜索关键词 + String searchText = keyword; + if (searchText == null || searchText.trim().isEmpty()) { + searchText = q; + } + if (searchText == null || searchText.trim().isEmpty()) { + searchText = content; + } + + if (searchText == null || searchText.trim().isEmpty()) { + return AjaxResult.error("搜索关键词不能为空"); + } + + HtmlPages searchCondition = new HtmlPages(); + searchCondition.setStatus(Integer.valueOf(1)); // 只搜索启用状态的内容 + if (pageType != null && !pageType.trim().isEmpty()) { + searchCondition.setPageType(pageType); + } + + List allPages = htmlPagesService.selectHtmlPagesList(searchCondition); + List searchResults = new ArrayList<>(); + + if (allPages != null && !allPages.isEmpty()) { + // 在标题和内容中搜索关键词 + String keywordLower = searchText.toLowerCase(); + searchResults = allPages.stream() + .filter(page -> { + String title = page.getTitle() != null ? page.getTitle().toLowerCase() : ""; + String pageContent = page.getContent() != null ? page.getContent().toLowerCase() : ""; + String desc = page.getDescription() != null ? page.getDescription().toLowerCase() : ""; + String keys = page.getKeywords() != null ? page.getKeywords().toLowerCase() : ""; + + return title.contains(keywordLower) || + pageContent.contains(keywordLower) || + desc.contains(keywordLower) || + keys.contains(keywordLower); + }) + .collect(Collectors.toList()); + } + + return AjaxResult.success(searchResults); + } + + /** + * 搜索API - 前端路径兼容版本 + */ + @GetMapping({"/hasfjpages/search", "/search"}) + @Operation(summary = "搜索内容(前端兼容版)") + public AjaxResult searchFrontend( + @RequestParam(value = "keyword", required = false) String keyword, + @RequestParam(value = "q", required = false) String q, + @RequestParam(value = "content", required = false) String content, + @RequestParam(value = "type", required = false) String pageType, + @RequestParam(value = "pageType", required = false) String pageTypeAlt, + @RequestParam(value = "stringQuery", required = false) String stringQuery) { + + try { + // 获取可能的ID参数,但不使用@RequestParam注解 + // 因为@RequestParam对于特定类型的参数会尝试自动类型转换,可能导致错误 + String idStr = null; + try { + // 手动从请求参数中获取id,避免Spring自动类型转换导致的错误 + idStr = this.getRequest().getParameter("id"); + System.out.println("手动获取id参数: " + idStr); + } catch (Exception e) { + System.out.println("获取id参数时出错: " + e.getMessage()); + } + + System.out.println("搜索请求参数: keyword=" + keyword + ", q=" + q + ", content=" + content + + ", type=" + pageType + ", pageType=" + pageTypeAlt + + ", id=" + idStr + ", stringQuery=" + stringQuery); + + // 检测参数值是否含有前缀,如果有则移除前缀 + if (keyword != null && keyword.startsWith("keyword:")) { + keyword = keyword.substring("keyword:".length()); + } + if (q != null && q.startsWith("keyword:")) { + q = q.substring("keyword:".length()); + } + if (content != null && content.startsWith("keyword:")) { + content = content.substring("keyword:".length()); + } + + // 特殊关键词处理,如果搜索关键词为"search"、"如何"等特殊词,强制使用字符串搜索模式 + boolean forceStringSearch = "true".equalsIgnoreCase(stringQuery); + + // 扩展特殊关键词列表,包括"如何"、"search"等 + String[] specialKeywords = {"search", "如何", "怎么", "怎样", "什么", "哪些", "为什么"}; + + // 检查所有可能的参数是否包含特殊关键词 + if (containsSpecialKeyword(keyword, specialKeywords) || + containsSpecialKeyword(q, specialKeywords) || + containsSpecialKeyword(content, specialKeywords) || + containsSpecialKeyword(idStr, specialKeywords)) { + forceStringSearch = true; + System.out.println("检测到特殊关键词,启用强制字符串搜索模式"); + } + + // 按优先级选择搜索关键词 + String searchText = keyword; + if (searchText == null || searchText.trim().isEmpty()) { + searchText = q; + } + if (searchText == null || searchText.trim().isEmpty()) { + searchText = content; + } + if (searchText == null || searchText.trim().isEmpty() && !forceStringSearch && idStr != null && !isSpecialKeyword(idStr)) { + searchText = idStr; // 如果ID不是数字且不是特殊关键词,当作关键词使用 + } + + if (searchText == null || searchText.trim().isEmpty()) { + return AjaxResult.error("搜索关键词不能为空"); + } + + System.out.println("最终使用的搜索文本: " + searchText + ", 强制字符串搜索模式: " + forceStringSearch); + + // 确定页面类型 + String finalPageType = pageType; + if (finalPageType == null || finalPageType.trim().isEmpty()) { + finalPageType = pageTypeAlt; + } + + // 直接调用专用搜索API + return searchContent(searchText, finalPageType); + } catch (Exception ex) { + System.out.println("搜索接口全局异常: " + ex.getMessage()); + ex.printStackTrace(); + return AjaxResult.error("搜索服务异常,请稍后重试"); + } + } + + /** + * 判断字符串是否包含特殊关键词 + */ + private boolean containsSpecialKeyword(String text, String[] specialKeywords) { + if (text == null || text.trim().isEmpty()) { + return false; + } + + String lowerText = text.toLowerCase(); + for (String keyword : specialKeywords) { + if (lowerText.contains(keyword.toLowerCase())) { + System.out.println("检测到特殊关键词: " + keyword + " 在文本: " + text); + return true; + } + } + + return false; + } + + /** + * 判断字符串是否为特殊关键词 + */ + private boolean isSpecialKeyword(String text) { + if (text == null || text.trim().isEmpty()) { + return false; + } + + String[] specialKeywords = {"search", "如何", "怎么", "怎样", "什么", "哪些", "为什么"}; + String lowerText = text.toLowerCase(); + + for (String keyword : specialKeywords) { + if (lowerText.equals(keyword.toLowerCase())) { + return true; + } + } + + // 检查是否为纯数字 + try { + Long.parseLong(text); + return false; // 是纯数字,不是特殊关键词 + } catch (NumberFormatException e) { + return true; // 不是纯数字,视为特殊关键词 + } + } + + /** + * 搜索API - 纯文本搜索端点,无ID参数干扰 + */ + @GetMapping("/search-text") + @Operation(summary = "全文搜索(无ID冲突)") + public AjaxResult searchText( + @RequestParam(value = "keyword", required = false) String keyword, + @RequestParam(value = "type", required = false) String pageType) { + + System.out.println("全文搜索请求: keyword=" + keyword + ", type=" + pageType); + + if (keyword == null || keyword.trim().isEmpty()) { + return AjaxResult.error("搜索关键词不能为空"); + } + + HtmlPages searchCondition = new HtmlPages(); + searchCondition.setStatus(Integer.valueOf(1)); // 只搜索启用状态的内容 + if (pageType != null && !pageType.trim().isEmpty()) { + searchCondition.setPageType(pageType); + } + + try { + // 获取所有启用状态的页面 + List allPages = htmlPagesService.selectHtmlPagesList(searchCondition); + List searchResults = new ArrayList<>(); + + if (allPages != null && !allPages.isEmpty()) { + // 在标题和内容中搜索关键词 + String keywordLower = keyword.toLowerCase(); + searchResults = allPages.stream() + .filter(page -> { + String title = page.getTitle() != null ? page.getTitle().toLowerCase() : ""; + String pageContent = page.getContent() != null ? page.getContent().toLowerCase() : ""; + String desc = page.getDescription() != null ? page.getDescription().toLowerCase() : ""; + String keys = page.getKeywords() != null ? page.getKeywords().toLowerCase() : ""; + + return title.contains(keywordLower) || + pageContent.contains(keywordLower) || + desc.contains(keywordLower) || + keys.contains(keywordLower); + }) + .collect(Collectors.toList()); + } + + System.out.println("全文搜索结果数量: " + searchResults.size()); + return AjaxResult.success(searchResults); + } catch (Exception e) { + System.out.println("全文搜索出错: " + e.getMessage()); + e.printStackTrace(); + return AjaxResult.error("搜索服务异常,请稍后重试"); + } + } + + /** + * 专用搜索API - 全新路径,避免与任何现有API冲突 + */ + @GetMapping("/search-content") + @Operation(summary = "专用内容搜索API") + public AjaxResult searchContent(@RequestParam(value = "keyword", required = false) String keyword, + @RequestParam(value = "type", required = false) String pageType) { + System.out.println("专用搜索API调用: keyword=" + keyword + ", type=" + pageType); + + try { + // 参数验证和处理 + if (keyword == null || keyword.trim().isEmpty()) { + System.out.println("搜索关键词为空,返回错误"); + return AjaxResult.error("搜索关键词不能为空"); + } + + // 记录关键词信息 + System.out.println("处理搜索关键词: " + keyword); + + // 检查是否为特殊关键词 + String[] specialKeywords = {"search", "如何", "怎么", "怎样", "什么", "哪些", "为什么"}; + boolean isSpecial = false; + for (String special : specialKeywords) { + if (keyword.toLowerCase().contains(special.toLowerCase())) { + isSpecial = true; + System.out.println("检测到特殊关键词: " + special + " 在搜索文本中"); + break; + } + } + + // 构建搜索条件 + HtmlPages searchCondition = new HtmlPages(); + searchCondition.setStatus(Integer.valueOf(1)); // 只搜索启用状态的内容 + + if (pageType != null && !pageType.trim().isEmpty()) { + searchCondition.setPageType(pageType); + System.out.println("按类型搜索: " + pageType); + } else { + System.out.println("搜索所有类型"); + } + + try { + // 获取所有启用状态的页面 + System.out.println("开始查询数据库..."); + List allPages = htmlPagesService.selectHtmlPagesList(searchCondition); + System.out.println("数据库查询完成,总记录数: " + (allPages != null ? allPages.size() : 0)); + + List searchResults = new ArrayList<>(); + + if (allPages != null && !allPages.isEmpty()) { + // 在标题和内容中搜索关键词 + String keywordLower = keyword.toLowerCase(); + searchResults = allPages.stream() + .filter(page -> { + // 获取页面各字段,防止空值 + String title = page.getTitle() != null ? page.getTitle().toLowerCase() : ""; + String pageContent = page.getContent() != null ? page.getContent().toLowerCase() : ""; + String desc = page.getDescription() != null ? page.getDescription().toLowerCase() : ""; + String keys = page.getKeywords() != null ? page.getKeywords().toLowerCase() : ""; + String formatId = page.getFormatId() != null ? page.getFormatId().toLowerCase() : ""; + String author = page.getAuthor() != null ? page.getAuthor().toLowerCase() : ""; + + // 对所有字段进行关键词匹配,实现全局搜索 + boolean matches = title.contains(keywordLower) || + pageContent.contains(keywordLower) || + desc.contains(keywordLower) || + keys.contains(keywordLower) || + formatId.contains(keywordLower) || + author.contains(keywordLower); + + if (matches) { + System.out.println("找到匹配: ID=" + page.getId() + ", 标题=" + page.getTitle() + ", 类型=" + page.getPageType()); + } + + return matches; + }) + .collect(Collectors.toList()); + + // 将匹配度最高的结果排在前面(标题匹配优先于内容匹配) + searchResults.sort((a, b) -> { + String aTitle = a.getTitle() != null ? a.getTitle().toLowerCase() : ""; + String bTitle = b.getTitle() != null ? b.getTitle().toLowerCase() : ""; + + boolean aTitleMatch = aTitle.contains(keywordLower); + boolean bTitleMatch = bTitle.contains(keywordLower); + + if (aTitleMatch && !bTitleMatch) { + return -1; + } else if (!aTitleMatch && bTitleMatch) { + return 1; + } else { + return 0; + } + }); + } + + System.out.println("专用搜索API搜索结果数量: " + searchResults.size()); + + // 返回成功结果 + AjaxResult result = AjaxResult.success(searchResults); + result.put("total", searchResults.size()); + return result; + } catch (Exception e) { + System.out.println("专用搜索API出错: " + e.getMessage()); + e.printStackTrace(); + return AjaxResult.error("搜索服务异常,请稍后重试: " + e.getMessage()); + } + } catch (Exception ex) { + System.out.println("专用搜索API全局异常: " + ex.getMessage()); + ex.printStackTrace(); + return AjaxResult.error("搜索服务异常,请稍后重试"); + } + } + + /** + * 为确保向后兼容,添加一个额外的搜索端点,与前端路径匹配 + */ + @GetMapping("/hasfjpages/search-content") + @Operation(summary = "专用内容搜索API(前端兼容版)") + public AjaxResult searchContentFrontend(@RequestParam(value = "keyword", required = true) String keyword, + @RequestParam(value = "type", required = false) String pageType) { + // 调用主要的搜索方法 + return searchContent(keyword, pageType); + } + + /** + * 新增:前端搜索API - 无需前缀路径,直接支持/hasfj/search-content + */ + @GetMapping("/hasfj/search-content") + @Operation(summary = "前端直接搜索API") + public AjaxResult directSearchContent(@RequestParam(value = "keyword", required = true) String keyword, + @RequestParam(value = "type", required = false) String pageType) { + // 调用主要的搜索方法 + return searchContent(keyword, pageType); + } + + /** + * 新增:搜索API - 处理所有搜索请求的通用端点 + * 此端点不会与ID路径冲突,专门用于处理搜索请求 + */ + @GetMapping("/search-api") + @Operation(summary = "通用搜索API") + public AjaxResult searchApi(@RequestParam(value = "keyword", required = true) String keyword, + @RequestParam(value = "type", required = false) String pageType) { + // 调用主要的搜索方法 + return searchContent(keyword, pageType); + } + + /** + * 新增:前端搜索API - 前端兼容版本 + */ + @GetMapping("/hasfjpages/search-api") + @Operation(summary = "通用搜索API(前端兼容版)") + public AjaxResult searchApiFrontend(@RequestParam(value = "keyword", required = true) String keyword, + @RequestParam(value = "type", required = false) String pageType) { + // 调用主要的搜索方法 + return searchContent(keyword, pageType); + } + + /** + * 获取当前请求对象 + */ + private HttpServletRequest getRequest() { + return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + } +} \ No newline at end of file diff --git a/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/controller/HtmlPageViewController.java b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/controller/HtmlPageViewController.java new file mode 100644 index 0000000..17e9553 --- /dev/null +++ b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/controller/HtmlPageViewController.java @@ -0,0 +1,171 @@ +package com.boyue.hasfj.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.hasfj.domain.HtmlPages; +import com.boyue.hasfj.service.IHtmlPagesService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +import java.util.List; + +/** + * 页面前端视图控制器 + * + * @author boyue + */ +@Controller +@Tag(name = "页面前端视图") +public class HtmlPageViewController extends BaseController { + + @Autowired + private IHtmlPagesService htmlPagesService; + + /** + * 首页 + */ + @GetMapping("/hasfj") + @Operation(summary = "淮安市司法局首页") + public String index() { + return "hasfj/index"; + } + + /** + * 法律规定页面列表 + */ + @GetMapping("/hasfjlaw") + @Operation(summary = "法律规定页面列表") + public String lawList(ModelMap modelMap) { + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setPageType("law"); + htmlPages.setStatus(1); // 只查询启用状态的 + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + modelMap.put("lawList", list); + return "hasfj/law_list"; + } + + /** + * 典型案例页面列表 + */ + @GetMapping("/hasfjcase") + @Operation(summary = "典型案例页面列表") + public String caseList(ModelMap modelMap) { + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setPageType("case"); + htmlPages.setStatus(1); // 只查询启用状态的 + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + modelMap.put("caseList", list); + return "hasfj/case_list"; + } + + /** + * 表单下载页面列表 + */ + @GetMapping("/hasfjform") + @Operation(summary = "表单下载页面列表") + public String formList(ModelMap modelMap) { + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setPageType("form"); + htmlPages.setStatus(1); // 只查询启用状态的 + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + modelMap.put("formList", list); + return "hasfj/form_list"; + } + + /** + * 法律规定页面 + */ + @GetMapping("/show.html") + @Operation(summary = "法律规定页面") + public String showLawPage(@RequestParam(value = "Id", required = true) String formatId, ModelMap modelMap) { + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setFormatId(formatId); + htmlPages.setPageType("law"); + htmlPages.setStatus(1); // 只查询启用状态的 + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + + if (list != null && !list.isEmpty()) { + HtmlPages page = list.get(0); + // 使用专门的方法更新浏览次数 + htmlPagesService.updateHtmlPagesViewCount(page.getId()); + // 重新查询最新数据 + page = htmlPagesService.selectHtmlPagesById(page.getId()); + + modelMap.put("page", page); + return "hasfj/law"; + } + return "error/404"; + } + + /** + * 典型案例页面 + */ + @GetMapping("/showcase.html") + @Operation(summary = "典型案例页面") + public String showCasePage(@RequestParam(value = "Id", required = true) String formatId, ModelMap modelMap) { + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setFormatId(formatId); + htmlPages.setPageType("case"); + htmlPages.setStatus(1); // 只查询启用状态的 + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + + if (list != null && !list.isEmpty()) { + HtmlPages page = list.get(0); + // 使用专门的方法更新浏览次数 + htmlPagesService.updateHtmlPagesViewCount(page.getId()); + // 重新查询最新数据 + page = htmlPagesService.selectHtmlPagesById(page.getId()); + + modelMap.put("page", page); + return "hasfj/case"; + } + return "error/404"; + } + + /** + * 表单下载页面 + */ + @GetMapping("/table.html") + @Operation(summary = "表单下载页面") + public String showFormPage(@RequestParam(value = "Id", required = true) String formatId, ModelMap modelMap) { + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setFormatId(formatId); + htmlPages.setPageType("form"); + htmlPages.setStatus(1); // 只查询启用状态的 + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + + if (list != null && !list.isEmpty()) { + HtmlPages page = list.get(0); + // 使用专门的方法更新浏览次数 + htmlPagesService.updateHtmlPagesViewCount(page.getId()); + // 重新查询最新数据 + page = htmlPagesService.selectHtmlPagesById(page.getId()); + + modelMap.put("page", page); + return "hasfj/form"; + } + return "error/404"; + } + + /** + * 获取页面列表(按类型) + */ + @GetMapping("/api/pages") + @Operation(summary = "获取页面列表(按类型)") + public AjaxResult getPagesByType(@RequestParam(value = "type", required = false) String pageType) { + HtmlPages htmlPages = new HtmlPages(); + if (pageType != null && !pageType.isEmpty()) { + htmlPages.setPageType(pageType); + } + htmlPages.setStatus(1); // 只查询启用状态的 + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + return AjaxResult.success(list); + } +} \ No newline at end of file diff --git a/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/controller/HtmlPagesController.java b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/controller/HtmlPagesController.java new file mode 100644 index 0000000..aceb049 --- /dev/null +++ b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/controller/HtmlPagesController.java @@ -0,0 +1,296 @@ +package com.boyue.hasfj.controller; + +import java.util.List; +import java.util.Map; +import java.nio.charset.StandardCharsets; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.enums.BusinessType; +import com.boyue.hasfj.domain.HtmlPages; +import com.boyue.hasfj.service.IHtmlPagesService; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.file.FileUtils; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.web.multipart.MultipartFile; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.pagehelper.PageHelper; +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * 司法局法律规定、典型案例、单下载Controller + * + * @author boyue + * @date 2025-05-28 + */ +@RestController +@RequestMapping("/hasfj/hasfjpages") +@Tag(name = "【司法局法律规定、典型案例、单下载】管理") +public class HtmlPagesController extends BaseController +{ + @Autowired + private IHtmlPagesService htmlPagesService; + + @Value("${boyue.profile}") + private String uploadPath; + + @Autowired + private HttpServletRequest request; + + /** + * 查询司法局法律规定、典型案例、单下载列表 + */ + @Operation(summary = "查询司法局法律规定、典型案例、单下载列表") +// @PreAuthorize("@ss.hasPermi('hasfj:hasfjpages:list')") + @GetMapping("/list") + public TableDataInfo list(HtmlPages htmlPages) + { + startPage(); + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + return getDataTable(list); + } + + /** + * 查询指定类型的页面列表 + */ + @Operation(summary = "查询指定类型的页面列表") + @GetMapping("/listByType/{pageType}") + public AjaxResult listByType(@PathVariable("pageType") String pageType) + { + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setPageType(pageType); + htmlPages.setStatus(1); // 只查询启用状态的 + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + return success(list); + } + + /** + * 导出司法局法律规定、典型案例、单下载列表 + */ + @Operation(summary = "导出司法局法律规定、典型案例、单下载列表") +// @PreAuthorize("@ss.hasPermi('hasfj:hasfjpages:export')") + @Log(title = "司法局法律规定、典型案例、单下载", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, HtmlPages htmlPages) + { + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + ExcelUtil util = new ExcelUtil(HtmlPages.class); + util.exportExcel(response, list, "司法局法律规定、典型案例、单下载数据"); + } + + /** + * 导入数据 + */ + @Operation(summary = "导入数据") + @PreAuthorize("@ss.hasPermi('hasfj:hasfjpages:import')") + @Log(title = "司法局法律规定、典型案例、单下载", businessType = BusinessType.IMPORT) + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file, boolean updateSupport, String importType) throws Exception + { + try { + // 根据importType决定导入方式 + if ("excel".equals(importType)) { + // Excel导入 + ExcelUtil util = new ExcelUtil(HtmlPages.class); + List htmlPagesList = util.importExcel(file.getInputStream()); + String operName = getUsername(); + String message = htmlPagesService.importHtmlPages(htmlPagesList, updateSupport, operName); + return success(message); + } else if ("batch".equals(importType)) { + // JSON批量导入 + String jsonContent = new String(file.getBytes(), StandardCharsets.UTF_8); + ObjectMapper objectMapper = new ObjectMapper(); + List htmlPagesList = objectMapper.readValue(jsonContent, + objectMapper.getTypeFactory().constructCollectionType(List.class, HtmlPages.class)); + + String operName = getUsername(); + String message = htmlPagesService.importHtmlPages(htmlPagesList, updateSupport, operName); + return success(message); + } else { + return error("不支持的导入类型"); + } + } catch (Exception e) { + logger.error("导入数据异常", e); + return error("导入数据失败: " + e.getMessage()); + } + } + + /** + * 下载导入模板 + */ + @Operation(summary = "下载导入模板") + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) + { + ExcelUtil util = new ExcelUtil(HtmlPages.class); + util.importTemplateExcel(response, "司法局法律规定、典型案例、单下载数据"); + } + + /** + * 删除附件 + */ + @Operation(summary = "删除附件") + @PreAuthorize("@ss.hasPermi('hasfj:hasfjpages:edit')") + @Log(title = "司法局法律规定、典型案例、单下载-删除附件", businessType = BusinessType.DELETE) + @PostMapping("/deleteAttachment") + public AjaxResult deleteAttachment(@RequestBody Map params) + { + try { + String attachmentUrl = params.get("attachmentUrl"); + if (StringUtils.isEmpty(attachmentUrl)) { + return error("附件URL不能为空"); + } + + logger.info("删除附件请求: {}", attachmentUrl); + + boolean result = htmlPagesService.deleteAttachment(attachmentUrl); + if (result) { + return success("附件删除成功"); + } else { + return error("附件删除失败,可能文件不存在或没有权限"); + } + } catch (Exception e) { + logger.error("删除附件异常", e); + return error("删除附件失败: " + e.getMessage()); + } + } + + /** + * 根据路径删除文件 + */ + @Operation(summary = "根据路径删除文件") + @PreAuthorize("@ss.hasPermi('common:profile:delete')") + @Log(title = "附件管理-删除文件", businessType = BusinessType.DELETE) + @PostMapping("/deleteFileByPath") + public AjaxResult deleteFile(@RequestBody Map requestBody) { + try { + String filePath = requestBody.get("path"); + if (StringUtils.isEmpty(filePath)) { + return error("文件路径不能为空"); + } + + logger.info("删除文件请求: {}", filePath); + + boolean result = htmlPagesService.deleteFileByPath(filePath); + if (result) { + return success("文件删除成功"); + } else { + return error("文件删除失败,可能文件不存在或没有权限"); + } + } catch (Exception e) { + logger.error("删除文件异常", e); + return error("删除文件失败: " + e.getMessage()); + } + } + + /** + * 获取司法局法律规定、典型案例、单下载详细信息 + */ + @Operation(summary = "获取司法局法律规定、典型案例、单下载详细信息") +// @PreAuthorize("@ss.hasPermi('hasfj:hasfjpages:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(htmlPagesService.selectHtmlPagesById(id)); + } + + /** + * 根据访问ID获取页面详情 + */ + @Operation(summary = "根据访问ID获取页面详情") + @GetMapping(value = "/format/{formatId}") + public AjaxResult getInfoByFormatId(@PathVariable("formatId") String formatId) + { + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setFormatId(formatId); + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + if (list != null && !list.isEmpty()) { + // 获取页面 + HtmlPages page = list.get(0); + // 使用专门的方法更新浏览次数,避免并发问题 + htmlPagesService.updateHtmlPagesViewCount(page.getId()); + // 重新查询最新数据 + page = htmlPagesService.selectHtmlPagesById(page.getId()); + return success(page); + } + return error("未找到对应页面"); + } + + /** + * 新增司法局法律规定、典型案例、单下载 + */ + @Operation(summary = "新增司法局法律规定、典型案例、单下载") +// @PreAuthorize("@ss.hasPermi('hasfj:hasfjpages:add')") + @Log(title = "司法局法律规定、典型案例、单下载", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody HtmlPages htmlPages) + { + return toAjax(htmlPagesService.insertHtmlPages(htmlPages)); + } + + /** + * 修改司法局法律规定、典型案例、单下载 + */ + @Operation(summary = "修改司法局法律规定、典型案例、单下载") +// @PreAuthorize("@ss.hasPermi('hasfj:hasfjpages:edit')") + @Log(title = "司法局法律规定、典型案例、单下载", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody HtmlPages htmlPages) + { + return toAjax(htmlPagesService.updateHtmlPages(htmlPages)); + } + + /** + * 删除司法局法律规定、典型案例、单下载 + */ + @Operation(summary = "删除司法局法律规定、典型案例、单下载") +// @PreAuthorize("@ss.hasPermi('hasfj:hasfjpages:remove')") + @Log(title = "司法局法律规定、典型案例、单下载", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable( name = "ids" ) Long[] ids) + { + return toAjax(htmlPagesService.deleteHtmlPagesByIds(ids)); + } + + /** + * 获取指定类型的页面列表用于二维码展示 + */ + @Operation(summary = "获取指定类型的页面列表用于二维码展示") + @GetMapping("/qrcodes") + public TableDataInfo getQRCodes( + @RequestParam(value = "type", required = false, defaultValue = "law") String type, + @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum, + @RequestParam(value = "pageSize", required = false, defaultValue = "6") Integer pageSize) { + PageHelper.startPage(pageNum, pageSize); + HtmlPages htmlPages = new HtmlPages(); + htmlPages.setPageType(type); + htmlPages.setStatus(1); // 只查询启用状态的 + List list = htmlPagesService.selectHtmlPagesList(htmlPages); + return getDataTable(list); + } +} \ No newline at end of file diff --git a/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/domain/HtmlPages.java b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/domain/HtmlPages.java new file mode 100644 index 0000000..3e3b0ec --- /dev/null +++ b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/domain/HtmlPages.java @@ -0,0 +1,250 @@ +package com.boyue.hasfj.domain; + +import com.boyue.common.core.domain.BaseEntity; +import io.swagger.v3.oas.annotations.media.Schema; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.boyue.common.annotation.Excel; + +/** + * 司法局法律规定、典型案例、单下载对象 html_pages + * + * @author boyue + * @date 2025-05-28 + */ +@Schema(description = "司法局法律规定、典型案例、单下载对象") +public class HtmlPages extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + + /** 序号 */ + @Schema(title = "序号") + @Excel(name = "序号") + private Long id; + + /** 访问id */ + @Schema(title = "访问id") + @Excel(name = "访问id") + private String formatId; + + /** 页面标题 */ + @Schema(title = "页面标题") + @Excel(name = "页面标题") + private String title; + + /** HTML内容 */ + @Schema(title = "HTML内容") + @Excel(name = "HTML内容") + private String content; + + /** 页面类型:法律规定 law、典型案例 case、表单下载from */ + @Schema(title = "页面类型:法律规定 law、典型案例 case、表单下载from") + @Excel(name = "页面类型:法律规定 law、典型案例 case、表单下载from") + private String pageType; + + /** 页面访问URL */ + @Schema(title = "页面访问URL") + @Excel(name = "页面访问URL") + private String pageUrl; + + /** 状态:1-启用,0-禁用 */ + @Schema(title = "状态:1-启用,0-禁用") + @Excel(name = "状态:1-启用,0-禁用") + private Integer status; + + /** 排序序号,数值越小排序越靠前,用于自定义显示顺序 */ + @Schema(title = "排序序号,数值越小排序越靠前,用于自定义显示顺序") + @Excel(name = "排序序号,数值越小排序越靠前,用于自定义显示顺序") + private Long sortOrder; + + /** 浏览次数,记录页面被访问的总次数 */ + @Schema(title = "浏览次数,记录页面被访问的总次数") + @Excel(name = "浏览次数,记录页面被访问的总次数") + private Long viewCount; + + /** 作者/负责人,记录页面的创建者或负责维护的人员 */ + @Schema(title = "作者/负责人,记录页面的创建者或负责维护的人员") + @Excel(name = "作者/负责人,记录页面的创建者或负责维护的人员") + private String author; + + /** SEO关键词,用于搜索引擎优化 */ + @Schema(title = "SEO关键词,用于搜索引擎优化") + @Excel(name = "SEO关键词,用于搜索引擎优化") + private String keywords; + + /** SEO描述,用于搜索引擎结果展示的页面摘要 */ + @Schema(title = "SEO描述,用于搜索引擎结果展示的页面摘要") + @Excel(name = "SEO描述,用于搜索引擎结果展示的页面摘要") + private String description; + + /** 多附件URLs,JSON格式存储多个附件信息 + * 格式: [{"name":"文件名","url":"文件路径","size":"文件大小"}] + */ + @Schema(title = "多附件URLs,JSON格式存储", description = "格式: [{'name':'文件名','url':'文件路径','size':'文件大小'}]") + @Excel(name = "多附件URLs", type = Excel.Type.EXPORT) + private String multiAttachments; + + public void setId(Long id) + { + this.id = id; + } + + public Long getId() + { + return id; + } + + + public void setFormatId(String formatId) + { + this.formatId = formatId; + } + + public String getFormatId() + { + return formatId; + } + + + public void setTitle(String title) + { + this.title = title; + } + + public String getTitle() + { + return title; + } + + + public void setContent(String content) + { + this.content = content; + } + + public String getContent() + { + return content; + } + + + public void setPageType(String pageType) + { + this.pageType = pageType; + } + + public String getPageType() + { + return pageType; + } + + + public void setPageUrl(String pageUrl) + { + this.pageUrl = pageUrl; + } + + public String getPageUrl() + { + return pageUrl; + } + + + public void setStatus(Integer status) + { + this.status = status; + } + + public Integer getStatus() + { + return status; + } + + + public void setSortOrder(Long sortOrder) + { + this.sortOrder = sortOrder; + } + + public Long getSortOrder() + { + return sortOrder; + } + + + public void setViewCount(Long viewCount) + { + this.viewCount = viewCount; + } + + public Long getViewCount() + { + return viewCount; + } + + + public void setAuthor(String author) + { + this.author = author; + } + + public String getAuthor() + { + return author; + } + + + public void setKeywords(String keywords) + { + this.keywords = keywords; + } + + public String getKeywords() + { + return keywords; + } + + + public void setDescription(String description) + { + this.description = description; + } + + public String getDescription() + { + return description; + } + + public void setMultiAttachments(String multiAttachments) + { + this.multiAttachments = multiAttachments; + } + + public String getMultiAttachments() + { + return multiAttachments; + } + + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("formatId", getFormatId()) + .append("title", getTitle()) + .append("content", getContent()) + .append("pageType", getPageType()) + .append("pageUrl", getPageUrl()) + .append("createTime", getCreateTime()) + .append("updateTime", getUpdateTime()) + .append("status", getStatus()) + .append("sortOrder", getSortOrder()) + .append("viewCount", getViewCount()) + .append("author", getAuthor()) + .append("keywords", getKeywords()) + .append("description", getDescription()) + .append("multiAttachments", getMultiAttachments()) + .toString(); + } +} diff --git a/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/mapper/HtmlPagesMapper.java b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/mapper/HtmlPagesMapper.java new file mode 100644 index 0000000..be01095 --- /dev/null +++ b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/mapper/HtmlPagesMapper.java @@ -0,0 +1,85 @@ +package com.boyue.hasfj.mapper; + +import java.util.List; +import com.boyue.hasfj.domain.HtmlPages; + +/** + * 司法局法律规定、典型案例、单下载Mapper接口 + * + * @author boyue + * @date 2025-05-28 + */ +public interface HtmlPagesMapper +{ + /** + * 查询司法局法律规定、典型案例、单下载 + * + * @param id 司法局法律规定、典型案例、单下载主键 + * @return 司法局法律规定、典型案例、单下载 + */ + public HtmlPages selectHtmlPagesById(Long id); + + /** + * 根据formatId查询司法局法律规定、典型案例、单下载 + * + * @param formatId 访问ID + * @return 司法局法律规定、典型案例、单下载 + */ + public HtmlPages selectHtmlPagesByFormatId(String formatId); + + /** + * 查询司法局法律规定、典型案例、单下载列表 + * + * @param htmlPages 司法局法律规定、典型案例、单下载 + * @return 司法局法律规定、典型案例、单下载集合 + */ + public List selectHtmlPagesList(HtmlPages htmlPages); + + /** + * 根据页面类型查询列表 + * + * @param pageType 页面类型 + * @return 司法局法律规定、典型案例、单下载集合 + */ + public List selectHtmlPagesListByType(String pageType); + + /** + * 新增司法局法律规定、典型案例、单下载 + * + * @param htmlPages 司法局法律规定、典型案例、单下载 + * @return 结果 + */ + public int insertHtmlPages(HtmlPages htmlPages); + + /** + * 修改司法局法律规定、典型案例、单下载 + * + * @param htmlPages 司法局法律规定、典型案例、单下载 + * @return 结果 + */ + public int updateHtmlPages(HtmlPages htmlPages); + + /** + * 删除司法局法律规定、典型案例、单下载 + * + * @param id 司法局法律规定、典型案例、单下载主键 + * @return 结果 + */ + public int deleteHtmlPagesById(Long id); + + /** + * 批量删除司法局法律规定、典型案例、单下载 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteHtmlPagesByIds(Long[] ids); + + /** + * 更新页面浏览次数(直接在数据库中累加) + * + * @param id 页面ID + * @return 结果 + */ + public int updateHtmlPagesViewCount(Long id); +} diff --git a/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/service/IHtmlPagesService.java b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/service/IHtmlPagesService.java new file mode 100644 index 0000000..6c68bcd --- /dev/null +++ b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/service/IHtmlPagesService.java @@ -0,0 +1,111 @@ +package com.boyue.hasfj.service; + +import java.util.List; +import com.boyue.hasfj.domain.HtmlPages; + +/** + * 司法局法律规定、典型案例、单下载Service接口 + * + * @author boyue + * @date 2025-05-28 + */ +public interface IHtmlPagesService +{ + /** + * 查询司法局法律规定、典型案例、单下载 + * + * @param id 司法局法律规定、典型案例、单下载主键 + * @return 司法局法律规定、典型案例、单下载 + */ + public HtmlPages selectHtmlPagesById(Long id); + + /** + * 根据formatId查询司法局法律规定、典型案例、单下载 + * + * @param formatId 访问ID + * @return 司法局法律规定、典型案例、单下载 + */ + public HtmlPages selectHtmlPagesByFormatId(String formatId); + + /** + * 查询司法局法律规定、典型案例、单下载列表 + * + * @param htmlPages 司法局法律规定、典型案例、单下载 + * @return 司法局法律规定、典型案例、单下载集合 + */ + public List selectHtmlPagesList(HtmlPages htmlPages); + + /** + * 根据页面类型查询列表 + * + * @param pageType 页面类型 + * @return 司法局法律规定、典型案例、单下载集合 + */ + public List selectHtmlPagesListByType(String pageType); + + /** + * 新增司法局法律规定、典型案例、单下载 + * + * @param htmlPages 司法局法律规定、典型案例、单下载 + * @return 结果 + */ + public int insertHtmlPages(HtmlPages htmlPages); + + /** + * 修改司法局法律规定、典型案例、单下载 + * + * @param htmlPages 司法局法律规定、典型案例、单下载 + * @return 结果 + */ + public int updateHtmlPages(HtmlPages htmlPages); + + /** + * 批量删除司法局法律规定、典型案例、单下载 + * + * @param ids 需要删除的司法局法律规定、典型案例、单下载主键集合 + * @return 结果 + */ + public int deleteHtmlPagesByIds(Long[] ids); + + /** + * 删除司法局法律规定、典型案例、单下载信息 + * + * @param id 司法局法律规定、典型案例、单下载主键 + * @return 结果 + */ + public int deleteHtmlPagesById(Long id); + + /** + * 导入数据 + * + * @param htmlPagesList 司法局法律规定、典型案例、单下载数据列表 + * @param updateSupport 是否更新已存在的数据 + * @param operName 操作人 + * @return 导入结果消息 + */ + public String importHtmlPages(List htmlPagesList, boolean updateSupport, String operName); + + /** + * 删除附件 + * + * @param attachmentUrl 附件URL + * @return 删除结果 + */ + public boolean deleteAttachment(String attachmentUrl); + + /** + * 根据路径删除文件 + * + * @param path 文件路径 + * @return 删除结果 + */ + public boolean deleteFileByPath(String path); + + /** + * 更新页面浏览次数 + * + * @param id 页面ID + * @return 结果 + */ + public int updateHtmlPagesViewCount(Long id); +} diff --git a/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/service/impl/HtmlPagesServiceImpl.java b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/service/impl/HtmlPagesServiceImpl.java new file mode 100644 index 0000000..2d0c674 --- /dev/null +++ b/boyue-models/boyue-hasfj/src/main/java/com/boyue/hasfj/service/impl/HtmlPagesServiceImpl.java @@ -0,0 +1,403 @@ +package com.boyue.hasfj.service.impl; + +import java.util.List; +import java.io.File; +import com.boyue.common.utils.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import com.boyue.hasfj.mapper.HtmlPagesMapper; +import com.boyue.hasfj.domain.HtmlPages; +import com.boyue.hasfj.service.IHtmlPagesService; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.file.FileUtils; +import com.boyue.common.exception.ServiceException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +/** + * 司法局法律规定、典型案例、单下载Service业务层处理 + * + * @author boyue + * @date 2025-05-28 + */ +@Service +public class HtmlPagesServiceImpl implements IHtmlPagesService +{ + private static final Logger log = LoggerFactory.getLogger(HtmlPagesServiceImpl.class); + + @Autowired + private HtmlPagesMapper htmlPagesMapper; + + @Value("${boyue.profile}") + private String uploadPath; + + /** + * 查询司法局法律规定、典型案例、单下载 + * + * @param id 司法局法律规定、典型案例、单下载主键 + * @return 司法局法律规定、典型案例、单下载 + */ + @Override + public HtmlPages selectHtmlPagesById(Long id) + { + return htmlPagesMapper.selectHtmlPagesById(id); + } + + /** + * 根据formatId查询司法局法律规定、典型案例、单下载 + * + * @param formatId 访问ID + * @return 司法局法律规定、典型案例、单下载 + */ + @Override + public HtmlPages selectHtmlPagesByFormatId(String formatId) + { + if (StringUtils.isEmpty(formatId)) + { + return null; + } + return htmlPagesMapper.selectHtmlPagesByFormatId(formatId); + } + + /** + * 查询司法局法律规定、典型案例、单下载列表 + * + * @param htmlPages 司法局法律规定、典型案例、单下载 + * @return 司法局法律规定、典型案例、单下载 + */ + @Override + public List selectHtmlPagesList(HtmlPages htmlPages) + { + return htmlPagesMapper.selectHtmlPagesList(htmlPages); + } + + /** + * 根据页面类型查询列表 + * + * @param pageType 页面类型 + * @return 司法局法律规定、典型案例、单下载集合 + */ + @Override + public List selectHtmlPagesListByType(String pageType) + { + return htmlPagesMapper.selectHtmlPagesListByType(pageType); + } + + /** + * 新增司法局法律规定、典型案例、单下载 + * + * @param htmlPages 司法局法律规定、典型案例、单下载 + * @return 结果 + */ + @Override + public int insertHtmlPages(HtmlPages htmlPages) + { + // 验证多附件格式 + validateMultiAttachments(htmlPages); + + htmlPages.setCreateTime(DateUtils.getNowDate()); + return htmlPagesMapper.insertHtmlPages(htmlPages); + } + + /** + * 修改司法局法律规定、典型案例、单下载 + * + * @param htmlPages 司法局法律规定、典型案例、单下载 + * @return 结果 + */ + @Override + public int updateHtmlPages(HtmlPages htmlPages) + { + // 验证多附件格式 + validateMultiAttachments(htmlPages); + + htmlPages.setUpdateTime(DateUtils.getNowDate()); + return htmlPagesMapper.updateHtmlPages(htmlPages); + } + + /** + * 更新页面浏览次数(增加专门的方法处理浏览次数更新) + * + * @param id 页面ID + * @return 结果 + */ + @Override + public int updateHtmlPagesViewCount(Long id) + { + if (id == null || id <= 0) { + return 0; + } + return htmlPagesMapper.updateHtmlPagesViewCount(id); + } + + /** + * 批量删除司法局法律规定、典型案例、单下载 + * + * @param ids 需要删除的司法局法律规定、典型案例、单下载主键 + * @return 结果 + */ + @Override + public int deleteHtmlPagesByIds(Long[] ids) + { + return htmlPagesMapper.deleteHtmlPagesByIds(ids); + } + + /** + * 删除司法局法律规定、典型案例、单下载信息 + * + * @param id 司法局法律规定、典型案例、单下载主键 + * @return 结果 + */ + @Override + public int deleteHtmlPagesById(Long id) + { + return htmlPagesMapper.deleteHtmlPagesById(id); + } + + /** + * 验证附件格式 + * + * @param htmlPages 页面对象 + */ + private void validateMultiAttachments(HtmlPages htmlPages) + { + if (htmlPages.getMultiAttachments() != null && !htmlPages.getMultiAttachments().trim().startsWith("[")) + { + log.warn("附件格式不正确,将重置为空数组: {}", htmlPages.getMultiAttachments()); + htmlPages.setMultiAttachments("[]"); + } + } + + /** + * 导入数据 + * + * @param htmlPagesList 司法局法律规定、典型案例、单下载数据列表 + * @param updateSupport 是否更新已存在的数据 + * @param operName 操作人 + * @return 导入结果消息 + */ + @Override + public String importHtmlPages(List htmlPagesList, boolean updateSupport, String operName) + { + if (StringUtils.isNull(htmlPagesList) || htmlPagesList.size() == 0) + { + throw new ServiceException("导入数据不能为空!"); + } + int successNum = 0; + int failureNum = 0; + StringBuilder successMsg = new StringBuilder(); + StringBuilder failureMsg = new StringBuilder(); + for (HtmlPages htmlPages : htmlPagesList) + { + try + { + // 验证是否存在这个用户 + HtmlPages existHtmlPages = selectHtmlPagesByFormatId(htmlPages.getFormatId()); + if (StringUtils.isNull(existHtmlPages)) + { + htmlPages.setCreateBy(operName); + htmlPages.setCreateTime(DateUtils.getNowDate()); + htmlPages.setUpdateBy(operName); + htmlPages.setUpdateTime(DateUtils.getNowDate()); + // 设置默认值 + if (htmlPages.getStatus() == null) + { + htmlPages.setStatus(1); // 默认启用 + } + if (htmlPages.getSortOrder() == null) + { + htmlPages.setSortOrder(0L); // 默认排序值 + } + if (htmlPages.getViewCount() == null) + { + htmlPages.setViewCount(0L); // 默认浏览量为0 + } + if (StringUtils.isEmpty(htmlPages.getMultiAttachments())) + { + htmlPages.setMultiAttachments("[]"); // 默认附件为空数组 + } + this.insertHtmlPages(htmlPages); + successNum++; + successMsg.append("
" + successNum + "、页面标题 " + htmlPages.getTitle() + " 导入成功"); + } + else if (updateSupport) + { + htmlPages.setId(existHtmlPages.getId()); + htmlPages.setUpdateBy(operName); + htmlPages.setUpdateTime(DateUtils.getNowDate()); + this.updateHtmlPages(htmlPages); + successNum++; + successMsg.append("
" + successNum + "、页面标题 " + htmlPages.getTitle() + " 更新成功"); + } + else + { + failureNum++; + failureMsg.append("
" + failureNum + "、页面标题 " + htmlPages.getTitle() + " 已存在"); + } + } + catch (Exception e) + { + failureNum++; + String msg = "
" + failureNum + "、页面标题 " + htmlPages.getTitle() + " 导入失败:"; + failureMsg.append(msg + e.getMessage()); + log.error(msg, e); + } + } + if (failureNum > 0) + { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new ServiceException(failureMsg.toString()); + } + else + { + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } + + /** + * 删除附件 + * + * @param attachmentUrl 附件URL + * @return 删除结果 + */ + @Override + public boolean deleteAttachment(String attachmentUrl) { + if (StringUtils.isEmpty(attachmentUrl)) { + return false; + } + + log.info("删除附件: {}", attachmentUrl); + + // 处理URL格式问题 + String processedUrl = attachmentUrl; + + // 处理URL中可能存在的双斜杠问题 + if (processedUrl.contains("://")) { + final int baseUrlPart = processedUrl.indexOf("://") + 3; + processedUrl = processedUrl.substring(0, baseUrlPart) + + processedUrl.substring(baseUrlPart).replace("//", "/"); + } + + // 提取相对路径 + String relativePath = null; + + // 格式1: 包含/profile/的完整URL + if (processedUrl.contains("/profile/")) { + final int pathIndex = processedUrl.indexOf("/profile/"); + if (pathIndex >= 0) { + relativePath = processedUrl.substring(pathIndex + 9); // 9是'/profile/'的长度 + } + } + + // 格式2: 包含年月日格式的路径 + if (relativePath == null) { + java.util.regex.Matcher yearMatch = java.util.regex.Pattern.compile("/(\\d{4}/\\d{2}/\\d{2}/[^/]+)$").matcher(processedUrl); + if (yearMatch.find()) { + relativePath = yearMatch.group(1); + } + } + + // 格式3: files/master/路径格式 + if (relativePath == null && processedUrl.contains("/files/master/")) { + final int pathIndex = processedUrl.indexOf("/files/master/"); + if (pathIndex >= 0) { + relativePath = processedUrl.substring(pathIndex + 1); // 保留files/master/前缀 + } + } + + // 如果提取到了相对路径,进行进一步处理 + if (relativePath != null) { + // 检查是否为年份格式的路径,如果是且不包含files/master前缀,则添加 + if (relativePath.matches("^\\d{4}/\\d{2}/\\d{2}/.*") && !relativePath.contains("files/master")) { + relativePath = "files/master/" + relativePath; + } + + log.info("提取的相对路径: {}", relativePath); + return deleteFileByPath(relativePath); + } + + // 如果以上方法都无法提取路径,则直接尝试删除 + log.info("无法提取相对路径,尝试直接删除: {}", processedUrl); + File file = new File(uploadPath + File.separator + processedUrl); + if (file.exists() && file.isFile()) { + boolean result = file.delete(); + log.info("直接删除文件结果: {}", result ? "成功" : "失败"); + return result; + } + + log.warn("找不到文件: {}", processedUrl); + return false; + } + + /** + * 根据路径删除文件 + * + * @param path 文件路径 + * @return 删除结果 + */ + @Override + public boolean deleteFileByPath(String path) { + if (StringUtils.isEmpty(path)) { + return false; + } + + log.info("根据路径删除文件: {}", path); + + // 处理路径格式,确保正斜杠格式 + String processedPath = path; + if (path.contains("\\")) { + processedPath = path.replace("\\", "/"); + } + + // 确保没有连续的双斜杠(除了http://这种协议部分) + if (processedPath.contains("://")) { + String[] parts = processedPath.split("://", 2); + String protocolPart = parts[0] + "://"; + String pathPart = parts[1].replace("//", "/"); + processedPath = protocolPart + pathPart; + } else { + processedPath = processedPath.replace("//", "/"); + } + + // 构建完整文件路径 + String fullPath = uploadPath + File.separator + processedPath; + log.info("完整文件路径: {}", fullPath); + + // 规范化路径 + fullPath = fullPath.replace("/", File.separator); + + File file = new File(fullPath); + if (file.exists() && file.isFile()) { + boolean result = file.delete(); + log.info("删除文件结果: {}", result ? "成功" : "失败"); + return result; + } + + // 如果找不到文件,可能是因为路径问题,尝试直接在upload目录下查找 + String fileName = new File(processedPath).getName(); + try { + Files.walk(Paths.get(uploadPath)) + .filter(Files::isRegularFile) + .filter(p -> p.getFileName().toString().equals(fileName)) + .forEach(p -> { + try { + Files.deleteIfExists(p); + log.info("通过文件名查找并删除: {}", p); + } catch (IOException e) { + log.error("删除文件失败: {}", p, e); + } + }); + return true; + } catch (IOException e) { + log.error("搜索文件失败", e); + } + + log.warn("找不到文件: {}", fullPath); + return false; + } +} diff --git a/boyue-models/boyue-hasfj/src/main/resources/mapper/hasfj/HtmlPagesMapper.xml b/boyue-models/boyue-hasfj/src/main/resources/mapper/hasfj/HtmlPagesMapper.xml new file mode 100644 index 0000000..556290e --- /dev/null +++ b/boyue-models/boyue-hasfj/src/main/resources/mapper/hasfj/HtmlPagesMapper.xml @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + select + hp.id, + hp.format_id, + hp.title, + hp.content, + hp.page_type, + hp.page_url, + hp.create_time, + hp.update_time, + hp.status, + hp.sort_order, + hp.view_count, + hp.author, + hp.keywords, + hp.description, + hp.multi_attachments + from html_pages hp + + + + + + + + + + + + insert into html_pages + + format_id, + title, + content, + page_type, + page_url, + create_time, + update_time, + status, + sort_order, + view_count, + author, + keywords, + description, + multi_attachments, + + + #{formatId}, + #{title}, + #{content}, + #{pageType}, + #{pageUrl}, + #{createTime}, + #{updateTime}, + #{status}, + #{sortOrder}, + #{viewCount}, + #{author}, + #{keywords}, + #{description}, + #{multiAttachments}, + + + + + update html_pages + + format_id = #{formatId}, + title = #{title}, + content = #{content}, + page_type = #{pageType}, + page_url = #{pageUrl}, + create_time = #{createTime}, + update_time = #{updateTime}, + status = #{status}, + sort_order = #{sortOrder}, + view_count = #{viewCount}, + author = #{author}, + keywords = #{keywords}, + description = #{description}, + multi_attachments = #{multiAttachments}, + + where id = #{id} + + + + delete from html_pages where id = #{id} + + + + delete from html_pages where id in + + #{id} + + + + + + update html_pages + set view_count = IFNULL(view_count, 0) + 1, + update_time = sysdate() + where id = #{id} + + \ No newline at end of file diff --git a/boyue-models/boyue-message/pom.xml b/boyue-models/boyue-message/pom.xml new file mode 100644 index 0000000..92163f8 --- /dev/null +++ b/boyue-models/boyue-message/pom.xml @@ -0,0 +1,45 @@ + + + + boyue-models + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-message + + + message消息模块 + + + + + + + com.boyue + boyue-framework + + + + + com.boyue + boyue-common + + + + + com.boyue + boyue-tfa-phone + + + + + com.boyue + boyue-tfa-email + + + + \ No newline at end of file diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/annotation/MessageLog.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/annotation/MessageLog.java new file mode 100644 index 0000000..2de35b9 --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/annotation/MessageLog.java @@ -0,0 +1,36 @@ +package com.boyue.modelMessage.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.boyue.modelMessage.enums.MessageType; + + +//自定义消息系统注解 +@Target({ ElementType.PARAMETER, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface MessageLog { + /** + * 消息操作的描述 + */ + String description() default ""; + + /** + * 消息标题 + */ + String title() default ""; + + /** + * 是否立即记录消息,默认为 true + */ + boolean immediateLog() default true; + + /** + * 操作类型 + */ + MessageType messageType() default MessageType.INFO; +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/controller/MessageSystemController.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/controller/MessageSystemController.java new file mode 100644 index 0000000..2d56e06 --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/controller/MessageSystemController.java @@ -0,0 +1,214 @@ +package com.boyue.modelMessage.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.DateUtils; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.modelMessage.domain.MessageSystem; +import com.boyue.modelMessage.service.IMessageSystemService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 消息管理Controller + * + * @author boyue + * @date 2024-12-21 + */ +@RestController +@RequestMapping("/modelMessage/messageSystem") +@Tag(name = "【消息管理】管理") +public class MessageSystemController extends BaseController +{ + @Autowired + private IMessageSystemService messageSystemService; + + /** + * 查询消息管理列表 + */ + @Operation(summary = "查询消息管理列表") + //@PreAuthorize("@ss.hasPermi('modelMessage:messageSystem:list')") + @GetMapping("/list") + public TableDataInfo list(MessageSystem messageSystem) + { + startPage(); + messageSystem.setCreateBy(getUsername()); + messageSystem.setMessageRecipient(getUsername()); + List list = messageSystemService.selectMessageSystemList(messageSystem); + return getDataTable(list); + } + + /** + * 导出消息管理列表 + */ + @Operation(summary = "导出消息管理列表") + @PreAuthorize("@ss.hasPermi('modelMessage:messageSystem:export')") + @Log(title = "消息管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, MessageSystem messageSystem) + { + List list = messageSystemService.selectMessageSystemList(messageSystem); + ExcelUtil util = new ExcelUtil(MessageSystem.class); + util.exportExcel(response, list, "消息管理数据"); + } + + /** + * 获取消息管理详细信息 + */ + @Operation(summary = "获取消息管理详细信息") + //@PreAuthorize("@ss.hasPermi('modelMessage:messageSystem:query')") + @GetMapping(value = "/{messageId}") + public AjaxResult getInfo(@PathVariable("messageId") Long messageId) + { + return success(messageSystemService.selectMessageSystemByMessageId(messageId)); + } + + /** + * 修改消息管理 + */ + @Operation(summary = "修改消息管理") + //@PreAuthorize("@ss.hasPermi('modelMessage:messageSystem:edit')") + @Log(title = "消息管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody MessageSystem messageSystem) + { + messageSystem.setUpdateBy(getUsername()); + messageSystem.setUpdateTime(DateUtils.getNowDate()); + return toAjax(messageSystemService.updateMessageSystem(messageSystem)); + } + + /** + * 删除消息管理 + */ + @Operation(summary = "删除消息管理") + //@PreAuthorize("@ss.hasPermi('modelMessage:messageSystem:remove')") + @Log(title = "消息管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{messageIds}") + public AjaxResult remove(@PathVariable( name = "messageIds" ) Long[] messageIds) + { + return toAjax(messageSystemService.deleteMessageSystemByMessageIds(messageIds)); + } + + /** + * 批量发送消息 + */ + @Operation(summary = "发送消息") + @Log(title = "发送消息", businessType = BusinessType.INSERT) + @PostMapping + @Transactional + public AjaxResult batchAdd(@RequestBody List messageSystemList) { + try { + messageSystemList.forEach(messageSystemService::processMessageSystem); + messageSystemService.batchInsertMessageSystem(messageSystemList); + return AjaxResult.success("消息发送成功!"); + } catch (Exception e) { + return AjaxResult.error("消息发送失败", e); + } + } + + /** + * 用户点击标题调整信息状态 + */ + @Operation(summary = "用户点击标题调整信息状态") + @PostMapping("/{messageId}") + public AjaxResult update(@PathVariable Long messageId){ + return success(messageSystemService.updateState(messageId)); + } + + /** + * 查询平台用户 sendMode 进行过滤。 + */ + @Operation(summary = "查询平台用户") + @GetMapping("/selectUser") + public AjaxResult selectUser(@RequestParam(required = false) String sendMode) { + try { + // 非空检查并提供默认值 + if (sendMode == null || sendMode.trim().isEmpty()) { + sendMode = "default"; + } + List list; + switch (sendMode) { + case "1": list = messageSystemService.getUsersFilteredBySendMode("phone"); break; // 短信 + case "2": list = messageSystemService.getUsersFilteredBySendMode("email"); break;// 邮件 + default: list = messageSystemService.selectUser(); break; //默认查询全部的用户 + } + return success(list); + } catch (ServiceException e) { + return AjaxResult.error(e.getMessage()); + } + } + + /** + * 查询角色信息 + */ + @Operation(summary = "查询角色") + @GetMapping("/selectRole") + public AjaxResult selectRole() { + return success(messageSystemService.selectRole()); + } + + /** + * 查询所有部门信息 + */ + @Operation(summary = "查询部门") + @GetMapping("/selectDept") + public AjaxResult selectDept() { + return success(messageSystemService.selectDept()); + } + + /** + * 根据角色ID获取所有符合条件的用户信息。 + * + * @param roleId 角色ID + * @return 用户信息列表 + */ + @Operation(summary = "根据角色Id查询所有符合条件的用户信息") + @GetMapping("/getUsersByRole/{roleId}") + public AjaxResult selectUsersByRoleId(@PathVariable Long roleId) { + return success(messageSystemService.selectUsersByRoleId(roleId)); + } + + /** + * 根据部门ID获取所有符合条件的用户信息。 + * + * @param deptId 部门ID + * @return 用户信息列表 + */ + @Operation(summary = "根据部门Id查询所有符合条件的用户信息") + @GetMapping("/getUserNameByDeptId/{deptId}") + public AjaxResult getUserNameByDeptId(@PathVariable Long deptId) { + return success(messageSystemService.getUserNameByDeptId(deptId)); + } + + /** + * 查询模版签名 + * @return 模版信息列表 + */ + @Operation(summary = "查询模版签名") + @GetMapping("/selecTemplates") + public AjaxResult selecTemplates() { + return success(messageSystemService.selecTemplates()); + } +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/controller/MessageTemplateController.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/controller/MessageTemplateController.java new file mode 100644 index 0000000..991a483 --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/controller/MessageTemplateController.java @@ -0,0 +1,116 @@ +package com.boyue.modelMessage.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.modelMessage.domain.MessageTemplate; +import com.boyue.modelMessage.service.IMessageTemplateService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 模版管理Controller + * + * @author boyue + * @date 2024-12-31 + */ +@RestController +@RequestMapping("/modelMessage/template") +@Tag(name = "【模版管理】管理") +public class MessageTemplateController extends BaseController +{ + @Autowired + private IMessageTemplateService messageTemplateService; + + /** + * 查询模版管理列表 + */ + @Operation(summary = "查询模版管理列表") + //@PreAuthorize("@ss.hasPermi('modelMessage:template:list')") + @GetMapping("/list") + public TableDataInfo list(MessageTemplate messageTemplate) + { + startPage(); + List list = messageTemplateService.selectMessageTemplateList(messageTemplate); + return getDataTable(list); + } + + /** + * 导出模版管理列表 + */ + @Operation(summary = "导出模版管理列表") + @PreAuthorize("@ss.hasPermi('modelMessage:template:export')") + @Log(title = "模版管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, MessageTemplate messageTemplate) + { + List list = messageTemplateService.selectMessageTemplateList(messageTemplate); + ExcelUtil util = new ExcelUtil(MessageTemplate.class); + util.exportExcel(response, list, "模版管理数据"); + } + + /** + * 获取模版管理详细信息 + */ + @Operation(summary = "获取模版管理详细信息") + //@PreAuthorize("@ss.hasPermi('modelMessage:template:query')") + @GetMapping(value = "/{templateId}") + public AjaxResult getInfo(@PathVariable("templateId") Long templateId) + { + return success(messageTemplateService.selectMessageTemplateByTemplateId(templateId)); + } + + /** + * 新增模版管理 + */ + @Operation(summary = "新增模版管理") + //@PreAuthorize("@ss.hasPermi('modelMessage:template:add')") + @Log(title = "模版管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody MessageTemplate messageTemplate) + { + return toAjax(messageTemplateService.insertMessageTemplate(messageTemplate)); + } + + /** + * 修改模版管理 + */ + @Operation(summary = "修改模版管理") + //@PreAuthorize("@ss.hasPermi('modelMessage:template:edit')") + @Log(title = "模版管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody MessageTemplate messageTemplate) + { + return toAjax(messageTemplateService.updateMessageTemplate(messageTemplate)); + } + + /** + * 删除模版管理 + */ + @Operation(summary = "删除模版管理") + //@PreAuthorize("@ss.hasPermi('modelMessage:template:remove')") + @Log(title = "模版管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{templateIds}") + public AjaxResult remove(@PathVariable( name = "templateIds" ) Long[] templateIds) + { + return toAjax(messageTemplateService.deleteMessageTemplateByTemplateIds(templateIds)); + } +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/controller/MessageVariableController.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/controller/MessageVariableController.java new file mode 100644 index 0000000..40f7c75 --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/controller/MessageVariableController.java @@ -0,0 +1,139 @@ +package com.boyue.modelMessage.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.modelMessage.domain.MessageVariable; +import com.boyue.modelMessage.service.IMessageVariableService; +import com.boyue.modelMessage.utils.MessageSystemUtils; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 变量管理Controller + * + * @author boyue + * @date 2024-12-31 + */ +@RestController +@RequestMapping("/modelMessage/variable") +@Tag(name = "【变量管理】管理") +public class MessageVariableController extends BaseController +{ + @Autowired + private IMessageVariableService messageVariableService; + + @Autowired + private MessageSystemUtils messageVariableUtils; + + /** + * 查询变量管理列表 + */ + @Operation(summary = "查询变量管理列表") + //@PreAuthorize("@ss.hasPermi('modelMessage:variable:list')") + @GetMapping("/list") + public TableDataInfo list(MessageVariable messageVariable) + { + startPage(); + List list = messageVariableService.selectMessageVariableList(messageVariable); + return getDataTable(list); + } + + /** + * 导出变量管理列表 + */ + @Operation(summary = "导出变量管理列表") + @PreAuthorize("@ss.hasPermi('modelMessage:variable:export')") + @Log(title = "变量管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, MessageVariable messageVariable) + { + List list = messageVariableService.selectMessageVariableList(messageVariable); + ExcelUtil util = new ExcelUtil(MessageVariable.class); + util.exportExcel(response, list, "变量管理数据"); + } + + /** + * 获取变量管理详细信息 + */ + @Operation(summary = "获取变量管理详细信息") + //@PreAuthorize("@ss.hasPermi('modelMessage:variable:query')") + @GetMapping(value = "/{variableId}") + public AjaxResult getInfo(@PathVariable("variableId") Long variableId) + { + return success(messageVariableService.selectMessageVariableByVariableId(variableId)); + } + + /** + * 新增变量管理 + */ + @Operation(summary = "新增变量管理") + //@PreAuthorize("@ss.hasPermi('modelMessage:variable:add')") + @Log(title = "变量管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody MessageVariable messageVariable) + { + return toAjax(messageVariableService.insertMessageVariable(messageVariable)); + } + + /** + * 修改变量管理 + */ + @Operation(summary = "修改变量管理") + //@PreAuthorize("@ss.hasPermi('modelMessage:variable:edit')") + @Log(title = "变量管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody MessageVariable messageVariable) + { + return toAjax(messageVariableService.updateMessageVariable(messageVariable)); + } + + /** + * 删除变量管理 + */ + @Operation(summary = "删除变量管理") + //@PreAuthorize("@ss.hasPermi('modelMessage:variable:remove')") + @Log(title = "变量管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{variableIds}") + public AjaxResult remove(@PathVariable( name = "variableIds" ) Long[] variableIds) + { + return toAjax(messageVariableService.deleteMessageVariableByVariableIds(variableIds)); + } + + /** + * 查询变量 + */ + @Operation(summary = "查询变量") + @GetMapping("/selectMessageVariable") + public AjaxResult selectMessageVariable() { + return success(messageVariableService.selectMessageVariable()); + } + + /** + * 根据变量类型生成不同的变量内容 + */ + @Operation(summary = "根据内置变量生成不同内容") + @GetMapping("/generate") + public AjaxResult generateVariableContent(@RequestParam String variableContent) { + return success(messageVariableUtils.generateVariableContent(variableContent)); + } +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/domain/MessageSystem.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/domain/MessageSystem.java new file mode 100644 index 0000000..904cbf6 --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/domain/MessageSystem.java @@ -0,0 +1,159 @@ +package com.boyue.modelMessage.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 消息管理对象 message_system + * + * @author boyue + * @date 2024-12-21 + */ +@Schema(description = "消息管理对象") +public class MessageSystem extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 主键 */ + @Schema(title = "主键") + private Long messageId; + + /** 标题 */ + @Schema(title = "标题") + @Excel(name = "标题") + private String messageTitle; + + /** 消息内容 */ + @Schema(title = "消息内容") + @Excel(name = "消息内容") + private String messageContent; + + /** 消息状态(0未读 1已读) */ + @Schema(title = "消息状态(0未读 1已读)") + @Excel(name = "消息状态(0未读 1已读)") + private String messageStatus; + + /** 消息类型 */ + @Schema(title = "消息类型") + @Excel(name = "消息类型") + private String messageType; + + /** 消息类型 */ + @Schema(title = "接收人") + @Excel(name = "接收人") + private String messageRecipient; + + /** 发送方式(0平台 1手机号 2 邮箱) */ + @Schema(title = "发送方式(0平台 1手机号 2 邮箱)") + @Excel(name = "发送方式(0平台 1手机号 2 邮箱)") + private String sendMode; + + /** 号码 */ + @Schema(title = "号码") + @Excel(name = "号码") + private String code; + + public String getSendMode() { + return sendMode; + } + + public void setSendMode(String sendMode) { + this.sendMode = sendMode; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public void setMessageId(Long messageId) + { + this.messageId = messageId; + } + + public Long getMessageId() + { + return messageId; + } + + + public void setMessageTitle(String messageTitle) + { + this.messageTitle = messageTitle; + } + + public String getMessageTitle() + { + return messageTitle; + } + + + public void setMessageContent(String messageContent) + { + this.messageContent = messageContent; + } + + public String getMessageContent() + { + return messageContent; + } + + + public void setMessageStatus(String messageStatus) + { + this.messageStatus = messageStatus; + } + + public String getMessageStatus() + { + return messageStatus; + } + + + public void setMessageType(String messageType) + { + this.messageType = messageType; + } + + public String getMessageType() + { + return messageType; + } + + public String getMessageRecipient() { + return messageRecipient; + } + + public void setMessageRecipient(String messageRecipient) { + this.messageRecipient = messageRecipient; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("messageId", getMessageId()) + .append("messageTitle", getMessageTitle()) + .append("messageContent", getMessageContent()) + .append("messageStatus", getMessageStatus()) + .append("messageType", getMessageType()) + .append("messageRecipient", getMessageRecipient()) + .append("sendMode", getSendMode()) + .append("code", getCode()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } + + +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/domain/MessageTemplate.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/domain/MessageTemplate.java new file mode 100644 index 0000000..720a9e9 --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/domain/MessageTemplate.java @@ -0,0 +1,134 @@ +package com.boyue.modelMessage.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 模版管理对象 message_template + * + * @author boyue + * @date 2024-12-31 + */ +@Schema(description = "模版管理对象") +public class MessageTemplate extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + + /** 主键 */ + @Schema(title = "主键") + private Long templateId; + + /** 模版名称 */ + @Schema(title = "模版名称") + @Excel(name = "模版名称") + private String templateName; + + /** 模版CODE */ + @Schema(title = "模版CODE") + @Excel(name = "模版CODE") + private String templateCode; + + /** 模版类型 */ + @Schema(title = "模版类型") + @Excel(name = "模版类型") + private String templateType; + + /** 模版内容 */ + @Schema(title = "模版内容") + @Excel(name = "模版内容") + private String templateContent; + + /** 变量属性 */ + @Schema(title = "变量属性") + @Excel(name = "变量属性") + private String templateVariable; + public void setTemplateId(Long templateId) + { + this.templateId = templateId; + } + + public Long getTemplateId() + { + return templateId; + } + + + public void setTemplateName(String templateName) + { + this.templateName = templateName; + } + + public String getTemplateName() + { + return templateName; + } + + + public void setTemplateCode(String templateCode) + { + this.templateCode = templateCode; + } + + public String getTemplateCode() + { + return templateCode; + } + + + public void setTemplateType(String templateType) + { + this.templateType = templateType; + } + + public String getTemplateType() + { + return templateType; + } + + + public void setTemplateContent(String templateContent) + { + this.templateContent = templateContent; + } + + public String getTemplateContent() + { + return templateContent; + } + + + public void setTemplateVariable(String templateVariable) + { + this.templateVariable = templateVariable; + } + + public String getTemplateVariable() + { + return templateVariable; + } + + + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("templateId", getTemplateId()) + .append("templateName", getTemplateName()) + .append("templateCode", getTemplateCode()) + .append("templateType", getTemplateType()) + .append("templateContent", getTemplateContent()) + .append("templateVariable", getTemplateVariable()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/domain/MessageVariable.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/domain/MessageVariable.java new file mode 100644 index 0000000..9543ab2 --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/domain/MessageVariable.java @@ -0,0 +1,107 @@ +package com.boyue.modelMessage.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 变量管理对象 message_variable + * + * @author boyue + * @date 2024-12-31 + */ +@Schema(description = "变量管理对象") +public class MessageVariable extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + + /** 主键 */ + @Schema(title = "主键") + private Long variableId; + + /** 变量名称 */ + @Schema(title = "变量名称") + @Excel(name = "变量名称") + private String variableName; + + /** 变量类型 */ + @Schema(title = "变量类型") + @Excel(name = "变量类型") + private String variableType; + + /** 变量内容 */ + @Schema(title = "变量内容") + @Excel(name = "变量内容") + private String variableContent; + public void setVariableId(Long variableId) + { + this.variableId = variableId; + } + + public MessageVariable(Long variableId, String variableName, String variableType, String variableContent) { + this.variableId = variableId; + this.variableName = variableName; + this.variableType = variableType; + this.variableContent = variableContent; + } + + public Long getVariableId() + { + return variableId; + } + + + public void setVariableName(String variableName) + { + this.variableName = variableName; + } + + public String getVariableName() + { + return variableName; + } + + + public void setVariableType(String variableLength) + { + this.variableType = variableLength; + } + + public String getVariableType() + { + return variableType; + } + + + public void setVariableContent(String variableContent) + { + this.variableContent = variableContent; + } + + public String getVariableContent() + { + return variableContent; + } + + + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("variableId", getVariableId()) + .append("variableName", getVariableName()) + .append("variableType", getVariableType()) + .append("variableContent", getVariableContent()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/enums/MessageType.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/enums/MessageType.java new file mode 100644 index 0000000..3d40f49 --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/enums/MessageType.java @@ -0,0 +1,25 @@ +package com.boyue.modelMessage.enums; + +public enum MessageType { + INFO("信息", "普通信息记录"), + WARN("警告", "非致命问题警告"), + ERROR("错误", "严重错误信息"), + DEBUG("调试", "调试信息,仅用于开发环境"), + SUCCESS("成功", "操作成功的提示信息"); + + private final String code; + private final String description; + + MessageType(String code, String description) { + this.code = code; + this.description = description; + } + + public String getCode() { + return code; + } + + public String getDescription() { + return description; + } +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/enums/SendMode.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/enums/SendMode.java new file mode 100644 index 0000000..43fe225 --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/enums/SendMode.java @@ -0,0 +1,32 @@ +package com.boyue.modelMessage.enums; + +public enum SendMode { + PLATFORM("0", "平台"), + PHONE("1", "手机号"), + EMAIL("2", "邮箱"); + + private final String code; + private final String description; + + SendMode(String code, String description) { + this.code = code; + this.description = description; + } + + public String getCode() { + return code; + } + + public String getDescription() { + return description; + } + + public static SendMode fromCode(String code) { + for (SendMode mode : SendMode.values()) { + if (mode.getCode().equals(code)) { + return mode; + } + } + throw new IllegalArgumentException("未知的发送方式: " + code); + } +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/mapper/MessageSystemMapper.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/mapper/MessageSystemMapper.java new file mode 100644 index 0000000..71158e5 --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/mapper/MessageSystemMapper.java @@ -0,0 +1,121 @@ +package com.boyue.modelMessage.mapper; + +import java.util.List; + +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; + +import com.boyue.common.core.domain.entity.SysDept; +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.modelMessage.domain.MessageSystem; +import com.boyue.modelMessage.domain.MessageTemplate; + +/** + * 消息管理Mapper接口 + * + * @author boyue + * @date 2024-12-21 + */ +public interface MessageSystemMapper +{ + /** + * 查询消息管理 + * + * @param messageId 消息管理主键 + * @return 消息管理 + */ + public MessageSystem selectMessageSystemByMessageId(Long messageId); + + /** + * 查询消息管理列表 + * + * @param messageSystem 消息管理 + * @return 消息管理集合 + */ + public List selectMessageSystemList(MessageSystem messageSystem); + + /** + * 新增消息管理 + * + * @param messageSystem 消息管理 + * @return 结果 + */ + public int insertMessageSystem(MessageSystem messageSystem); + + /** + * 修改消息管理 + * + * @param messageSystem 消息管理 + * @return 结果 + */ + public int updateMessageSystem(MessageSystem messageSystem); + + /** + * 删除消息管理 + * + * @param messageId 消息管理主键 + * @return 结果 + */ + public int deleteMessageSystemByMessageId(Long messageId); + + /** + * 批量删除消息管理 + * + * @param messageIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteMessageSystemByMessageIds(Long[] messageIds); + + //查询平台系统资源收件人用户信息 + @Select("SELECT user_id, dept_id, user_name, phonenumber, email FROM `sys_user`") + public List selectUser(); + + //查询角色信息 然后根据角色把消息发给某角色 + @Select("SELECT role_id, role_name FROM `sys_role`") + public List selectRole(); + + //查询部门信息 然后根据部门把消息发给某部门 + @Select("SELECT dept_id, parent_id, dept_name FROM `sys_dept`") + public List selectDept(); + + // 根据发送方式过滤用户 (短信或邮箱) + @Select("") + List selectUserBySendMode(String filterType); + + //将信息状态未读信息变为已读 + @Update("update message_system set message_status = 1 where message_id = #{messageId} and message_recipient = #{userName}") + public int updateState(Long messageId, String userName); + + + /** + * 根据部门ID获取所有符合条件的用户信息。 + * + * @param deptId 部门ID + * @return 用户信息列表 + */ + @Select("SELECT u.user_name FROM sys_user u JOIN sys_dept d ON u.dept_id = d.dept_id WHERE d.dept_id = #{deptId}") + public List getUserNameByDeptId(Long deptId); + + /** + * 根据角色ID查询用户列表。 + * + * @param roleId 角色ID + * @return 用户列表 + */ + @Select("SELECT u.user_name FROM sys_user u JOIN sys_user_role ur ON u.user_id = ur.user_id WHERE ur.role_id = #{roleId}") + public List selectUsersByRoleId(Long roleId); + + //查询模版签名 + @Select("SELECT template_id,template_code FROM `message_template`") + public List selecTemplates(); + + //批量发送信息 + public int batchInsertMessageSystem(List messageSystemList); +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/mapper/MessageTemplateMapper.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/mapper/MessageTemplateMapper.java new file mode 100644 index 0000000..9fcedc3 --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/mapper/MessageTemplateMapper.java @@ -0,0 +1,73 @@ +package com.boyue.modelMessage.mapper; + +import java.util.List; + +import org.apache.ibatis.annotations.Select; + +import com.boyue.modelMessage.domain.MessageTemplate; + +/** + * 模版管理Mapper接口 + * + * @author boyue + * @date 2024-12-31 + */ +public interface MessageTemplateMapper +{ + /** + * 查询模版管理 + * + * @param templateId 模版管理主键 + * @return 模版管理 + */ + public MessageTemplate selectMessageTemplateByTemplateId(Long templateId); + + /** + * 查询模版管理列表 + * + * @param messageTemplate 模版管理 + * @return 模版管理集合 + */ + public List selectMessageTemplateList(MessageTemplate messageTemplate); + + /** + * 新增模版管理 + * + * @param messageTemplate 模版管理 + * @return 结果 + */ + public int insertMessageTemplate(MessageTemplate messageTemplate); + + /** + * 修改模版管理 + * + * @param messageTemplate 模版管理 + * @return 结果 + */ + public int updateMessageTemplate(MessageTemplate messageTemplate); + + /** + * 删除模版管理 + * + * @param templateId 模版管理主键 + * @return 结果 + */ + public int deleteMessageTemplateByTemplateId(Long templateId); + + /** + * 批量删除模版管理 + * + * @param templateIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteMessageTemplateByTemplateIds(Long[] templateIds); + + /** + * 根据模板templateCode查询模板信息 + * + * @param templateCode 模版编码 + * @return 模版对象 + */ + @Select("SELECT template_code,template_variable,template_content FROM `message_template` WHERE template_code = #{templateCode}") + public MessageTemplate selectMessageTemplateByTemplateCode(String templateCode); +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/mapper/MessageVariableMapper.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/mapper/MessageVariableMapper.java new file mode 100644 index 0000000..6b6e1ba --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/mapper/MessageVariableMapper.java @@ -0,0 +1,75 @@ +package com.boyue.modelMessage.mapper; + +import java.util.List; + +import org.apache.ibatis.annotations.Select; + +import com.boyue.modelMessage.domain.MessageVariable; + +/** + * 变量管理Mapper接口 + * + * @author boyue + * @date 2024-12-31 + */ +public interface MessageVariableMapper +{ + /** + * 查询变量管理 + * + * @param variableId 变量管理主键 + * @return 变量管理 + */ + public MessageVariable selectMessageVariableByVariableId(Long variableId); + + /** + * 查询变量管理列表 + * + * @param messageVariable 变量管理 + * @return 变量管理集合 + */ + public List selectMessageVariableList(MessageVariable messageVariable); + + /** + * 新增变量管理 + * + * @param messageVariable 变量管理 + * @return 结果 + */ + public int insertMessageVariable(MessageVariable messageVariable); + + /** + * 修改变量管理 + * + * @param messageVariable 变量管理 + * @return 结果 + */ + public int updateMessageVariable(MessageVariable messageVariable); + + /** + * 删除变量管理 + * + * @param variableId 变量管理主键 + * @return 结果 + */ + public int deleteMessageVariableByVariableId(Long variableId); + + /** + * 批量删除变量管理 + * + * @param variableIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteMessageVariableByVariableIds(Long[] variableIds); + + //查询变量 + @Select("SELECT variable_id, variable_name, variable_type, variable_content FROM message_variable") + public List selectMessageVariable(); + + //查询在使用模版签名时用到了那些变量一一赋值 + public List selectMessageVariables(List variableNames); + + //查询模版使用的变量 + @Select("SELECT template_variable FROM message_template") + public List selectAllTemplateVariables(); +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/IMessageSystemService.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/IMessageSystemService.java new file mode 100644 index 0000000..cb89637 --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/IMessageSystemService.java @@ -0,0 +1,108 @@ +package com.boyue.modelMessage.service; + +import java.util.List; + +import com.boyue.common.core.domain.entity.SysDept; +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.modelMessage.domain.MessageSystem; +import com.boyue.modelMessage.domain.MessageTemplate; + +/** + * 消息管理Service接口 + * + * @author boyue + * @date 2024-12-21 + */ +public interface IMessageSystemService +{ + /** + * 查询消息管理 + * + * @param messageId 消息管理主键 + * @return 消息管理 + */ + public MessageSystem selectMessageSystemByMessageId(Long messageId); + + /** + * 查询消息管理列表 + * + * @param messageSystem 消息管理 + * @return 消息管理集合 + */ + public List selectMessageSystemList(MessageSystem messageSystem); + + /** + * 新增消息管理 + * + * @param messageSystem 消息管理 + * @return 结果 + */ + public int insertMessageSystem(MessageSystem messageSystem); + + /** + * 修改消息管理 + * + * @param messageSystem 消息管理 + * @return 结果 + */ + public int updateMessageSystem(MessageSystem messageSystem); + + /** + * 批量删除消息管理 + * + * @param messageIds 需要删除的消息管理主键集合 + * @return 结果 + */ + public int deleteMessageSystemByMessageIds(Long[] messageIds); + + /** + * 删除消息管理信息 + * + * @param messageId 消息管理主键 + * @return 结果 + */ + public int deleteMessageSystemByMessageId(Long messageId); + + //查询系统资源用户信息 + public List selectUser(); + + //将信息状态未读信息变为已读 + public int updateState(Long messageId); + + //根据发送方式 执行不同操作 + public void processMessageSystem(MessageSystem messageSystem); + + // 根据发送方式过滤用户 (短信或邮箱) + public List getUsersFilteredBySendMode(String filterType); + + //查询角色信息 然后根据角色把消息发给某角色 + public List selectRole(); + + //查询部门信息 然后根据部门把消息发给某部门 + public List selectDept(); + + /** + * 根据角色ID获取用户列表。 + * + * @param roleId 角色ID + * @return + * + * */ + public List selectUsersByRoleId(Long roleId); + + /** + * 根据部门ID获取用户列表。 + * + * @param deptId 部门ID + * @return + * + * */ + public List getUserNameByDeptId(Long deptId); + + // 查询模版签名 + public List selecTemplates(); + + // 批量发送信息 + public int batchInsertMessageSystem(List messageSystemList); +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/IMessageTemplateService.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/IMessageTemplateService.java new file mode 100644 index 0000000..5ec471b --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/IMessageTemplateService.java @@ -0,0 +1,62 @@ +package com.boyue.modelMessage.service; + +import java.util.List; + +import com.boyue.modelMessage.domain.MessageTemplate; + +/** + * 模版管理Service接口 + * + * @author boyue + * @date 2024-12-31 + */ +public interface IMessageTemplateService +{ + /** + * 查询模版管理 + * + * @param templateId 模版管理主键 + * @return 模版管理 + */ + public MessageTemplate selectMessageTemplateByTemplateId(Long templateId); + + /** + * 查询模版管理列表 + * + * @param messageTemplate 模版管理 + * @return 模版管理集合 + */ + public List selectMessageTemplateList(MessageTemplate messageTemplate); + + /** + * 新增模版管理 + * + * @param messageTemplate 模版管理 + * @return 结果 + */ + public int insertMessageTemplate(MessageTemplate messageTemplate); + + /** + * 修改模版管理 + * + * @param messageTemplate 模版管理 + * @return 结果 + */ + public int updateMessageTemplate(MessageTemplate messageTemplate); + + /** + * 批量删除模版管理 + * + * @param templateIds 需要删除的模版管理主键集合 + * @return 结果 + */ + public int deleteMessageTemplateByTemplateIds(Long[] templateIds); + + /** + * 删除模版管理信息 + * + * @param templateId 模版管理主键 + * @return 结果 + */ + public int deleteMessageTemplateByTemplateId(Long templateId); +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/IMessageVariableService.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/IMessageVariableService.java new file mode 100644 index 0000000..1d17aee --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/IMessageVariableService.java @@ -0,0 +1,67 @@ +package com.boyue.modelMessage.service; + +import java.util.List; + +import com.boyue.modelMessage.domain.MessageVariable; + +/** + * 变量管理Service接口 + * + * @author boyue + * @date 2024-12-31 + */ +public interface IMessageVariableService +{ + /** + * 查询变量管理 + * + * @param variableId 变量管理主键 + * @return 变量管理 + */ + public MessageVariable selectMessageVariableByVariableId(Long variableId); + + /** + * 查询变量管理列表 + * + * @param messageVariable 变量管理 + * @return 变量管理集合 + */ + public List selectMessageVariableList(MessageVariable messageVariable); + + /** + * 新增变量管理 + * + * @param messageVariable 变量管理 + * @return 结果 + */ + public int insertMessageVariable(MessageVariable messageVariable); + + /** + * 修改变量管理 + * + * @param messageVariable 变量管理 + * @return 结果 + */ + public int updateMessageVariable(MessageVariable messageVariable); + + /** + * 批量删除变量管理 + * + * @param variableIds 需要删除的变量管理主键集合 + * @return 结果 + */ + public int deleteMessageVariableByVariableIds(Long[] variableIds); + + /** + * 删除变量管理信息 + * + * @param variableId 变量管理主键 + * @return 结果 + */ + public int deleteMessageVariableByVariableId(Long variableId); + + /** + * 查询全部变量 + */ + public List selectMessageVariable(); +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/impl/MessageSystemServiceImpl.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/impl/MessageSystemServiceImpl.java new file mode 100644 index 0000000..c1463e1 --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/impl/MessageSystemServiceImpl.java @@ -0,0 +1,305 @@ +package com.boyue.modelMessage.service.impl; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson2.JSONObject; +import com.boyue.common.core.domain.entity.SysDept; +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.DateUtils; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.modelMessage.domain.MessageSystem; +import com.boyue.modelMessage.domain.MessageTemplate; +import com.boyue.modelMessage.enums.SendMode; +import com.boyue.modelMessage.mapper.MessageSystemMapper; +import com.boyue.modelMessage.service.IMessageSystemService; +import com.boyue.modelMessage.utils.MessageSystemUtils; +import com.boyue.tfa.email.utils.EmailUtil; +import com.boyue.tfa.phone.config.DySmsConfig; +import com.boyue.tfa.phone.domain.DySmsTemplate; +import com.boyue.tfa.phone.utils.DySmsUtil; + +/** + * 消息管理Service业务层处理 + * + */ +@Service +public class MessageSystemServiceImpl implements IMessageSystemService { + + private static final Logger log = LoggerFactory.getLogger(MessageSystemServiceImpl.class); + + @Autowired + private DySmsConfig dySmsConfig; + + @Autowired + private MessageSystemMapper messageSystemMapper; + + @Autowired + private MessageSystemUtils messageSystemUtils; + + /** + * 查询消息管理 + * + * @param messageId 消息管理主键 + * @return 消息管理 + */ + @Override + public MessageSystem selectMessageSystemByMessageId(Long messageId) { + return messageSystemMapper.selectMessageSystemByMessageId(messageId); + } + + /** + * 查询消息管理列表 + * + * @param messageSystem 消息管理 + * @return 消息管理列表 + */ + @Override + public List selectMessageSystemList(MessageSystem messageSystem) { + return messageSystemMapper.selectMessageSystemList(messageSystem); + } + + /** + * 新增消息管理 + * + * @param messageSystem 消息管理 + * @return 结果 + */ + @Override + public int insertMessageSystem(MessageSystem messageSystem) { + messageSystem.setMessageStatus("0"); // 默认发送信息为未读状态 + messageSystem.setCreateBy(SecurityUtils.getUsername()); + messageSystem.setUpdateBy(SecurityUtils.getUsername()); + messageSystem.setCreateTime(DateUtils.getNowDate()); + messageSystem.setUpdateTime(DateUtils.getNowDate()); + return messageSystemMapper.insertMessageSystem(messageSystem); + } + + /** + * 修改消息管理 + * + * @param messageSystem 消息管理 + * @return 结果 + */ + @Override + public int updateMessageSystem(MessageSystem messageSystem) { + messageSystem.setUpdateTime(DateUtils.getNowDate()); + return messageSystemMapper.updateMessageSystem(messageSystem); + } + + /** + * 批量删除消息管理 + * + * @param messageIds 需要删除的消息管理主键 + * @return 结果 + */ + @Override + public int deleteMessageSystemByMessageIds(Long[] messageIds) { + return messageSystemMapper.deleteMessageSystemByMessageIds(messageIds); + } + + /** + * 删除消息管理信息 + * + * @param messageId 消息管理主键 + * @return 结果 + */ + @Override + public int deleteMessageSystemByMessageId(Long messageId) { + return messageSystemMapper.deleteMessageSystemByMessageId(messageId); + } + + // 查询系统资源用户信息 + @Override + public List selectUser() { + return messageSystemMapper.selectUser(); + } + + // 收件人为本人的话点击信息详情的时候然后把状态未读信息修改为已读 + @Override + public int updateState(Long messageId) { + int result = messageSystemMapper.updateState(messageId, SecurityUtils.getUsername()); + return result; + } + + // 根据发送方式过滤用户 (短信或邮箱) + @Override + public List getUsersFilteredBySendMode(String filterType) { + return messageSystemMapper.selectUserBySendMode(filterType); + } + + // 查询角色信息 然后根据角色把消息发给某角色 + @Override + public List selectRole() { + return messageSystemMapper.selectRole(); + } + + // 查询部门信息 然后根据部门把消息发给某部门 + @Override + public List selectDept() { + return messageSystemMapper.selectDept(); + } + + /** + * 根据角色ID获取对应用户信息。 + * + * @param roleId 角色ID + * @return 符合条件的用户列表 + */ + @Override + public List selectUsersByRoleId(Long roleId) { + List roleList = messageSystemMapper.selectUsersByRoleId(roleId); + return roleList; + } + + /** + * 根据角色ID获取用户ID列表。 + * + * @param roleId 角色ID + * @return 用户ID列表 + */ + @Override + public List getUserNameByDeptId(Long deptId) { + List depts = messageSystemMapper.getUserNameByDeptId(deptId); + return depts; + } + + // 查询模版签名 + @Override + public List selecTemplates() { + List templates = messageSystemMapper.selecTemplates(); + return templates; + } + + /** + * 批量发送信息 + */ + @Override + public int batchInsertMessageSystem(List messageSystemList) { + String username = SecurityUtils.getUsername(); + Date nowDate = DateUtils.getNowDate(); + for (MessageSystem messageSystem : messageSystemList) { + messageSystem.setMessageStatus("0"); // 默认发送信息为未读状态 + messageSystem.setCreateBy(username); + messageSystem.setUpdateBy(username); + messageSystem.setCreateTime(nowDate); + messageSystem.setUpdateTime(nowDate); + } + int result = messageSystemMapper.batchInsertMessageSystem(messageSystemList); + if (result <= 0) { + throw new ServiceException("消息发送失败!"); + } + return result; + } + + /** + * 根据 MessageSystem 对象的 sendMode 属性处理消息的发送方式 + */ + @Override + public void processMessageSystem(MessageSystem messageSystem) { + if (messageSystem == null || messageSystem.getSendMode() == null) { + throw new ServiceException("无效的消息系统对象或发送方式!"); + } + String sendModeStr = messageSystem.getSendMode(); + SendMode sendMode; + try { + sendMode = SendMode.fromCode(sendModeStr); + } catch (IllegalArgumentException e) { + throw new ServiceException("类型转换失败: " + sendModeStr); + } + switch (sendMode) { + case PHONE: + sendNotificationMessage(messageSystem); + break; + case EMAIL: + handleEmailNotification(messageSystem); + break; + case PLATFORM: + sendPlatformMessage(messageSystem); + break; + default: + throw new ServiceException("未知的发送方式!"); + } + } + + /** + * 发送平台消息 + */ + public void sendPlatformMessage(MessageSystem messageSystem) { + String notificationContent = messageSystem.getMessageContent(); + try { + String filledMessage = notificationContent.startsWith("SMS_") + ? messageSystemUtils.processTemplateMessage(messageSystem, notificationContent) + : notificationContent; // 是自定义输入,使用用户输入的内容 + log.info("平台内容: {}", filledMessage); + messageSystem.setMessageContent(filledMessage); + } catch (Exception e) { + log.error("发送平台消息时发生异常: ", e); + throw new ServiceException("发送平台消息异常:" + e.getMessage()); + } + } + + /** + * 发送邮件通知 + */ + public void handleEmailNotification(MessageSystem messageSystem) { + String email = messageSystem.getCode(); + if (StringUtils.isEmpty(email)) { + throw new ServiceException("邮箱地址不能为空!"); + } + try { + String filledMessage = messageSystem.getMessageContent().startsWith("SMS_") + ? messageSystemUtils.processTemplateMessage(messageSystem, messageSystem.getMessageContent()) + : messageSystem.getMessageContent(); // 是自定义输入,则直接使用用户提供的内容 + log.info("邮件内容: {}", filledMessage); + messageSystem.setMessageContent(filledMessage); + EmailUtil.sendMessage(email, "通知", filledMessage); + } catch (Exception e) { + log.error("发送邮件时发生异常: ", e); + throw new ServiceException("发送通知信息异常:" + e.getMessage()); + } + } + + /** + * 发送短信通知 + */ + @SuppressWarnings("unchecked") + public void sendNotificationMessage(MessageSystem messageSystem) { + String phone = messageSystem.getCode(); + if (StringUtils.isEmpty(phone)) { + throw new ServiceException("手机号码为空!"); + } + try { + // 解析并处理模板消息 + Map parsedParams = messageSystemUtils.parseInput(messageSystem.getMessageContent()); + String templateCode = (String) parsedParams.get("templateCode"); + DySmsTemplate dySmsTemplate = null; + if (templateCode != null) { + dySmsTemplate = dySmsConfig.getTemplate().get(templateCode); + Map params = (Map) parsedParams.get("params"); + // 提取模板中的变量名并填充内置变量 + List variableNames = (List) parsedParams.get("variableNames"); + messageSystemUtils.fillBuiltInVariables(params, messageSystem, variableNames); + String filledMessage = messageSystemUtils.fillTemplate((String) parsedParams.get("templateContent"), + params); + messageSystem.setMessageContent(filledMessage); + JSONObject templateParamJson = new JSONObject(params); + DySmsUtil.sendSms(phone, dySmsTemplate, templateParamJson); + } else { + DySmsUtil.sendSms(phone, null, null); + } + } catch (Exception e) { + log.error("发送短信时发生异常: ", e); + throw new ServiceException("发送短信异常:" + e.getMessage()); + } + } +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/impl/MessageTemplateServiceImpl.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/impl/MessageTemplateServiceImpl.java new file mode 100644 index 0000000..5d5c50f --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/impl/MessageTemplateServiceImpl.java @@ -0,0 +1,104 @@ +package com.boyue.modelMessage.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.boyue.common.utils.DateUtils; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.modelMessage.domain.MessageTemplate; +import com.boyue.modelMessage.mapper.MessageTemplateMapper; +import com.boyue.modelMessage.service.IMessageTemplateService; + + +/** + * 模版管理Service业务层处理 + * + * @author boyue + * @date 2024-12-31 + */ +@Service +public class MessageTemplateServiceImpl implements IMessageTemplateService +{ + @Autowired + private MessageTemplateMapper messageTemplateMapper; + + /** + * 查询模版管理 + * + * @param templateId 模版管理主键 + * @return 模版管理 + */ + @Override + public MessageTemplate selectMessageTemplateByTemplateId(Long templateId) + { + return messageTemplateMapper.selectMessageTemplateByTemplateId(templateId); + } + + /** + * 查询模版管理列表 + * + * @param messageTemplate 模版管理 + * @return 模版管理 + */ + @Override + public List selectMessageTemplateList(MessageTemplate messageTemplate) + { + return messageTemplateMapper.selectMessageTemplateList(messageTemplate); + } + + /** + * 新增模版管理 + * + * @param messageTemplate 模版管理 + * @return 结果 + */ + @Override + public int insertMessageTemplate(MessageTemplate messageTemplate) + { + messageTemplate.setCreateBy(SecurityUtils.getUsername()); + messageTemplate.setCreateTime(DateUtils.getNowDate()); + messageTemplate.setUpdateBy(SecurityUtils.getUsername()); + messageTemplate.setUpdateTime(DateUtils.getNowDate()); + return messageTemplateMapper.insertMessageTemplate(messageTemplate); + } + + /** + * 修改模版管理 + * + * @param messageTemplate 模版管理 + * @return 结果 + */ + @Override + public int updateMessageTemplate(MessageTemplate messageTemplate) + { + messageTemplate.setUpdateBy(SecurityUtils.getUsername()); + messageTemplate.setUpdateTime(DateUtils.getNowDate()); + return messageTemplateMapper.updateMessageTemplate(messageTemplate); + } + + /** + * 批量删除模版管理 + * + * @param templateIds 需要删除的模版管理主键 + * @return 结果 + */ + @Override + public int deleteMessageTemplateByTemplateIds(Long[] templateIds) + { + return messageTemplateMapper.deleteMessageTemplateByTemplateIds(templateIds); + } + + /** + * 删除模版管理信息 + * + * @param templateId 模版管理主键 + * @return 结果 + */ + @Override + public int deleteMessageTemplateByTemplateId(Long templateId) + { + return messageTemplateMapper.deleteMessageTemplateByTemplateId(templateId); + } +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/impl/MessageVariableServiceImpl.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/impl/MessageVariableServiceImpl.java new file mode 100644 index 0000000..560389a --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/service/impl/MessageVariableServiceImpl.java @@ -0,0 +1,129 @@ +package com.boyue.modelMessage.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.DateUtils; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.modelMessage.domain.MessageVariable; +import com.boyue.modelMessage.mapper.MessageVariableMapper; +import com.boyue.modelMessage.service.IMessageVariableService; + +/** + * 变量管理Service业务层处理 + * + * @author boyue + * @date 2024-12-31 + */ +@Service +public class MessageVariableServiceImpl implements IMessageVariableService +{ + + @Autowired + private MessageVariableMapper messageVariableMapper; + + /** + * 查询变量管理 + * + * @param variableId 变量管理主键 + * @return 变量管理 + */ + @Override + public MessageVariable selectMessageVariableByVariableId(Long variableId) + { + return messageVariableMapper.selectMessageVariableByVariableId(variableId); + } + + /** + * 查询变量管理列表 + * + * @param messageVariable 变量管理 + * @return 变量管理 + */ + @Override + public List selectMessageVariableList(MessageVariable messageVariable) + { + return messageVariableMapper.selectMessageVariableList(messageVariable); + } + + /** + * 新增变量管理 + * + * @param messageVariable 变量管理 + * @return 结果 + */ + @Override + public int insertMessageVariable(MessageVariable messageVariable) + { + messageVariable.setCreateBy(SecurityUtils.getUsername()); + messageVariable.setCreateTime(DateUtils.getNowDate()); + messageVariable.setUpdateBy(SecurityUtils.getUsername()); + messageVariable.setUpdateTime(DateUtils.getNowDate()); + return messageVariableMapper.insertMessageVariable(messageVariable); + } + + /** + * 修改变量管理 + * + * @param messageVariable 变量管理 + * @return 结果 + */ + @Override + public int updateMessageVariable(MessageVariable messageVariable) + { + messageVariable.setUpdateBy(SecurityUtils.getUsername()); + messageVariable.setUpdateTime(DateUtils.getNowDate()); + return messageVariableMapper.updateMessageVariable(messageVariable); + } + + /** + * 批量删除变量管理 + * + * @param variableIds 需要删除的变量管理主键 + * @return 结果 + */ + @Override + public int deleteMessageVariableByVariableIds(Long[] variableIds) + { + for (Long variableId : variableIds) { + // 获取变量信息 + MessageVariable variable = messageVariableMapper.selectMessageVariableByVariableId(variableId); + if (variable == null) { + throw new ServiceException("未找到该变量信息!"); + } + // 检查变量是否被模板使用 + String variableName = variable.getVariableName(); + List variables = messageVariableMapper.selectAllTemplateVariables(); + for (String templateVariable : variables) { + String[] templateParts = templateVariable.split("/"); + for (String part : templateParts) { + if (part.equals(variableName)) { + throw new ServiceException("变量为 '" + variableName + "'' 已被模版使用,不能删除!"); + } + } + } + } + return messageVariableMapper.deleteMessageVariableByVariableIds(variableIds); + } + + /** + * 删除变量管理信息 + * + * @param variableId 变量管理主键 + * @return 结果 + */ + @Override + public int deleteMessageVariableByVariableId(Long variableId) + { + return messageVariableMapper.deleteMessageVariableByVariableId(variableId); + } + + //查询变量 + @Override + public List selectMessageVariable() { + return messageVariableMapper.selectMessageVariable(); + } +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/utils/MessageLogAspect.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/utils/MessageLogAspect.java new file mode 100644 index 0000000..ff583af --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/utils/MessageLogAspect.java @@ -0,0 +1,68 @@ +package com.boyue.modelMessage.utils; + +import java.lang.reflect.Method; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import com.boyue.common.utils.DateUtils; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.modelMessage.annotation.MessageLog; +import com.boyue.modelMessage.domain.MessageSystem; +import com.boyue.modelMessage.enums.MessageType; +import com.boyue.modelMessage.service.IMessageSystemService; + +@Aspect +@Component +@Order(1) //Aspect 的优先级 +public class MessageLogAspect { + + private static final Logger logger = LoggerFactory.getLogger(MessageLogAspect.class); + + @Autowired + private IMessageSystemService messageSystemService; + + @Around("@annotation(messageLog)") + public Object handleMessageLog(ProceedingJoinPoint joinPoint, MessageLog messageLog) throws Throwable { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + // 获取注解信息 + String description = messageLog.description(); + String title = messageLog.title(); + MessageType messageType = messageLog.messageType(); + boolean immediateLog = messageLog.immediateLog(); + try { + Object result = joinPoint.proceed(); + // 如果设置了true立即执行 + if (immediateLog) { + logMessage(title, description, messageType); + } + return result; + } catch (Exception e) { + logger.error("消息记录失败,方法: {}, 描述: {}", method.getName(), description, e); + throw e; + } + } + + private void logMessage(String title, String description, MessageType messageType) { + MessageSystem messageSystem = new MessageSystem(); + messageSystem.setMessageTitle(title); // 标题 + messageSystem.setCreateBy(SecurityUtils.getUsername()); // 发送人 + messageSystem.setCreateTime(DateUtils.getNowDate()); // 发送时间 + messageSystem.setMessageContent(description); // 信息内容 + messageSystem.setMessageStatus("0"); // 默认为未读 0未读 1 已读 + messageSystem.setMessageType(messageType.getCode()); + messageSystem.setUpdateBy(SecurityUtils.getUsername()); // 修改人 + messageSystem.setUpdateTime(DateUtils.getNowDate()); // 修改时间 + messageSystem.setSendMode("0"); // 默认发送方式为平台 + messageSystemService.insertMessageSystem(messageSystem); + logger.info("消息记录成功,标题: {}, 描述: {}, 类型: {}", title, description, messageType); + } +} diff --git a/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/utils/MessageSystemUtils.java b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/utils/MessageSystemUtils.java new file mode 100644 index 0000000..8993261 --- /dev/null +++ b/boyue-models/boyue-message/src/main/java/com/boyue/modelMessage/utils/MessageSystemUtils.java @@ -0,0 +1,224 @@ +package com.boyue.modelMessage.utils; + +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.DateUtils; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.modelMessage.domain.MessageSystem; +import com.boyue.modelMessage.domain.MessageTemplate; +import com.boyue.modelMessage.domain.MessageVariable; +import com.boyue.modelMessage.mapper.MessageTemplateMapper; +import com.boyue.modelMessage.mapper.MessageVariableMapper; + +@Component +public class MessageSystemUtils { + + private static final String NUMERIC_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static final int CODE_LENGTH = 6; + + @Autowired + private MessageTemplateMapper messageTemplateMapper; + + @Autowired + private MessageVariableMapper messageVariableMapper; + + /** + * 解析输入字符串,提取模板代码和参数 + * + * @param input 输入字符串 + * @return 解析结果 + */ + public Map parseInput(String input) { + if (input == null) { + throw new ServiceException("输入内容不能为空!"); + } + String templateCode = null; + String queryParams = ""; + if (input.startsWith("SMS_")) { + int templateCodeEndIndex = input.indexOf('?'); + if (templateCodeEndIndex != -1) { + templateCode = input.substring(0, templateCodeEndIndex); + queryParams = input.substring(templateCodeEndIndex + 1); + } else { + templateCode = input; + } + } + MessageTemplate templateContent = null; + List variableNames = new ArrayList<>(); + if (templateCode != null) { + templateContent = messageTemplateMapper.selectMessageTemplateByTemplateCode(templateCode); + if (templateContent == null) { + throw new ServiceException("未找到该模版签名! " + templateCode); + } + variableNames = extractVariableNamesFromTemplate(templateContent); + } + + Map params = new HashMap<>(); + if (!queryParams.isEmpty()) { + for (String param : queryParams.split("&")) { + String[] keyValue = param.split("=", 2); + if (keyValue.length != 2) { + throw new ServiceException("无效的参数格式:" + param); + } + params.put(keyValue[0], URLDecoder.decode(keyValue[1], StandardCharsets.UTF_8)); + } + } + if (templateContent != null) { + for (String varName : variableNames) { + if (!params.containsKey(varName)) { + params.put(varName, null); //默认先不传递 等自动填充值 + } + } + } + return Map.of("templateCode", templateCode, "params", params, + "templateContent", templateContent != null ? templateContent.getTemplateContent() : input, + "variableNames", variableNames); + } + + /** + * 提取模板中的变量名 + * + * @param templateContent 模板内容 + * @return 变量名列表 + */ + public List extractVariableNamesFromTemplate(MessageTemplate templateContent) { + List variableNames = new ArrayList<>(); + Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}"); + Matcher matcher = pattern.matcher(templateContent.getTemplateContent()); + while (matcher.find()) { + variableNames.add(matcher.group(1)); + } + return variableNames; + } + + /** + * 填充模板 + * + * @param template 模板 + * @param params 参数 + * @return 填充后的模板 + */ + public String fillTemplate(String template, Map params) { + String filledTemplate = template; + for (Map.Entry entry : params.entrySet()) { + filledTemplate = filledTemplate.replace("${" + entry.getKey() + "}", entry.getValue()); + } + return filledTemplate; + } + + /** + * 清除内置变量的随机数字 + * + * @param params 参数 + */ + public void clearBuiltInVariables(Map params) { + List builtInVariables = messageVariableMapper.selectMessageVariable(); + for (MessageVariable variable : builtInVariables) { + String variableContent = variable.getVariableContent(); + params.remove(variableContent); + } + } + + /** + * 处理模板消息并填充内置变量 + */ + public String processTemplateMessage(MessageSystem messageSystem, String notificationContent) throws Exception { + Map parsedParams = parseInput(notificationContent); + String templateCode = (String) parsedParams.get("templateCode"); + MessageTemplate templateContent = null; + + if (templateCode != null) { + templateContent = messageTemplateMapper.selectMessageTemplateByTemplateCode(templateCode); //查询获取模版内容 + } + + @SuppressWarnings("unchecked") + Map params = (Map) parsedParams.get("params"); + + // 检查参数 + List variableNames = new ArrayList<>(); + if (templateContent != null) { + variableNames = extractVariableNamesFromTemplate(templateContent); + for (String varName : variableNames) { + if (!params.containsKey(varName)) { + throw new ServiceException("缺少参数: " + varName); + } + } + } + clearBuiltInVariables(params); // 清除内置变量 + fillBuiltInVariables(params, messageSystem, variableNames); + // 如果未找到模板,使用原始内容作为模板 + String templateContentStr = templateContent != null ? templateContent.getTemplateContent() : notificationContent; + return fillTemplate(templateContentStr, params); + } + + /** + * 填充内置变量 + * + * @param params 参数 + * @param message 消息 + * @param variableNames 变量名列表 + */ + public void fillBuiltInVariables(Map params, MessageSystem message, List variableNames) { + List builtInVariables = messageVariableMapper.selectMessageVariables(variableNames); + for (MessageVariable variable : builtInVariables) { + String variableContent = variable.getVariableContent(); + String variableValue = "recipients".equals(variableContent) ? message.getMessageRecipient() : generateVariableContent(variableContent); + params.putIfAbsent(variableContent, variableValue); + } + } + + /** + * 生成变量内容 + * + * @param variableContent 变量内容 + * @return 生成的变量内容 + */ + public String generateVariableContent(String variableContent) { + switch (variableContent) { + case "time": + return DateUtils.dateTimeNow("HH:mm:ss"); //发送时间 + case "date": + return DateUtils.dateTimeNow("yyyy-MM-dd"); //发送日期 + case "datetime": + return DateUtils.dateTimeNow("yyyy-MM-dd HH:mm:ss"); //发送日期+时间 + case "addresser": + return SecurityUtils.getUsername(); //发件人 + case "code": + case "RandomnDigits": + case "RandomnCharacters": + case "RandomN-digitLetters": + return generateRandomCode(CODE_LENGTH); //随机数字+英文 + default: + throw new ServiceException("不明确的类型 " + variableContent); + } + } + + /** + * 生成指定长度的随机数字字符串 数字+英文 + * + * @param length 长度 + * @return 随机数字字符串 + */ + public String generateRandomCode(int length) { + Random random = new Random(); + StringBuilder codeBuilder = new StringBuilder(length); + for (int i = 0; i < length; i++) { + int index = random.nextInt(NUMERIC_CHARACTERS.length()); + char randomChar = NUMERIC_CHARACTERS.charAt(index); + codeBuilder.append(randomChar); + } + return codeBuilder.toString(); + } +} diff --git a/boyue-models/boyue-message/src/main/resources/mapper/modelMessage/MessageSystemMapper.xml b/boyue-models/boyue-message/src/main/resources/mapper/modelMessage/MessageSystemMapper.xml new file mode 100644 index 0000000..9b789ad --- /dev/null +++ b/boyue-models/boyue-message/src/main/resources/mapper/modelMessage/MessageSystemMapper.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + select message_id, message_title, message_content, message_status, message_type, create_by, create_time, update_by, update_time, remark, message_recipient, send_mode, `code` from message_system + + + + + + + + insert into message_system + + message_title, + message_content, + message_status, + message_type, + create_by, + create_time, + update_by, + update_time, + remark, + message_recipient, + send_mode, + code, + + + #{messageTitle}, + #{messageContent}, + #{messageStatus}, + #{messageType}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + #{messageRecipient}, + #{sendMode}, + #{code}, + + + + + update message_system + + message_title = #{messageTitle}, + message_content = #{messageContent}, + message_status = #{messageStatus}, + message_type = #{messageType}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + message_recipient = #{messageRecipient}, + send_mode = #{sendMode}, + code = #{code}, + + where message_system.message_id = #{messageId} + + + + delete from message_system where message_id = #{messageId} + + + + delete from message_system where message_id in + + #{messageId} + + + + + + INSERT INTO message_system (message_title, message_content, message_status, message_type, message_recipient, + send_mode, `code`, create_by, create_time, update_by, update_time, remark) VALUES + + ( #{item.messageTitle}, #{item.messageContent}, #{item.messageStatus}, #{item.messageType}, + #{item.messageRecipient}, #{item.sendMode}, #{item.code}, #{item.createBy}, NOW(), #{item.updateBy}, + NOW(), #{item.remark} ) + + + + \ No newline at end of file diff --git a/boyue-models/boyue-message/src/main/resources/mapper/modelMessage/MessageTemplateMapper.xml b/boyue-models/boyue-message/src/main/resources/mapper/modelMessage/MessageTemplateMapper.xml new file mode 100644 index 0000000..78553e5 --- /dev/null +++ b/boyue-models/boyue-message/src/main/resources/mapper/modelMessage/MessageTemplateMapper.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + select template_id, template_name, template_code, template_type, template_content, template_variable, create_by, create_time, update_by, update_time, remark from message_template + + + + + + + + insert into message_template + + template_name, + template_code, + template_type, + template_content, + template_variable, + create_by, + create_time, + update_by, + update_time, + remark, + + + #{templateName}, + #{templateCode}, + #{templateType}, + #{templateContent}, + #{templateVariable}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + + + + + update message_template + + template_name = #{templateName}, + template_code = #{templateCode}, + template_type = #{templateType}, + template_content = #{templateContent}, + template_variable = #{templateVariable}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where message_template.template_id = #{templateId} + + + + delete from message_template where template_id = #{templateId} + + + + delete from message_template where template_id in + + #{templateId} + + + \ No newline at end of file diff --git a/boyue-models/boyue-message/src/main/resources/mapper/modelMessage/MessageVariableMapper.xml b/boyue-models/boyue-message/src/main/resources/mapper/modelMessage/MessageVariableMapper.xml new file mode 100644 index 0000000..76c56a2 --- /dev/null +++ b/boyue-models/boyue-message/src/main/resources/mapper/modelMessage/MessageVariableMapper.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + select variable_id, variable_name, variable_type, variable_content, create_by, create_time, update_by, update_time, remark from message_variable + + + + + + + + insert into message_variable + + variable_name, + variable_type, + variable_content, + create_by, + create_time, + update_by, + update_time, + remark, + + + #{variableName}, + #{variableType}, + #{variableContent}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + + + + + update message_variable + + variable_name = #{variableName}, + variable_type = #{variableType}, + variable_content = #{variableContent}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where message_variable.variable_id = #{variableId} + + + + delete from message_variable where variable_id = #{variableId} + + + + delete from message_variable where variable_id in + + #{variableId} + + + + + + \ No newline at end of file diff --git a/boyue-models/boyue-models-starter/pom.xml b/boyue-models/boyue-models-starter/pom.xml new file mode 100644 index 0000000..ed6a2f2 --- /dev/null +++ b/boyue-models/boyue-models-starter/pom.xml @@ -0,0 +1,57 @@ + + + + boyue-models + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-models-starter + + + 中间件 + + + + + + + com.boyue + boyue-quartz + + + + + com.boyue + boyue-generator + + + + + com.boyue + boyue-online + + + + + com.boyue + boyue-message + + + + + com.boyue + boyue-form + + + + + com.boyue + boyue-hasfj + + + + + diff --git a/boyue-models/boyue-online/pom.xml b/boyue-models/boyue-online/pom.xml new file mode 100644 index 0000000..e169097 --- /dev/null +++ b/boyue-models/boyue-online/pom.xml @@ -0,0 +1,26 @@ + + + + boyue-models + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-online + + + online系统模块 + + + + + + com.boyue + boyue-common + + + + \ No newline at end of file diff --git a/boyue-models/boyue-online/src/main/java/com/boyue/online/controller/OnLineController.java b/boyue-models/boyue-online/src/main/java/com/boyue/online/controller/OnLineController.java new file mode 100644 index 0000000..969d807 --- /dev/null +++ b/boyue-models/boyue-online/src/main/java/com/boyue/online/controller/OnLineController.java @@ -0,0 +1,141 @@ +package com.boyue.online.controller; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Anonymous; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.security.service.IPermissionService; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.online.domain.OnlineMb; +import com.boyue.online.service.IOnlineMbService; +import com.boyue.online.utils.SqlMapper; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 在线接口 + * + * @author Dftre + * @date 2024-01-26 + */ +@RestController +@Anonymous +@RequestMapping("/online") +public class OnLineController extends BaseController { + @Autowired + private IOnlineMbService onlineMbService; + + @Autowired + private IPermissionService permissionService; + + @Autowired + private SqlSessionFactory sqlSessionFactory; + + @SuppressWarnings("unchecked") + public Map getParams(HashMap params, HashMap data) { + Map object = new HashMap<>(); + HashMap object_params = new HashMap(); + String keyregex = "params\\[(.*?)\\]"; + Pattern pattern = Pattern.compile(keyregex); + if (params != null) { + params.keySet().forEach(key -> { + Matcher matcher = pattern.matcher(key); + if (matcher.find()) { + object_params.put(matcher.group(1), params.get(key)); + } else { + object.put(key, params.get(key)); + } + }); + } + if (data != null) { + if (data.containsKey("params")) { + object_params.putAll((HashMap) data.get("params")); + data.remove("params"); + } + object.putAll(data); + } + object.put("params", object_params); + return object; + } + + public Boolean checkPermission(String permissionType, String permissionValue) { + if (permissionType == null) { + return true; + } + return switch (permissionType) { + case "hasPermi" -> permissionService.hasPermi(permissionValue); + case "lacksPermi" -> permissionService.lacksPermi(permissionValue); + case "hasAnyPermi" -> permissionService.hasAnyPermi(permissionValue); + case "hasRole" -> permissionService.hasRole(permissionValue); + case "lacksRole" -> permissionService.lacksRole(permissionValue); + case "hasAnyRoles" -> permissionService.hasAnyRoles(permissionValue); + default -> true; + }; + } + + public Object processingMapper(String sqlContext, String actuatot, Map params) { + String sql = ""; + SqlSession sqlSession = sqlSessionFactory.openSession(); + try { + SqlMapper sqlMapper = new SqlMapper(sqlSession); + Object res = null; + res = switch (actuatot) { + case "selectList" -> getDataTable(sqlMapper.selectList(sql, params)); + case "insert" -> toAjax(sqlMapper.insert(sql, params)); + case "selectOne" -> success(sqlMapper.selectOne(sql, params)); + case "update" -> toAjax(sqlMapper.update(sql, params)); + case "delete" -> toAjax(sqlMapper.delete(sql, params)); + default -> AjaxResult.error(500, "系统错误,执行器错误"); + }; + return res; + } finally { + sqlSession.close(); + } + + } + + @RequestMapping("/api/**") + public Object api(@RequestParam(required = false) HashMap params, + @RequestBody(required = false) HashMap data, HttpServletRequest request, + HttpServletResponse response) { + OnlineMb selectOnlineMb = new OnlineMb(); + selectOnlineMb.setPath(request.getRequestURI().replace("/online/api", "")); + selectOnlineMb.setMethod(request.getMethod()); + + Map object = getParams(params, data); + + List selectOnlineMbList = onlineMbService.selectOnlineMbList(selectOnlineMb); + if (selectOnlineMbList.size() == 0) { + return AjaxResult.error("没有资源" + selectOnlineMb.getPath()); + } else if (selectOnlineMbList.size() > 1) { + return AjaxResult.error(500, "系统错误,在线接口重复"); + } else { + OnlineMb onlineMb = selectOnlineMbList.get(0); + if (!checkPermission(onlineMb.getPermissionType(), onlineMb.getPermissionValue())) { + return AjaxResult.error(403, "没有权限,请联系管理员授权"); + } + if (onlineMb.getDeptId() != null && onlineMb.getDeptId().equals("1")) { + object.put("deptId", SecurityUtils.getDeptId()); + } + if (onlineMb.getUserId() != null && onlineMb.getUserId().equals("1")) { + object.put("userId", SecurityUtils.getUserId()); + } + return processingMapper(onlineMb.getSqlText(), onlineMb.getActuator(), object); + } + } + +} diff --git a/boyue-models/boyue-online/src/main/java/com/boyue/online/controller/OnlineDbController.java b/boyue-models/boyue-online/src/main/java/com/boyue/online/controller/OnlineDbController.java new file mode 100644 index 0000000..49dc22e --- /dev/null +++ b/boyue-models/boyue-online/src/main/java/com/boyue/online/controller/OnlineDbController.java @@ -0,0 +1,39 @@ +package com.boyue.online.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Anonymous; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.BaseEntity; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.online.mapper.OnlineDbMapper; + + +/** + * mysql数据库Controller接口 + * + * @author Dftre + * @date 2024-01-26 + */ +@RestController +@RequestMapping("/online/db") +@Anonymous +public class OnlineDbController extends BaseController { + + @Autowired + private OnlineDbMapper onlineDbMapper; + + @GetMapping("/table/list") + public TableDataInfo selectDbTableList(BaseEntity baseEntity){ + startPage(); + return getDataTable(onlineDbMapper.selectDbTableList(baseEntity)); + } + + @GetMapping("/column/list") + public TableDataInfo selectDbColumnsListByTableName(String tableName){ + return getDataTable(onlineDbMapper.selectDbColumnsListByTableName(tableName)); + } +} diff --git a/boyue-models/boyue-online/src/main/java/com/boyue/online/controller/OnlineMbController.java b/boyue-models/boyue-online/src/main/java/com/boyue/online/controller/OnlineMbController.java new file mode 100644 index 0000000..6e678b5 --- /dev/null +++ b/boyue-models/boyue-online/src/main/java/com/boyue/online/controller/OnlineMbController.java @@ -0,0 +1,116 @@ +package com.boyue.online.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.online.domain.OnlineMb; +import com.boyue.online.service.IOnlineMbService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * mybatis在线接口Controller + * + * @author Dftre + * @date 2024-01-26 + */ +@RestController +@RequestMapping("/online/mb") +@Tag(name = "【mybatis在线接口】管理") +public class OnlineMbController extends BaseController +{ + @Autowired + private IOnlineMbService onlineMbService; + + /** + * 查询mybatis在线接口列表 + */ + @Operation(summary = "查询mybatis在线接口列表") + @PreAuthorize("@ss.hasPermi('online:mb:list')") + @GetMapping("/list") + public TableDataInfo list(OnlineMb onlineMb) + { + startPage(); + List list = onlineMbService.selectOnlineMbList(onlineMb); + return getDataTable(list); + } + + /** + * 导出mybatis在线接口列表 + */ + @Operation(summary = "导出mybatis在线接口列表") + @PreAuthorize("@ss.hasPermi('online:mb:export')") + @Log(title = "mybatis在线接口", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, OnlineMb onlineMb) + { + List list = onlineMbService.selectOnlineMbList(onlineMb); + ExcelUtil util = new ExcelUtil(OnlineMb.class); + util.exportExcel(response, list, "mybatis在线接口数据"); + } + + /** + * 获取mybatis在线接口详细信息 + */ + @Operation(summary = "获取mybatis在线接口详细信息") + @PreAuthorize("@ss.hasPermi('online:mb:query')") + @GetMapping(value = "/{mbId}") + public AjaxResult getInfo(@PathVariable("mbId") Long mbId) + { + return success(onlineMbService.selectOnlineMbByMbId(mbId)); + } + + /** + * 新增mybatis在线接口 + */ + @Operation(summary = "新增mybatis在线接口") + @PreAuthorize("@ss.hasPermi('online:mb:add')") + @Log(title = "mybatis在线接口", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody OnlineMb onlineMb) + { + return toAjax(onlineMbService.insertOnlineMb(onlineMb)); + } + + /** + * 修改mybatis在线接口 + */ + @Operation(summary = "修改mybatis在线接口") + @PreAuthorize("@ss.hasPermi('online:mb:edit')") + @Log(title = "mybatis在线接口", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody OnlineMb onlineMb) + { + return toAjax(onlineMbService.updateOnlineMb(onlineMb)); + } + + /** + * 删除mybatis在线接口 + */ + @Operation(summary = "删除mybatis在线接口") + @PreAuthorize("@ss.hasPermi('online:mb:remove')") + @Log(title = "mybatis在线接口", businessType = BusinessType.DELETE) + @DeleteMapping("/{mbIds}") + public AjaxResult remove(@PathVariable( name = "mbIds" ) Long[] mbIds) + { + return toAjax(onlineMbService.deleteOnlineMbByMbIds(mbIds)); + } +} diff --git a/boyue-models/boyue-online/src/main/java/com/boyue/online/domain/OnlineMb.java b/boyue-models/boyue-online/src/main/java/com/boyue/online/domain/OnlineMb.java new file mode 100644 index 0000000..118c077 --- /dev/null +++ b/boyue-models/boyue-online/src/main/java/com/boyue/online/domain/OnlineMb.java @@ -0,0 +1,221 @@ +package com.boyue.online.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * mybatis在线接口对象 online_mb + * + * @author Dftre + * @date 2024-01-26 + */ +@Schema(description = "mybatis在线接口对象") +public class OnlineMb extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** 主键 */ + @Schema(title = "主键") + private Long mbId; + + /** 标签名 */ + @Schema(title = "标签名") + @Excel(name = "标签名") + private String tag; + + /** 标签id */ + @Schema(title = "标签id") + @Excel(name = "标签id") + private String tagId; + + /** 参数类型 */ + @Schema(title = "参数类型") + @Excel(name = "参数类型") + private String parameterType; + + /** 结果类型 */ + @Schema(title = "结果类型") + @Excel(name = "结果类型") + private String resultMap; + + /** sql语句 */ + @Schema(title = "sql语句") + @Excel(name = "sql语句") + private String sqlText; + + /** 请求路径 */ + @Schema(title = "请求路径") + @Excel(name = "请求路径") + private String path; + + /** 请求方式 */ + @Schema(title = "请求方式") + @Excel(name = "请求方式") + private String method; + + /** 响应类型 */ + @Schema(title = "响应类型") + @Excel(name = "响应类型") + private String resultType; + + /** 执行器 */ + @Schema(title = "执行器") + @Excel(name = "执行器") + private String actuator; + + /** 是否需要userId */ + @Schema(title = "是否需要userId") + @Excel(name = "是否需要userId") + private String userId; + + /** 是否需要deptId */ + @Schema(title = "是否需要deptId") + @Excel(name = "是否需要deptId") + private String deptId; + + /** 许可类型 */ + @Schema(title = "许可类型") + @Excel(name = "许可类型") + private String permissionType; + + /** 许可值 */ + @Schema(title = "许可值") + @Excel(name = "许可值") + private String permissionValue; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getPermissionType() { + return permissionType; + } + + public void setPermissionType(String permissionType) { + this.permissionType = permissionType; + } + + public String getPermissionValue() { + return permissionValue; + } + + public void setPermissionValue(String permissionValue) { + this.permissionValue = permissionValue; + } + + public void setMbId(Long mbId) { + this.mbId = mbId; + } + + public Long getMbId() { + return mbId; + } + + public void setTag(String tag) { + this.tag = tag; + } + + public String getTag() { + return tag; + } + + public void setTagId(String tagId) { + this.tagId = tagId; + } + + public String getTagId() { + return tagId; + } + + public void setParameterType(String parameterType) { + this.parameterType = parameterType; + } + + public String getParameterType() { + return parameterType; + } + + public void setResultMap(String resultMap) { + this.resultMap = resultMap; + } + + public String getResultMap() { + return resultMap; + } + + public void setSqlText(String sqlText) { + this.sqlText = sqlText; + } + + public String getSqlText() { + return sqlText; + } + + public void setPath(String path) { + this.path = path; + } + + public String getPath() { + return path; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getMethod() { + return method; + } + + public void setResultType(String resultType) { + this.resultType = resultType; + } + + public String getResultType() { + return resultType; + } + + public void setActuator(String actuator) { + this.actuator = actuator; + } + + public String getActuator() { + return actuator; + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("mbId", getMbId()) + .append("tag", getTag()) + .append("tagId", getTagId()) + .append("parameterType", getParameterType()) + .append("resultMap", getResultMap()) + .append("sqlText", getSqlText()) + .append("path", getPath()) + .append("method", getMethod()) + .append("resultType", getResultType()) + .append("actuator", getActuator()) + .append("userId",getUserId()) + .append("deptId",getDeptId()) + .append("permissionType",getPermissionType()) + .append("permissionValue",getPermissionValue()) + .toString(); + } +} diff --git a/boyue-models/boyue-online/src/main/java/com/boyue/online/mapper/OnlineDbMapper.java b/boyue-models/boyue-online/src/main/java/com/boyue/online/mapper/OnlineDbMapper.java new file mode 100644 index 0000000..83cd2f6 --- /dev/null +++ b/boyue-models/boyue-online/src/main/java/com/boyue/online/mapper/OnlineDbMapper.java @@ -0,0 +1,17 @@ +package com.boyue.online.mapper; + +import java.util.List; +import java.util.Map; + +import com.boyue.common.core.domain.BaseEntity; + +/** + * mysql数据库Mapper接口 + * + * @author Dftre + * @date 2024-01-26 + */ +public interface OnlineDbMapper { + public List> selectDbTableList(BaseEntity baseEntity); + public List> selectDbColumnsListByTableName(String tableName); +} diff --git a/boyue-models/boyue-online/src/main/java/com/boyue/online/mapper/OnlineMbMapper.java b/boyue-models/boyue-online/src/main/java/com/boyue/online/mapper/OnlineMbMapper.java new file mode 100644 index 0000000..74d7136 --- /dev/null +++ b/boyue-models/boyue-online/src/main/java/com/boyue/online/mapper/OnlineMbMapper.java @@ -0,0 +1,62 @@ +package com.boyue.online.mapper; + +import java.util.List; + +import com.boyue.online.domain.OnlineMb; + +/** + * mybatis在线接口Mapper接口 + * + * @author Dftre + * @date 2024-01-26 + */ +public interface OnlineMbMapper +{ + /** + * 查询mybatis在线接口 + * + * @param mbId mybatis在线接口主键 + * @return mybatis在线接口 + */ + public OnlineMb selectOnlineMbByMbId(Long mbId); + + /** + * 查询mybatis在线接口列表 + * + * @param onlineMb mybatis在线接口 + * @return mybatis在线接口集合 + */ + public List selectOnlineMbList(OnlineMb onlineMb); + + /** + * 新增mybatis在线接口 + * + * @param onlineMb mybatis在线接口 + * @return 结果 + */ + public int insertOnlineMb(OnlineMb onlineMb); + + /** + * 修改mybatis在线接口 + * + * @param onlineMb mybatis在线接口 + * @return 结果 + */ + public int updateOnlineMb(OnlineMb onlineMb); + + /** + * 删除mybatis在线接口 + * + * @param mbId mybatis在线接口主键 + * @return 结果 + */ + public int deleteOnlineMbByMbId(Long mbId); + + /** + * 批量删除mybatis在线接口 + * + * @param mbIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteOnlineMbByMbIds(Long[] mbIds); +} diff --git a/boyue-models/boyue-online/src/main/java/com/boyue/online/service/IOnlineMbService.java b/boyue-models/boyue-online/src/main/java/com/boyue/online/service/IOnlineMbService.java new file mode 100644 index 0000000..2735dbb --- /dev/null +++ b/boyue-models/boyue-online/src/main/java/com/boyue/online/service/IOnlineMbService.java @@ -0,0 +1,62 @@ +package com.boyue.online.service; + +import java.util.List; + +import com.boyue.online.domain.OnlineMb; + +/** + * mybatis在线接口Service接口 + * + * @author Dftre + * @date 2024-01-26 + */ +public interface IOnlineMbService +{ + /** + * 查询mybatis在线接口 + * + * @param mbId mybatis在线接口主键 + * @return mybatis在线接口 + */ + public OnlineMb selectOnlineMbByMbId(Long mbId); + + /** + * 查询mybatis在线接口列表 + * + * @param onlineMb mybatis在线接口 + * @return mybatis在线接口集合 + */ + public List selectOnlineMbList(OnlineMb onlineMb); + + /** + * 新增mybatis在线接口 + * + * @param onlineMb mybatis在线接口 + * @return 结果 + */ + public int insertOnlineMb(OnlineMb onlineMb); + + /** + * 修改mybatis在线接口 + * + * @param onlineMb mybatis在线接口 + * @return 结果 + */ + public int updateOnlineMb(OnlineMb onlineMb); + + /** + * 批量删除mybatis在线接口 + * + * @param mbIds 需要删除的mybatis在线接口主键集合 + * @return 结果 + */ + public int deleteOnlineMbByMbIds(Long[] mbIds); + + /** + * 删除mybatis在线接口信息 + * + * @param mbId mybatis在线接口主键 + * @return 结果 + */ + public int deleteOnlineMbByMbId(Long mbId); +} diff --git a/boyue-models/boyue-online/src/main/java/com/boyue/online/service/impl/OnlineMbServiceImpl.java b/boyue-models/boyue-online/src/main/java/com/boyue/online/service/impl/OnlineMbServiceImpl.java new file mode 100644 index 0000000..be1850b --- /dev/null +++ b/boyue-models/boyue-online/src/main/java/com/boyue/online/service/impl/OnlineMbServiceImpl.java @@ -0,0 +1,95 @@ +package com.boyue.online.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.boyue.online.domain.OnlineMb; +import com.boyue.online.mapper.OnlineMbMapper; +import com.boyue.online.service.IOnlineMbService; + +/** + * mybatis在线接口Service业务层处理 + * + * @author Dftre + * @date 2024-01-26 + */ +@Service +public class OnlineMbServiceImpl implements IOnlineMbService +{ + @Autowired + private OnlineMbMapper onlineMbMapper; + + /** + * 查询mybatis在线接口 + * + * @param mbId mybatis在线接口主键 + * @return mybatis在线接口 + */ + @Override + public OnlineMb selectOnlineMbByMbId(Long mbId) + { + return onlineMbMapper.selectOnlineMbByMbId(mbId); + } + + /** + * 查询mybatis在线接口列表 + * + * @param onlineMb mybatis在线接口 + * @return mybatis在线接口 + */ + @Override + public List selectOnlineMbList(OnlineMb onlineMb) + { + return onlineMbMapper.selectOnlineMbList(onlineMb); + } + + /** + * 新增mybatis在线接口 + * + * @param onlineMb mybatis在线接口 + * @return 结果 + */ + @Override + public int insertOnlineMb(OnlineMb onlineMb) + { + return onlineMbMapper.insertOnlineMb(onlineMb); + } + + /** + * 修改mybatis在线接口 + * + * @param onlineMb mybatis在线接口 + * @return 结果 + */ + @Override + public int updateOnlineMb(OnlineMb onlineMb) + { + return onlineMbMapper.updateOnlineMb(onlineMb); + } + + /** + * 批量删除mybatis在线接口 + * + * @param mbIds 需要删除的mybatis在线接口主键 + * @return 结果 + */ + @Override + public int deleteOnlineMbByMbIds(Long[] mbIds) + { + return onlineMbMapper.deleteOnlineMbByMbIds(mbIds); + } + + /** + * 删除mybatis在线接口信息 + * + * @param mbId mybatis在线接口主键 + * @return 结果 + */ + @Override + public int deleteOnlineMbByMbId(Long mbId) + { + return onlineMbMapper.deleteOnlineMbByMbId(mbId); + } +} diff --git a/boyue-models/boyue-online/src/main/java/com/boyue/online/utils/SqlMapper.java b/boyue-models/boyue-online/src/main/java/com/boyue/online/utils/SqlMapper.java new file mode 100644 index 0000000..d5df049 --- /dev/null +++ b/boyue-models/boyue-online/src/main/java/com/boyue/online/utils/SqlMapper.java @@ -0,0 +1,411 @@ +package com.boyue.online.utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.builder.StaticSqlSource; +import org.apache.ibatis.exceptions.TooManyResultsException; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.ResultMap; +import org.apache.ibatis.mapping.ResultMapping; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.mapping.SqlSource; +import org.apache.ibatis.scripting.LanguageDriver; +import org.apache.ibatis.session.Configuration; +import org.apache.ibatis.session.SqlSession; + +/** + * MyBatis执行sql工具,在写SQL的时候建议使用参数形式的可以是${}或#{} + * + * 不建议将参数直接拼到字符串中,当大量这么使用的时候由于缓存MappedStatement而占用更多的内存 + * + * @author liuzh + * @since 2015-03-10 + */ +public class SqlMapper { + private final MSUtils msUtils; + private final SqlSession sqlSession; + + /** + * 构造方法,默认缓存MappedStatement + * + * @param sqlSession + */ + public SqlMapper(SqlSession sqlSession) { + this.sqlSession = sqlSession; + this.msUtils = new MSUtils(sqlSession.getConfiguration()); + } + + /** + * 获取List中最多只有一个的数据 + * + * @param list List结果 + * @param 泛型类型 + * @return + */ + private T getOne(List list) { + if (list.size() == 1) { + return list.get(0); + } else if (list.size() > 1) { + throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size()); + } else { + return null; + } + } + + /** + * 查询返回一个结果,多个结果时抛出异常 + * + * @param sql 执行的sql + * @return + */ + public Map selectOne(String sql) { + List> list = selectList(sql); + return getOne(list); + } + + /** + * 查询返回一个结果,多个结果时抛出异常 + * + * @param sql 执行的sql + * @param value 参数 + * @return + */ + public Map selectOne(String sql, Object value) { + List> list = selectList(sql, value); + return getOne(list); + } + + /** + * 查询返回一个结果,多个结果时抛出异常 + * + * @param sql 执行的sql + * @param resultType 返回的结果类型 + * @param 泛型类型 + * @return + */ + public T selectOne(String sql, Class resultType) { + List list = selectList(sql, resultType); + return getOne(list); + } + + /** + * 查询返回一个结果,多个结果时抛出异常 + * + * @param sql 执行的sql + * @param value 参数 + * @param resultType 返回的结果类型 + * @param 泛型类型 + * @return + */ + public T selectOne(String sql, Object value, Class resultType) { + List list = selectList(sql, value, resultType); + return getOne(list); + } + + /** + * 查询返回List> + * + * @param sql 执行的sql + * @return + */ + public List> selectList(String sql) { + String msId = msUtils.select(sql); + return sqlSession.selectList(msId); + } + + /** + * 查询返回List> + * + * @param sql 执行的sql + * @param value 参数 + * @return + */ + public List> selectList(String sql, Object value) { + Class parameterType = value != null ? value.getClass() : null; + String msId = msUtils.selectDynamic(sql, parameterType); + return sqlSession.selectList(msId, value); + } + + /** + * 查询返回指定的结果类型 + * + * @param sql 执行的sql + * @param resultType 返回的结果类型 + * @param 泛型类型 + * @return + */ + public List selectList(String sql, Class resultType) { + String msId; + if (resultType == null) { + msId = msUtils.select(sql); + } else { + msId = msUtils.select(sql, resultType); + } + return sqlSession.selectList(msId); + } + + /** + * 查询返回指定的结果类型 + * + * @param sql 执行的sql + * @param value 参数 + * @param resultType 返回的结果类型 + * @param 泛型类型 + * @return + */ + public List selectList(String sql, Object value, Class resultType) { + String msId; + Class parameterType = value != null ? value.getClass() : null; + if (resultType == null) { + msId = msUtils.selectDynamic(sql, parameterType); + } else { + msId = msUtils.selectDynamic(sql, parameterType, resultType); + } + return sqlSession.selectList(msId, value); + } + + /** + * 插入数据 + * + * @param sql 执行的sql + * @return + */ + public int insert(String sql) { + String msId = msUtils.insert(sql); + return sqlSession.insert(msId); + } + + /** + * 插入数据 + * + * @param sql 执行的sql + * @param value 参数 + * @return + */ + public int insert(String sql, Object value) { + Class parameterType = value != null ? value.getClass() : null; + String msId = msUtils.insertDynamic(sql, parameterType); + return sqlSession.insert(msId, value); + } + + /** + * 更新数据 + * + * @param sql 执行的sql + * @return + */ + public int update(String sql) { + String msId = msUtils.update(sql); + return sqlSession.update(msId); + } + + /** + * 更新数据 + * + * @param sql 执行的sql + * @param value 参数 + * @return + */ + public int update(String sql, Object value) { + Class parameterType = value != null ? value.getClass() : null; + String msId = msUtils.updateDynamic(sql, parameterType); + return sqlSession.update(msId, value); + } + + /** + * 删除数据 + * + * @param sql 执行的sql + * @return + */ + public int delete(String sql) { + String msId = msUtils.delete(sql); + return sqlSession.delete(msId); + } + + /** + * 删除数据 + * + * @param sql 执行的sql + * @param value 参数 + * @return + */ + public int delete(String sql, Object value) { + Class parameterType = value != null ? value.getClass() : null; + String msId = msUtils.deleteDynamic(sql, parameterType); + return sqlSession.delete(msId, value); + } + + private class MSUtils { + private Configuration configuration; + private LanguageDriver languageDriver; + + private MSUtils(Configuration configuration) { + this.configuration = configuration; + languageDriver = configuration.getDefaultScriptingLanguageInstance(); + } + + /** + * 创建MSID + * + * @param sql 执行的sql + * @param sql 执行的sqlCommandType + * @return + */ + private String newMsId(String sql, SqlCommandType sqlCommandType) { + StringBuilder msIdBuilder = new StringBuilder(sqlCommandType.toString()); + msIdBuilder.append(".").append(sql.hashCode()); + return msIdBuilder.toString(); + } + + /** + * 是否已经存在该ID + * + * @param msId + * @return + */ + private boolean hasMappedStatement(String msId) { + return configuration.hasStatement(msId, false); + } + + /** + * 创建一个查询的MS + * + * @param msId + * @param sqlSource 执行的sqlSource + * @param resultType 返回的结果类型 + */ + private void newSelectMappedStatement(String msId, SqlSource sqlSource, final Class resultType) { + MappedStatement ms = new MappedStatement.Builder(configuration, msId, sqlSource, SqlCommandType.SELECT) + .resultMaps(new ArrayList() { + { + add(new ResultMap.Builder(configuration, "defaultResultMap", resultType, new ArrayList(0)).build()); + } + }) + .build(); + //缓存 + configuration.addMappedStatement(ms); + } + + /** + * 创建一个简单的MS + * + * @param msId + * @param sqlSource 执行的sqlSource + * @param sqlCommandType 执行的sqlCommandType + */ + private void newUpdateMappedStatement(String msId, SqlSource sqlSource, SqlCommandType sqlCommandType) { + MappedStatement ms = new MappedStatement.Builder(configuration, msId, sqlSource, sqlCommandType) + .resultMaps(new ArrayList() { + { + add(new ResultMap.Builder(configuration, "defaultResultMap", int.class, new ArrayList(0)).build()); + } + }) + .build(); + //缓存 + configuration.addMappedStatement(ms); + } + + private String select(String sql) { + String msId = newMsId(sql, SqlCommandType.SELECT); + if (hasMappedStatement(msId)) { + return msId; + } + StaticSqlSource sqlSource = new StaticSqlSource(configuration, sql); + newSelectMappedStatement(msId, sqlSource, Map.class); + return msId; + } + + private String selectDynamic(String sql, Class parameterType) { + String msId = newMsId(sql + parameterType, SqlCommandType.SELECT); + if (hasMappedStatement(msId)) { + return msId; + } + SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, parameterType); + newSelectMappedStatement(msId, sqlSource, Map.class); + return msId; + } + + private String select(String sql, Class resultType) { + String msId = newMsId(resultType + sql, SqlCommandType.SELECT); + if (hasMappedStatement(msId)) { + return msId; + } + StaticSqlSource sqlSource = new StaticSqlSource(configuration, sql); + newSelectMappedStatement(msId, sqlSource, resultType); + return msId; + } + + private String selectDynamic(String sql, Class parameterType, Class resultType) { + String msId = newMsId(resultType + sql + parameterType, SqlCommandType.SELECT); + if (hasMappedStatement(msId)) { + return msId; + } + SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, parameterType); + newSelectMappedStatement(msId, sqlSource, resultType); + return msId; + } + + private String insert(String sql) { + String msId = newMsId(sql, SqlCommandType.INSERT); + if (hasMappedStatement(msId)) { + return msId; + } + StaticSqlSource sqlSource = new StaticSqlSource(configuration, sql); + newUpdateMappedStatement(msId, sqlSource, SqlCommandType.INSERT); + return msId; + } + + private String insertDynamic(String sql, Class parameterType) { + String msId = newMsId(sql + parameterType, SqlCommandType.INSERT); + if (hasMappedStatement(msId)) { + return msId; + } + SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, parameterType); + newUpdateMappedStatement(msId, sqlSource, SqlCommandType.INSERT); + return msId; + } + + private String update(String sql) { + String msId = newMsId(sql, SqlCommandType.UPDATE); + if (hasMappedStatement(msId)) { + return msId; + } + StaticSqlSource sqlSource = new StaticSqlSource(configuration, sql); + newUpdateMappedStatement(msId, sqlSource, SqlCommandType.UPDATE); + return msId; + } + + private String updateDynamic(String sql, Class parameterType) { + String msId = newMsId(sql + parameterType, SqlCommandType.UPDATE); + if (hasMappedStatement(msId)) { + return msId; + } + SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, parameterType); + newUpdateMappedStatement(msId, sqlSource, SqlCommandType.UPDATE); + return msId; + } + + private String delete(String sql) { + String msId = newMsId(sql, SqlCommandType.DELETE); + if (hasMappedStatement(msId)) { + return msId; + } + StaticSqlSource sqlSource = new StaticSqlSource(configuration, sql); + newUpdateMappedStatement(msId, sqlSource, SqlCommandType.DELETE); + return msId; + } + + private String deleteDynamic(String sql, Class parameterType) { + String msId = newMsId(sql + parameterType, SqlCommandType.DELETE); + if (hasMappedStatement(msId)) { + return msId; + } + SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, parameterType); + newUpdateMappedStatement(msId, sqlSource, SqlCommandType.DELETE); + return msId; + } + } +} \ No newline at end of file diff --git a/boyue-models/boyue-online/src/main/resources/mapper/online/OnlineDbMapper.xml b/boyue-models/boyue-online/src/main/resources/mapper/online/OnlineDbMapper.xml new file mode 100644 index 0000000..366d6a6 --- /dev/null +++ b/boyue-models/boyue-online/src/main/resources/mapper/online/OnlineDbMapper.xml @@ -0,0 +1,16 @@ + + + + + + + \ No newline at end of file diff --git a/boyue-models/boyue-online/src/main/resources/mapper/online/OnlineMbMapper.xml b/boyue-models/boyue-online/src/main/resources/mapper/online/OnlineMbMapper.xml new file mode 100644 index 0000000..80c589f --- /dev/null +++ b/boyue-models/boyue-online/src/main/resources/mapper/online/OnlineMbMapper.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + select mb_id, tag, tag_id, parameter_type, result_map, sql_text, online_mb.path, method, result_type, actuator,user_id,dept_id,permission_type,permission_value from online_mb + + + + + + + + insert into online_mb + + mb_id, + tag, + tag_id, + parameter_type, + result_map, + sql_text, + path, + method, + result_type, + actuator, + user_id, + dept_id, + permission_type, + permission_value, + + + #{mbId}, + #{tag}, + #{tagId}, + #{parameterType}, + #{resultMap}, + #{sqlText}, + #{path}, + #{method}, + #{resultType}, + #{actuator}, + #{userId}, + #{deptId}, + #{permissionType}, + #{permissionValue}, + + + + + update online_mb + + tag = #{tag}, + tag_id = #{tagId}, + parameter_type = #{parameterType}, + result_map = #{result_map}, + sql_text = #{sqlText}, + path = #{path}, + method = #{method}, + result_type = #{resultType}, + actuator = #{actuator}, + user_id = #{userId}, + dept_id = #{deptId}, + permission_type = #{permissionType}, + permission_value = #{permissionValue}, + + where online_mb.mb_id = #{mbId} and online_mb.del_flag != '1' + + + + update online_mb set del_flag = '1' where mb_id = #{mbId} + + + + update online_mb set del_flag = '1' where mb_id in + + #{mbId} + + + \ No newline at end of file diff --git a/boyue-models/boyue-quartz/pom.xml b/boyue-models/boyue-quartz/pom.xml new file mode 100644 index 0000000..3cede9a --- /dev/null +++ b/boyue-models/boyue-quartz/pom.xml @@ -0,0 +1,39 @@ + + + + boyue-models + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-quartz + + + quartz定时任务 + + + + + + + org.quartz-scheduler + quartz + + + com.mchange + c3p0 + + + + + + + com.boyue + boyue-common + + + + + diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/config/ScheduleConfig.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/config/ScheduleConfig.java new file mode 100644 index 0000000..00013dd --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/config/ScheduleConfig.java @@ -0,0 +1,57 @@ +//package com.boyue.quartz.config; +// +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.scheduling.quartz.SchedulerFactoryBean; +//import javax.sql.DataSource; +//import java.util.Properties; +// +///** +// * 定时任务配置(单机部署建议删除此类和qrtz数据库表,默认走内存会最高效) +// * +// * @author boyue +// */ +//@Configuration +//public class ScheduleConfig +//{ +// @Bean +// public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) +// { +// SchedulerFactoryBean factory = new SchedulerFactoryBean(); +// factory.setDataSource(dataSource); +// +// // quartz参数 +// Properties prop = new Properties(); +// prop.put("org.quartz.scheduler.instanceName", "boyueScheduler"); +// prop.put("org.quartz.scheduler.instanceId", "AUTO"); +// // 线程池配置 +// prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); +// prop.put("org.quartz.threadPool.threadCount", "20"); +// prop.put("org.quartz.threadPool.threadPriority", "5"); +// // JobStore配置 +// prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore"); +// // 集群配置 +// prop.put("org.quartz.jobStore.isClustered", "true"); +// prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000"); +// prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1"); +// prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true"); +// +// // sqlserver 启用 +// // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?"); +// prop.put("org.quartz.jobStore.misfireThreshold", "12000"); +// prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_"); +// factory.setQuartzProperties(prop); +// +// factory.setSchedulerName("boyueScheduler"); +// // 延时启动 +// factory.setStartupDelay(1); +// factory.setApplicationContextSchedulerContextKey("applicationContextKey"); +// // 可选,QuartzScheduler +// // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 +// factory.setOverwriteExistingJobs(true); +// // 设置自动启动,默认为true +// factory.setAutoStartup(true); +// +// return factory; +// } +//} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/controller/SysJobController.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/controller/SysJobController.java new file mode 100644 index 0000000..659f26d --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/controller/SysJobController.java @@ -0,0 +1,188 @@ +package com.boyue.quartz.controller; + +import java.util.List; + +import org.quartz.SchedulerException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.constant.Constants; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.exception.job.TaskException; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.quartz.domain.SysJob; +import com.boyue.quartz.service.ISysJobService; +import com.boyue.quartz.util.CronUtils; +import com.boyue.quartz.util.ScheduleUtils; + +import jakarta.servlet.http.HttpServletResponse; + +/** + * 调度任务信息操作处理 + * + * @author boyue + */ +@RestController +@RequestMapping("/monitor/job") +public class SysJobController extends BaseController +{ + @Autowired + private ISysJobService jobService; + + /** + * 查询定时任务列表 + */ + @PreAuthorize("@ss.hasPermi('monitor:job:list')") + @GetMapping("/list") + public TableDataInfo list(SysJob sysJob) + { + startPage(); + List list = jobService.selectJobList(sysJob); + return getDataTable(list); + } + + /** + * 导出定时任务列表 + */ + @PreAuthorize("@ss.hasPermi('monitor:job:export')") + @Log(title = "定时任务", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, SysJob sysJob) + { + List list = jobService.selectJobList(sysJob); + ExcelUtil util = new ExcelUtil(SysJob.class); + util.exportExcel(response, list, "定时任务"); + } + + /** + * 获取定时任务详细信息 + */ + @PreAuthorize("@ss.hasPermi('monitor:job:query')") + @GetMapping(value = "/{jobId}") + public AjaxResult getInfo(@PathVariable("jobId") Long jobId) + { + return success(jobService.selectJobById(jobId)); + } + + /** + * 新增定时任务 + */ + @PreAuthorize("@ss.hasPermi('monitor:job:add')") + @Log(title = "定时任务", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody SysJob job) throws SchedulerException, TaskException + { + if (!CronUtils.isValid(job.getCronExpression())) + { + return error("新增任务'" + job.getJobName() + "'失败,Cron表达式不正确"); + } + else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI)) + { + return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS })) + { + return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS })) + { + return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR)) + { + return error("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规"); + } + else if (!ScheduleUtils.whiteList(job.getInvokeTarget())) + { + return error("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内"); + } + job.setCreateBy(getUsername()); + return toAjax(jobService.insertJob(job)); + } + + /** + * 修改定时任务 + */ + @PreAuthorize("@ss.hasPermi('monitor:job:edit')") + @Log(title = "定时任务", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody SysJob job) throws SchedulerException, TaskException + { + if (!CronUtils.isValid(job.getCronExpression())) + { + return error("修改任务'" + job.getJobName() + "'失败,Cron表达式不正确"); + } + else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI)) + { + return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS })) + { + return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS })) + { + return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR)) + { + return error("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规"); + } + else if (!ScheduleUtils.whiteList(job.getInvokeTarget())) + { + return error("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内"); + } + job.setUpdateBy(getUsername()); + return toAjax(jobService.updateJob(job)); + } + + /** + * 定时任务状态修改 + */ + @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')") + @Log(title = "定时任务", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody SysJob job) throws SchedulerException + { + SysJob newJob = jobService.selectJobById(job.getJobId()); + newJob.setStatus(job.getStatus()); + return toAjax(jobService.changeStatus(newJob)); + } + + /** + * 定时任务立即执行一次 + */ + @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')") + @Log(title = "定时任务", businessType = BusinessType.UPDATE) + @PutMapping("/run") + public AjaxResult run(@RequestBody SysJob job) throws SchedulerException + { + boolean result = jobService.run(job); + return result ? success() : error("任务不存在或已过期!"); + } + + /** + * 删除定时任务 + */ + @PreAuthorize("@ss.hasPermi('monitor:job:remove')") + @Log(title = "定时任务", businessType = BusinessType.DELETE) + @DeleteMapping("/{jobIds}") + public AjaxResult remove(@PathVariable( name = "jobIds" ) Long[] jobIds) throws SchedulerException, TaskException + { + jobService.deleteJobByIds(jobIds); + return success(); + } +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/controller/SysJobLogController.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/controller/SysJobLogController.java new file mode 100644 index 0000000..d915e09 --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/controller/SysJobLogController.java @@ -0,0 +1,95 @@ +package com.boyue.quartz.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.quartz.domain.SysJobLog; +import com.boyue.quartz.service.ISysJobLogService; + +import jakarta.servlet.http.HttpServletResponse; + +/** + * 调度日志操作处理 + * + * @author boyue + */ +@RestController +@RequestMapping("/monitor/jobLog") +public class SysJobLogController extends BaseController +{ + @Autowired + private ISysJobLogService jobLogService; + + /** + * 查询定时任务调度日志列表 + */ + @PreAuthorize("@ss.hasPermi('monitor:job:list')") + @GetMapping("/list") + public TableDataInfo list(SysJobLog sysJobLog) + { + startPage(); + List list = jobLogService.selectJobLogList(sysJobLog); + return getDataTable(list); + } + + /** + * 导出定时任务调度日志列表 + */ + @PreAuthorize("@ss.hasPermi('monitor:job:export')") + @Log(title = "任务调度日志", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, SysJobLog sysJobLog) + { + List list = jobLogService.selectJobLogList(sysJobLog); + ExcelUtil util = new ExcelUtil(SysJobLog.class); + util.exportExcel(response, list, "调度日志"); + } + + /** + * 根据调度编号获取详细信息 + */ + @PreAuthorize("@ss.hasPermi('monitor:job:query')") + @GetMapping(value = "/{jobLogId}") + public AjaxResult getInfo(@PathVariable( name = "jobLogId" ) Long jobLogId) + { + return success(jobLogService.selectJobLogById(jobLogId)); + } + + + /** + * 删除定时任务调度日志 + */ + @PreAuthorize("@ss.hasPermi('monitor:job:remove')") + @Log(title = "定时任务调度日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{jobLogIds}") + public AjaxResult remove(@PathVariable( name = "jobLogIds" ) Long[] jobLogIds) + { + return toAjax(jobLogService.deleteJobLogByIds(jobLogIds)); + } + + /** + * 清空定时任务调度日志 + */ + @PreAuthorize("@ss.hasPermi('monitor:job:remove')") + @Log(title = "调度日志", businessType = BusinessType.CLEAN) + @DeleteMapping("/clean") + public AjaxResult clean() + { + jobLogService.cleanJobLog(); + return success(); + } +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/domain/SysJob.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/domain/SysJob.java new file mode 100644 index 0000000..006fba9 --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/domain/SysJob.java @@ -0,0 +1,171 @@ +package com.boyue.quartz.domain; + +import java.util.Date; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.boyue.common.annotation.Excel; +import com.boyue.common.annotation.Excel.ColumnType; +import com.boyue.common.constant.ScheduleConstants; +import com.boyue.common.core.domain.BaseEntity; +import com.boyue.common.utils.StringUtils; +import com.boyue.quartz.util.CronUtils; + +/** + * 定时任务调度表 sys_job + * + * @author boyue + */ +public class SysJob extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 任务ID */ + @Excel(name = "任务序号", cellType = ColumnType.NUMERIC) + private Long jobId; + + /** 任务名称 */ + @Excel(name = "任务名称") + private String jobName; + + /** 任务组名 */ + @Excel(name = "任务组名") + private String jobGroup; + + /** 调用目标字符串 */ + @Excel(name = "调用目标字符串") + private String invokeTarget; + + /** cron执行表达式 */ + @Excel(name = "执行表达式 ") + private String cronExpression; + + /** cron计划策略 */ + @Excel(name = "计划策略 ", readConverterExp = "0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行") + private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT; + + /** 是否并发执行(0允许 1禁止) */ + @Excel(name = "并发执行", readConverterExp = "0=允许,1=禁止") + private String concurrent; + + /** 任务状态(0正常 1暂停) */ + @Excel(name = "任务状态", readConverterExp = "0=正常,1=暂停") + private String status; + + public Long getJobId() + { + return jobId; + } + + public void setJobId(Long jobId) + { + this.jobId = jobId; + } + + @NotBlank(message = "任务名称不能为空") + @Size(min = 0, max = 64, message = "任务名称不能超过64个字符") + public String getJobName() + { + return jobName; + } + + public void setJobName(String jobName) + { + this.jobName = jobName; + } + + public String getJobGroup() + { + return jobGroup; + } + + public void setJobGroup(String jobGroup) + { + this.jobGroup = jobGroup; + } + + @NotBlank(message = "调用目标字符串不能为空") + @Size(min = 0, max = 500, message = "调用目标字符串长度不能超过500个字符") + public String getInvokeTarget() + { + return invokeTarget; + } + + public void setInvokeTarget(String invokeTarget) + { + this.invokeTarget = invokeTarget; + } + + @NotBlank(message = "Cron执行表达式不能为空") + @Size(min = 0, max = 255, message = "Cron执行表达式不能超过255个字符") + public String getCronExpression() + { + return cronExpression; + } + + public void setCronExpression(String cronExpression) + { + this.cronExpression = cronExpression; + } + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + public Date getNextValidTime() + { + if (StringUtils.isNotEmpty(cronExpression)) + { + return CronUtils.getNextExecution(cronExpression); + } + return null; + } + + public String getMisfirePolicy() + { + return misfirePolicy; + } + + public void setMisfirePolicy(String misfirePolicy) + { + this.misfirePolicy = misfirePolicy; + } + + public String getConcurrent() + { + return concurrent; + } + + public void setConcurrent(String concurrent) + { + this.concurrent = concurrent; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("jobId", getJobId()) + .append("jobName", getJobName()) + .append("jobGroup", getJobGroup()) + .append("cronExpression", getCronExpression()) + .append("nextValidTime", getNextValidTime()) + .append("misfirePolicy", getMisfirePolicy()) + .append("concurrent", getConcurrent()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/domain/SysJobLog.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/domain/SysJobLog.java new file mode 100644 index 0000000..28ca728 --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/domain/SysJobLog.java @@ -0,0 +1,155 @@ +package com.boyue.quartz.domain; + +import java.util.Date; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.boyue.common.annotation.Excel; +import com.boyue.common.core.domain.BaseEntity; + +/** + * 定时任务调度日志表 sys_job_log + * + * @author boyue + */ +public class SysJobLog extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** ID */ + @Excel(name = "日志序号") + private Long jobLogId; + + /** 任务名称 */ + @Excel(name = "任务名称") + private String jobName; + + /** 任务组名 */ + @Excel(name = "任务组名") + private String jobGroup; + + /** 调用目标字符串 */ + @Excel(name = "调用目标字符串") + private String invokeTarget; + + /** 日志信息 */ + @Excel(name = "日志信息") + private String jobMessage; + + /** 执行状态(0正常 1失败) */ + @Excel(name = "执行状态", readConverterExp = "0=正常,1=失败") + private String status; + + /** 异常信息 */ + @Excel(name = "异常信息") + private String exceptionInfo; + + /** 开始时间 */ + private Date startTime; + + /** 停止时间 */ + private Date stopTime; + + public Long getJobLogId() + { + return jobLogId; + } + + public void setJobLogId(Long jobLogId) + { + this.jobLogId = jobLogId; + } + + public String getJobName() + { + return jobName; + } + + public void setJobName(String jobName) + { + this.jobName = jobName; + } + + public String getJobGroup() + { + return jobGroup; + } + + public void setJobGroup(String jobGroup) + { + this.jobGroup = jobGroup; + } + + public String getInvokeTarget() + { + return invokeTarget; + } + + public void setInvokeTarget(String invokeTarget) + { + this.invokeTarget = invokeTarget; + } + + public String getJobMessage() + { + return jobMessage; + } + + public void setJobMessage(String jobMessage) + { + this.jobMessage = jobMessage; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getExceptionInfo() + { + return exceptionInfo; + } + + public void setExceptionInfo(String exceptionInfo) + { + this.exceptionInfo = exceptionInfo; + } + + public Date getStartTime() + { + return startTime; + } + + public void setStartTime(Date startTime) + { + this.startTime = startTime; + } + + public Date getStopTime() + { + return stopTime; + } + + public void setStopTime(Date stopTime) + { + this.stopTime = stopTime; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("jobLogId", getJobLogId()) + .append("jobName", getJobName()) + .append("jobGroup", getJobGroup()) + .append("jobMessage", getJobMessage()) + .append("status", getStatus()) + .append("exceptionInfo", getExceptionInfo()) + .append("startTime", getStartTime()) + .append("stopTime", getStopTime()) + .toString(); + } +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/mapper/SysJobLogMapper.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/mapper/SysJobLogMapper.java new file mode 100644 index 0000000..7f52a23 --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/mapper/SysJobLogMapper.java @@ -0,0 +1,64 @@ +package com.boyue.quartz.mapper; + +import java.util.List; +import com.boyue.quartz.domain.SysJobLog; + +/** + * 调度任务日志信息 数据层 + * + * @author boyue + */ +public interface SysJobLogMapper +{ + /** + * 获取quartz调度器日志的计划任务 + * + * @param jobLog 调度日志信息 + * @return 调度任务日志集合 + */ + public List selectJobLogList(SysJobLog jobLog); + + /** + * 查询所有调度任务日志 + * + * @return 调度任务日志列表 + */ + public List selectJobLogAll(); + + /** + * 通过调度任务日志ID查询调度信息 + * + * @param jobLogId 调度任务日志ID + * @return 调度任务日志对象信息 + */ + public SysJobLog selectJobLogById(Long jobLogId); + + /** + * 新增任务日志 + * + * @param jobLog 调度日志信息 + * @return 结果 + */ + public int insertJobLog(SysJobLog jobLog); + + /** + * 批量删除调度日志信息 + * + * @param logIds 需要删除的数据ID + * @return 结果 + */ + public int deleteJobLogByIds(Long[] logIds); + + /** + * 删除任务日志 + * + * @param jobId 调度日志ID + * @return 结果 + */ + public int deleteJobLogById(Long jobId); + + /** + * 清空任务日志 + */ + public void cleanJobLog(); +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/mapper/SysJobMapper.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/mapper/SysJobMapper.java new file mode 100644 index 0000000..eb92dca --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/mapper/SysJobMapper.java @@ -0,0 +1,67 @@ +package com.boyue.quartz.mapper; + +import java.util.List; +import com.boyue.quartz.domain.SysJob; + +/** + * 调度任务信息 数据层 + * + * @author boyue + */ +public interface SysJobMapper +{ + /** + * 查询调度任务日志集合 + * + * @param job 调度信息 + * @return 操作日志集合 + */ + public List selectJobList(SysJob job); + + /** + * 查询所有调度任务 + * + * @return 调度任务列表 + */ + public List selectJobAll(); + + /** + * 通过调度ID查询调度任务信息 + * + * @param jobId 调度ID + * @return 角色对象信息 + */ + public SysJob selectJobById(Long jobId); + + /** + * 通过调度ID删除调度任务信息 + * + * @param jobId 调度ID + * @return 结果 + */ + public int deleteJobById(Long jobId); + + /** + * 批量删除调度任务信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteJobByIds(Long[] ids); + + /** + * 修改调度任务信息 + * + * @param job 调度任务信息 + * @return 结果 + */ + public int updateJob(SysJob job); + + /** + * 新增调度任务信息 + * + * @param job 调度任务信息 + * @return 结果 + */ + public int insertJob(SysJob job); +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/service/ISysJobLogService.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/service/ISysJobLogService.java new file mode 100644 index 0000000..e4431dc --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/service/ISysJobLogService.java @@ -0,0 +1,56 @@ +package com.boyue.quartz.service; + +import java.util.List; +import com.boyue.quartz.domain.SysJobLog; + +/** + * 定时任务调度日志信息信息 服务层 + * + * @author boyue + */ +public interface ISysJobLogService +{ + /** + * 获取quartz调度器日志的计划任务 + * + * @param jobLog 调度日志信息 + * @return 调度任务日志集合 + */ + public List selectJobLogList(SysJobLog jobLog); + + /** + * 通过调度任务日志ID查询调度信息 + * + * @param jobLogId 调度任务日志ID + * @return 调度任务日志对象信息 + */ + public SysJobLog selectJobLogById(Long jobLogId); + + /** + * 新增任务日志 + * + * @param jobLog 调度日志信息 + */ + public void addJobLog(SysJobLog jobLog); + + /** + * 批量删除调度日志信息 + * + * @param logIds 需要删除的日志ID + * @return 结果 + */ + public int deleteJobLogByIds(Long[] logIds); + + /** + * 删除任务日志 + * + * @param jobId 调度日志ID + * @return 结果 + */ + public int deleteJobLogById(Long jobId); + + /** + * 清空任务日志 + */ + public void cleanJobLog(); +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/service/ISysJobService.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/service/ISysJobService.java new file mode 100644 index 0000000..769efbf --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/service/ISysJobService.java @@ -0,0 +1,102 @@ +package com.boyue.quartz.service; + +import java.util.List; +import org.quartz.SchedulerException; +import com.boyue.common.exception.job.TaskException; +import com.boyue.quartz.domain.SysJob; + +/** + * 定时任务调度信息信息 服务层 + * + * @author boyue + */ +public interface ISysJobService +{ + /** + * 获取quartz调度器的计划任务 + * + * @param job 调度信息 + * @return 调度任务集合 + */ + public List selectJobList(SysJob job); + + /** + * 通过调度任务ID查询调度信息 + * + * @param jobId 调度任务ID + * @return 调度任务对象信息 + */ + public SysJob selectJobById(Long jobId); + + /** + * 暂停任务 + * + * @param job 调度信息 + * @return 结果 + */ + public int pauseJob(SysJob job) throws SchedulerException; + + /** + * 恢复任务 + * + * @param job 调度信息 + * @return 结果 + */ + public int resumeJob(SysJob job) throws SchedulerException; + + /** + * 删除任务后,所对应的trigger也将被删除 + * + * @param job 调度信息 + * @return 结果 + */ + public int deleteJob(SysJob job) throws SchedulerException; + + /** + * 批量删除调度信息 + * + * @param jobIds 需要删除的任务ID + * @return 结果 + */ + public void deleteJobByIds(Long[] jobIds) throws SchedulerException; + + /** + * 任务调度状态修改 + * + * @param job 调度信息 + * @return 结果 + */ + public int changeStatus(SysJob job) throws SchedulerException; + + /** + * 立即运行任务 + * + * @param job 调度信息 + * @return 结果 + */ + public boolean run(SysJob job) throws SchedulerException; + + /** + * 新增任务 + * + * @param job 调度信息 + * @return 结果 + */ + public int insertJob(SysJob job) throws SchedulerException, TaskException; + + /** + * 更新任务 + * + * @param job 调度信息 + * @return 结果 + */ + public int updateJob(SysJob job) throws SchedulerException, TaskException; + + /** + * 校验cron表达式是否有效 + * + * @param cronExpression 表达式 + * @return 结果 + */ + public boolean checkCronExpressionIsValid(String cronExpression); +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/service/impl/SysJobLogServiceImpl.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/service/impl/SysJobLogServiceImpl.java new file mode 100644 index 0000000..e3b8c13 --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/service/impl/SysJobLogServiceImpl.java @@ -0,0 +1,87 @@ +package com.boyue.quartz.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.boyue.quartz.domain.SysJobLog; +import com.boyue.quartz.mapper.SysJobLogMapper; +import com.boyue.quartz.service.ISysJobLogService; + +/** + * 定时任务调度日志信息 服务层 + * + * @author boyue + */ +@Service +public class SysJobLogServiceImpl implements ISysJobLogService +{ + @Autowired + private SysJobLogMapper jobLogMapper; + + /** + * 获取quartz调度器日志的计划任务 + * + * @param jobLog 调度日志信息 + * @return 调度任务日志集合 + */ + @Override + public List selectJobLogList(SysJobLog jobLog) + { + return jobLogMapper.selectJobLogList(jobLog); + } + + /** + * 通过调度任务日志ID查询调度信息 + * + * @param jobLogId 调度任务日志ID + * @return 调度任务日志对象信息 + */ + @Override + public SysJobLog selectJobLogById(Long jobLogId) + { + return jobLogMapper.selectJobLogById(jobLogId); + } + + /** + * 新增任务日志 + * + * @param jobLog 调度日志信息 + */ + @Override + public void addJobLog(SysJobLog jobLog) + { + jobLogMapper.insertJobLog(jobLog); + } + + /** + * 批量删除调度日志信息 + * + * @param logIds 需要删除的数据ID + * @return 结果 + */ + @Override + public int deleteJobLogByIds(Long[] logIds) + { + return jobLogMapper.deleteJobLogByIds(logIds); + } + + /** + * 删除任务日志 + * + * @param jobId 调度日志ID + */ + @Override + public int deleteJobLogById(Long jobId) + { + return jobLogMapper.deleteJobLogById(jobId); + } + + /** + * 清空任务日志 + */ + @Override + public void cleanJobLog() + { + jobLogMapper.cleanJobLog(); + } +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/service/impl/SysJobServiceImpl.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/service/impl/SysJobServiceImpl.java new file mode 100644 index 0000000..7c5df63 --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/service/impl/SysJobServiceImpl.java @@ -0,0 +1,261 @@ +package com.boyue.quartz.service.impl; + +import java.util.List; +import jakarta.annotation.PostConstruct; +import org.quartz.JobDataMap; +import org.quartz.JobKey; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import com.boyue.common.constant.ScheduleConstants; +import com.boyue.common.exception.job.TaskException; +import com.boyue.quartz.domain.SysJob; +import com.boyue.quartz.mapper.SysJobMapper; +import com.boyue.quartz.service.ISysJobService; +import com.boyue.quartz.util.CronUtils; +import com.boyue.quartz.util.ScheduleUtils; + +/** + * 定时任务调度信息 服务层 + * + * @author boyue + */ +@Service +public class SysJobServiceImpl implements ISysJobService +{ + @Autowired + private Scheduler scheduler; + + @Autowired + private SysJobMapper jobMapper; + + /** + * 项目启动时,初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据) + */ + @PostConstruct + public void init() throws SchedulerException, TaskException + { + scheduler.clear(); + List jobList = jobMapper.selectJobAll(); + for (SysJob job : jobList) + { + ScheduleUtils.createScheduleJob(scheduler, job); + } + } + + /** + * 获取quartz调度器的计划任务列表 + * + * @param job 调度信息 + * @return + */ + @Override + public List selectJobList(SysJob job) + { + return jobMapper.selectJobList(job); + } + + /** + * 通过调度任务ID查询调度信息 + * + * @param jobId 调度任务ID + * @return 调度任务对象信息 + */ + @Override + public SysJob selectJobById(Long jobId) + { + return jobMapper.selectJobById(jobId); + } + + /** + * 暂停任务 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int pauseJob(SysJob job) throws SchedulerException + { + Long jobId = job.getJobId(); + String jobGroup = job.getJobGroup(); + job.setStatus(ScheduleConstants.Status.PAUSE.getValue()); + int rows = jobMapper.updateJob(job); + if (rows > 0) + { + scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup)); + } + return rows; + } + + /** + * 恢复任务 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int resumeJob(SysJob job) throws SchedulerException + { + Long jobId = job.getJobId(); + String jobGroup = job.getJobGroup(); + job.setStatus(ScheduleConstants.Status.NORMAL.getValue()); + int rows = jobMapper.updateJob(job); + if (rows > 0) + { + scheduler.resumeJob(ScheduleUtils.getJobKey(jobId, jobGroup)); + } + return rows; + } + + /** + * 删除任务后,所对应的trigger也将被删除 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteJob(SysJob job) throws SchedulerException + { + Long jobId = job.getJobId(); + String jobGroup = job.getJobGroup(); + int rows = jobMapper.deleteJobById(jobId); + if (rows > 0) + { + scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, jobGroup)); + } + return rows; + } + + /** + * 批量删除调度信息 + * + * @param jobIds 需要删除的任务ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteJobByIds(Long[] jobIds) throws SchedulerException + { + for (Long jobId : jobIds) + { + SysJob job = jobMapper.selectJobById(jobId); + deleteJob(job); + } + } + + /** + * 任务调度状态修改 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int changeStatus(SysJob job) throws SchedulerException + { + int rows = 0; + String status = job.getStatus(); + if (ScheduleConstants.Status.NORMAL.getValue().equals(status)) + { + rows = resumeJob(job); + } + else if (ScheduleConstants.Status.PAUSE.getValue().equals(status)) + { + rows = pauseJob(job); + } + return rows; + } + + /** + * 立即运行任务 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean run(SysJob job) throws SchedulerException + { + boolean result = false; + Long jobId = job.getJobId(); + String jobGroup = job.getJobGroup(); + SysJob properties = selectJobById(job.getJobId()); + // 参数 + JobDataMap dataMap = new JobDataMap(); + dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties); + JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup); + if (scheduler.checkExists(jobKey)) + { + result = true; + scheduler.triggerJob(jobKey, dataMap); + } + return result; + } + + /** + * 新增任务 + * + * @param job 调度信息 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int insertJob(SysJob job) throws SchedulerException, TaskException + { + job.setStatus(ScheduleConstants.Status.PAUSE.getValue()); + int rows = jobMapper.insertJob(job); + if (rows > 0) + { + ScheduleUtils.createScheduleJob(scheduler, job); + } + return rows; + } + + /** + * 更新任务的时间表达式 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int updateJob(SysJob job) throws SchedulerException, TaskException + { + SysJob properties = selectJobById(job.getJobId()); + int rows = jobMapper.updateJob(job); + if (rows > 0) + { + updateSchedulerJob(job, properties.getJobGroup()); + } + return rows; + } + + /** + * 更新任务 + * + * @param job 任务对象 + * @param jobGroup 任务组名 + */ + public void updateSchedulerJob(SysJob job, String jobGroup) throws SchedulerException, TaskException + { + Long jobId = job.getJobId(); + // 判断是否存在 + JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup); + if (scheduler.checkExists(jobKey)) + { + // 防止创建时存在数据问题 先移除,然后在执行创建操作 + scheduler.deleteJob(jobKey); + } + ScheduleUtils.createScheduleJob(scheduler, job); + } + + /** + * 校验cron表达式是否有效 + * + * @param cronExpression 表达式 + * @return 结果 + */ + @Override + public boolean checkCronExpressionIsValid(String cronExpression) + { + return CronUtils.isValid(cronExpression); + } +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/task/RyTask.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/task/RyTask.java new file mode 100644 index 0000000..f874312 --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/task/RyTask.java @@ -0,0 +1,28 @@ +package com.boyue.quartz.task; + +import org.springframework.stereotype.Component; +import com.boyue.common.utils.StringUtils; + +/** + * 定时任务调度测试 + * + * @author boyue + */ +@Component("ryTask") +public class RyTask +{ + public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i) + { + System.out.println(StringUtils.format("执行多参方法: 字符串类型{},布尔类型{},长整型{},浮点型{},整形{}", s, b, l, d, i)); + } + + public void ryParams(String params) + { + System.out.println("执行有参方法:" + params); + } + + public void ryNoParams() + { + System.out.println("执行无参方法"); + } +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/AbstractQuartzJob.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/AbstractQuartzJob.java new file mode 100644 index 0000000..6d8fd05 --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/AbstractQuartzJob.java @@ -0,0 +1,107 @@ +package com.boyue.quartz.util; + +import java.util.Date; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.boyue.common.constant.Constants; +import com.boyue.common.constant.ScheduleConstants; +import com.boyue.common.utils.ExceptionUtil; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.bean.BeanUtils; +import com.boyue.common.utils.spring.SpringUtils; +import com.boyue.quartz.domain.SysJob; +import com.boyue.quartz.domain.SysJobLog; +import com.boyue.quartz.service.ISysJobLogService; + +/** + * 抽象quartz调用 + * + * @author boyue + */ +public abstract class AbstractQuartzJob implements Job +{ + private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class); + + /** + * 线程本地变量 + */ + private static ThreadLocal threadLocal = new ThreadLocal<>(); + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException + { + SysJob sysJob = new SysJob(); + BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES)); + try + { + before(context, sysJob); + if (sysJob != null) + { + doExecute(context, sysJob); + } + after(context, sysJob, null); + } + catch (Exception e) + { + log.error("任务执行异常 - :", e); + after(context, sysJob, e); + } + } + + /** + * 执行前 + * + * @param context 工作执行上下文对象 + * @param sysJob 系统计划任务 + */ + protected void before(JobExecutionContext context, SysJob sysJob) + { + threadLocal.set(new Date()); + } + + /** + * 执行后 + * + * @param context 工作执行上下文对象 + * @param sysJob 系统计划任务 + */ + protected void after(JobExecutionContext context, SysJob sysJob, Exception e) + { + Date startTime = threadLocal.get(); + threadLocal.remove(); + + final SysJobLog sysJobLog = new SysJobLog(); + sysJobLog.setJobName(sysJob.getJobName()); + sysJobLog.setJobGroup(sysJob.getJobGroup()); + sysJobLog.setInvokeTarget(sysJob.getInvokeTarget()); + sysJobLog.setStartTime(startTime); + sysJobLog.setStopTime(new Date()); + long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime(); + sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒"); + if (e != null) + { + sysJobLog.setStatus(Constants.FAIL); + String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000); + sysJobLog.setExceptionInfo(errorMsg); + } + else + { + sysJobLog.setStatus(Constants.SUCCESS); + } + + // 写入数据库当中 + SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog); + } + + /** + * 执行方法,由子类重载 + * + * @param context 工作执行上下文对象 + * @param sysJob 系统计划任务 + * @throws Exception 执行过程中的异常 + */ + protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception; +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/CronUtils.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/CronUtils.java new file mode 100644 index 0000000..71f6bc4 --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/CronUtils.java @@ -0,0 +1,63 @@ +package com.boyue.quartz.util; + +import java.text.ParseException; +import java.util.Date; +import org.quartz.CronExpression; + +/** + * cron表达式工具类 + * + * @author boyue + * + */ +public class CronUtils +{ + /** + * 返回一个布尔值代表一个给定的Cron表达式的有效性 + * + * @param cronExpression Cron表达式 + * @return boolean 表达式是否有效 + */ + public static boolean isValid(String cronExpression) + { + return CronExpression.isValidExpression(cronExpression); + } + + /** + * 返回一个字符串值,表示该消息无效Cron表达式给出有效性 + * + * @param cronExpression Cron表达式 + * @return String 无效时返回表达式错误描述,如果有效返回null + */ + public static String getInvalidMessage(String cronExpression) + { + try + { + new CronExpression(cronExpression); + return null; + } + catch (ParseException pe) + { + return pe.getMessage(); + } + } + + /** + * 返回下一个执行时间根据给定的Cron表达式 + * + * @param cronExpression Cron表达式 + * @return Date 下次Cron表达式执行时间 + */ + public static Date getNextExecution(String cronExpression) + { + try + { + CronExpression cron = new CronExpression(cronExpression); + return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis())); + } + catch (ParseException e) + { + throw new IllegalArgumentException(e.getMessage()); + } + } +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/JobInvokeUtil.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/JobInvokeUtil.java new file mode 100644 index 0000000..e26c3b5 --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/JobInvokeUtil.java @@ -0,0 +1,182 @@ +package com.boyue.quartz.util; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.spring.SpringUtils; +import com.boyue.quartz.domain.SysJob; + +/** + * 任务执行工具 + * + * @author boyue + */ +public class JobInvokeUtil +{ + /** + * 执行方法 + * + * @param sysJob 系统任务 + */ + public static void invokeMethod(SysJob sysJob) throws Exception + { + String invokeTarget = sysJob.getInvokeTarget(); + String beanName = getBeanName(invokeTarget); + String methodName = getMethodName(invokeTarget); + List methodParams = getMethodParams(invokeTarget); + + if (!isValidClassName(beanName)) + { + Object bean = SpringUtils.getBean(beanName); + invokeMethod(bean, methodName, methodParams); + } + else + { + Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance(); + invokeMethod(bean, methodName, methodParams); + } + } + + /** + * 调用任务方法 + * + * @param bean 目标对象 + * @param methodName 方法名称 + * @param methodParams 方法参数 + */ + private static void invokeMethod(Object bean, String methodName, List methodParams) + throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, + InvocationTargetException + { + if (StringUtils.isNotNull(methodParams) && methodParams.size() > 0) + { + Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams)); + method.invoke(bean, getMethodParamsValue(methodParams)); + } + else + { + Method method = bean.getClass().getMethod(methodName); + method.invoke(bean); + } + } + + /** + * 校验是否为为class包名 + * + * @param invokeTarget 名称 + * @return true是 false否 + */ + public static boolean isValidClassName(String invokeTarget) + { + return StringUtils.countMatches(invokeTarget, ".") > 1; + } + + /** + * 获取bean名称 + * + * @param invokeTarget 目标字符串 + * @return bean名称 + */ + public static String getBeanName(String invokeTarget) + { + String beanName = StringUtils.substringBefore(invokeTarget, "("); + return StringUtils.substringBeforeLast(beanName, "."); + } + + /** + * 获取bean方法 + * + * @param invokeTarget 目标字符串 + * @return method方法 + */ + public static String getMethodName(String invokeTarget) + { + String methodName = StringUtils.substringBefore(invokeTarget, "("); + return StringUtils.substringAfterLast(methodName, "."); + } + + /** + * 获取method方法参数相关列表 + * + * @param invokeTarget 目标字符串 + * @return method方法相关参数列表 + */ + public static List getMethodParams(String invokeTarget) + { + String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")"); + if (StringUtils.isEmpty(methodStr)) + { + return null; + } + String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)"); + List classs = new LinkedList<>(); + for (int i = 0; i < methodParams.length; i++) + { + String str = StringUtils.trimToEmpty(methodParams[i]); + // String字符串类型,以'或"开头 + if (StringUtils.startsWithAny(str, "'", "\"")) + { + classs.add(new Object[] { StringUtils.substring(str, 1, str.length() - 1), String.class }); + } + // boolean布尔类型,等于true或者false + else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)) + { + classs.add(new Object[] { Boolean.valueOf(str), Boolean.class }); + } + // long长整形,以L结尾 + else if (StringUtils.endsWith(str, "L")) + { + classs.add(new Object[] { Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class }); + } + // double浮点类型,以D结尾 + else if (StringUtils.endsWith(str, "D")) + { + classs.add(new Object[] { Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class }); + } + // 其他类型归类为整形 + else + { + classs.add(new Object[] { Integer.valueOf(str), Integer.class }); + } + } + return classs; + } + + /** + * 获取参数类型 + * + * @param methodParams 参数相关列表 + * @return 参数类型列表 + */ + public static Class[] getMethodParamsType(List methodParams) + { + Class[] classs = new Class[methodParams.size()]; + int index = 0; + for (Object[] os : methodParams) + { + classs[index] = (Class) os[1]; + index++; + } + return classs; + } + + /** + * 获取参数值 + * + * @param methodParams 参数相关列表 + * @return 参数值列表 + */ + public static Object[] getMethodParamsValue(List methodParams) + { + Object[] classs = new Object[methodParams.size()]; + int index = 0; + for (Object[] os : methodParams) + { + classs[index] = (Object) os[0]; + index++; + } + return classs; + } +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/QuartzDisallowConcurrentExecution.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/QuartzDisallowConcurrentExecution.java new file mode 100644 index 0000000..b3db63d --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/QuartzDisallowConcurrentExecution.java @@ -0,0 +1,21 @@ +package com.boyue.quartz.util; + +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; +import com.boyue.quartz.domain.SysJob; + +/** + * 定时任务处理(禁止并发执行) + * + * @author boyue + * + */ +@DisallowConcurrentExecution +public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob +{ + @Override + protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception + { + JobInvokeUtil.invokeMethod(sysJob); + } +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/QuartzJobExecution.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/QuartzJobExecution.java new file mode 100644 index 0000000..9c4e7ed --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/QuartzJobExecution.java @@ -0,0 +1,19 @@ +package com.boyue.quartz.util; + +import org.quartz.JobExecutionContext; +import com.boyue.quartz.domain.SysJob; + +/** + * 定时任务处理(允许并发执行) + * + * @author boyue + * + */ +public class QuartzJobExecution extends AbstractQuartzJob +{ + @Override + protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception + { + JobInvokeUtil.invokeMethod(sysJob); + } +} diff --git a/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/ScheduleUtils.java b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/ScheduleUtils.java new file mode 100644 index 0000000..f52c9b9 --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/java/com/boyue/quartz/util/ScheduleUtils.java @@ -0,0 +1,141 @@ +package com.boyue.quartz.util; + +import org.quartz.CronScheduleBuilder; +import org.quartz.CronTrigger; +import org.quartz.Job; +import org.quartz.JobBuilder; +import org.quartz.JobDetail; +import org.quartz.JobKey; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.TriggerBuilder; +import org.quartz.TriggerKey; +import com.boyue.common.constant.Constants; +import com.boyue.common.constant.ScheduleConstants; +import com.boyue.common.exception.job.TaskException; +import com.boyue.common.exception.job.TaskException.Code; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.spring.SpringUtils; +import com.boyue.quartz.domain.SysJob; + +/** + * 定时任务工具类 + * + * @author boyue + * + */ +public class ScheduleUtils +{ + /** + * 得到quartz任务类 + * + * @param sysJob 执行计划 + * @return 具体执行任务类 + */ + private static Class getQuartzJobClass(SysJob sysJob) + { + boolean isConcurrent = "0".equals(sysJob.getConcurrent()); + return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class; + } + + /** + * 构建任务触发对象 + */ + public static TriggerKey getTriggerKey(Long jobId, String jobGroup) + { + return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup); + } + + /** + * 构建任务键对象 + */ + public static JobKey getJobKey(Long jobId, String jobGroup) + { + return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup); + } + + /** + * 创建定时任务 + */ + public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException + { + Class jobClass = getQuartzJobClass(job); + // 构建job信息 + Long jobId = job.getJobId(); + String jobGroup = job.getJobGroup(); + JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build(); + + // 表达式调度构建器 + CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression()); + cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder); + + // 按新的cronExpression表达式构建一个新的trigger + CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup)) + .withSchedule(cronScheduleBuilder).build(); + + // 放入参数,运行时的方法可以获取 + jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job); + + // 判断是否存在 + if (scheduler.checkExists(getJobKey(jobId, jobGroup))) + { + // 防止创建时存在数据问题 先移除,然后在执行创建操作 + scheduler.deleteJob(getJobKey(jobId, jobGroup)); + } + + // 判断任务是否过期 + if (StringUtils.isNotNull(CronUtils.getNextExecution(job.getCronExpression()))) + { + // 执行调度任务 + scheduler.scheduleJob(jobDetail, trigger); + } + + // 暂停任务 + if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) + { + scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup)); + } + } + + /** + * 设置定时任务策略 + */ + public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb) + throws TaskException + { + switch (job.getMisfirePolicy()) + { + case ScheduleConstants.MISFIRE_DEFAULT: + return cb; + case ScheduleConstants.MISFIRE_IGNORE_MISFIRES: + return cb.withMisfireHandlingInstructionIgnoreMisfires(); + case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED: + return cb.withMisfireHandlingInstructionFireAndProceed(); + case ScheduleConstants.MISFIRE_DO_NOTHING: + return cb.withMisfireHandlingInstructionDoNothing(); + default: + throw new TaskException("The task misfire policy '" + job.getMisfirePolicy() + + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR); + } + } + + /** + * 检查包名是否为白名单配置 + * + * @param invokeTarget 目标字符串 + * @return 结果 + */ + public static boolean whiteList(String invokeTarget) + { + String packageName = StringUtils.substringBefore(invokeTarget, "("); + int count = StringUtils.countMatches(packageName, "."); + if (count > 1) + { + return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR); + } + Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]); + String beanPackageName = obj.getClass().getPackage().getName(); + return StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_WHITELIST_STR) + && !StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_ERROR_STR); + } +} diff --git a/boyue-models/boyue-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml b/boyue-models/boyue-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml new file mode 100644 index 0000000..859d777 --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + select job_log_id, job_name, job_group, invoke_target, job_message, status, exception_info, create_time + from sys_job_log + + + + + + + + + + delete from sys_job_log where job_log_id = #{jobLogId} + + + + delete from sys_job_log where job_log_id in + + #{jobLogId} + + + + + truncate table sys_job_log + + + + insert into sys_job_log( + job_log_id, + job_name, + job_group, + invoke_target, + job_message, + status, + exception_info, + create_time + )values( + #{jobLogId}, + #{jobName}, + #{jobGroup}, + #{invokeTarget}, + #{jobMessage}, + #{status}, + #{exceptionInfo}, + sysdate() + ) + + + \ No newline at end of file diff --git a/boyue-models/boyue-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml b/boyue-models/boyue-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml new file mode 100644 index 0000000..2870a77 --- /dev/null +++ b/boyue-models/boyue-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + select job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark + from sys_job + + + + + + + + + + delete from sys_job where job_id = #{jobId} + + + + delete from sys_job where job_id in + + #{jobId} + + + + + update sys_job + + job_name = #{jobName}, + job_group = #{jobGroup}, + invoke_target = #{invokeTarget}, + cron_expression = #{cronExpression}, + misfire_policy = #{misfirePolicy}, + concurrent = #{concurrent}, + status = #{status}, + remark = #{remark}, + update_by = #{updateBy}, + update_time = sysdate() + + where job_id = #{jobId} + + + + insert into sys_job( + job_id, + job_name, + job_group, + invoke_target, + cron_expression, + misfire_policy, + concurrent, + status, + remark, + create_by, + create_time + )values( + #{jobId}, + #{jobName}, + #{jobGroup}, + #{invokeTarget}, + #{cronExpression}, + #{misfirePolicy}, + #{concurrent}, + #{status}, + #{remark}, + #{createBy}, + sysdate() + ) + + + \ No newline at end of file diff --git a/boyue-models/pom.xml b/boyue-models/pom.xml new file mode 100644 index 0000000..4cea8d1 --- /dev/null +++ b/boyue-models/pom.xml @@ -0,0 +1,97 @@ + + + + boyuehasfj-java + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-models + + + 中间件 + + + + + + + com.boyue + boyue-quartz + ${boyue.version} + + + + + com.boyue + boyue-generator + ${boyue.version} + + + + + com.boyue + boyue-online + ${boyue.version} + + + + + com.boyue + boyue-message + ${boyue.version} + + + + + com.boyue + boyue-form + ${boyue.version} + + + + + com.boyue + boyue-flowable + ${boyue.version} + + + + + com.boyue + boyue-tfa-phone + ${boyue.version} + + + + + com.boyue + boyue-tfa-email + ${boyue.version} + + + + + com.boyue + boyue-hasfj + ${boyue.version} + + + + + + + + boyue-models-starter + boyue-generator + boyue-quartz + boyue-online + boyue-message + boyue-form + boyue-flowable + boyue-hasfj + + pom + \ No newline at end of file diff --git a/boyue-pay/boyue-pay-alipay/pom.xml b/boyue-pay/boyue-pay-alipay/pom.xml new file mode 100644 index 0000000..b08c6cb --- /dev/null +++ b/boyue-pay/boyue-pay-alipay/pom.xml @@ -0,0 +1,31 @@ + + + + boyue-pay + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-pay-alipay + + + 支付宝支付模块 + + + + + + com.boyue + boyue-pay-common + + + + com.alipay.sdk + alipay-easysdk + + + + + \ No newline at end of file diff --git a/boyue-pay/boyue-pay-alipay/src/main/java/com/boyue/pay/alipay/config/AliPayConfig.java b/boyue-pay/boyue-pay-alipay/src/main/java/com/boyue/pay/alipay/config/AliPayConfig.java new file mode 100644 index 0000000..d2a7f80 --- /dev/null +++ b/boyue-pay/boyue-pay-alipay/src/main/java/com/boyue/pay/alipay/config/AliPayConfig.java @@ -0,0 +1,80 @@ +package com.boyue.pay.alipay.config; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.Resource; + +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.kernel.Config; + +/** + * @author zlh + */ +@Configuration +@ConditionalOnProperty(prefix = "pay.alipay", name = "enabled", havingValue = "true") +public class AliPayConfig { + @Value("${pay.alipay.appId}") + private String appId; + @Value("${pay.alipay.notifyUrl}") + private String notifyUrl; + @Value("${pay.alipay.appPrivateKey}") + private String appPrivateKey; + @Value("${pay.alipay.alipayPublicKey}") + private String alipayPublicKey; + + @Autowired + private ApplicationContext applicationContext; + + private String getAppPrivateKey() throws Exception { + if (appPrivateKey.startsWith("classpath")) { + Resource resource = applicationContext.getResource(appPrivateKey); + InputStream inputStream = resource.getInputStream(); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + String appPrivateKeyValue = bufferedReader.lines().collect(Collectors.joining(System.lineSeparator())); + bufferedReader.close(); + appPrivateKey = appPrivateKeyValue; + } + return appPrivateKey; + } + + private String getAlipayPublicKey() throws Exception { + if (alipayPublicKey.startsWith("classpath")) { + Resource resource = applicationContext.getResource(alipayPublicKey); + InputStream inputStream = resource.getInputStream(); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + String alipayPublicKeyValue = bufferedReader.lines().collect(Collectors.joining(System.lineSeparator())); + bufferedReader.close(); + alipayPublicKey = alipayPublicKeyValue; + } + return alipayPublicKey; + + } + + @Bean + protected Config alipayBaseConfig() throws Exception { + // 设置参数(全局只需设置一次) + Config config = new Config(); + config.protocol = "https"; + config.gatewayHost = "openapi.alipay.com";// openapi-sandbox.dl.alipaydev.com||openapi.alipay.com + config.signType = "RSA2"; + config.appId = this.appId; + config.merchantPrivateKey = getAppPrivateKey(); + config.alipayPublicKey = getAlipayPublicKey(); + System.out.println(getAlipayPublicKey()); + config.notifyUrl = this.notifyUrl; + Factory.setOptions(config); + return config; + } + +} + +// https://openapi-sandbox.dl.alipaydev.com/gateway.do \ No newline at end of file diff --git a/boyue-pay/boyue-pay-alipay/src/main/java/com/boyue/pay/alipay/service/IAliPayService.java b/boyue-pay/boyue-pay-alipay/src/main/java/com/boyue/pay/alipay/service/IAliPayService.java new file mode 100644 index 0000000..5d38682 --- /dev/null +++ b/boyue-pay/boyue-pay-alipay/src/main/java/com/boyue/pay/alipay/service/IAliPayService.java @@ -0,0 +1,9 @@ +package com.boyue.pay.alipay.service; + +import java.util.Map; + +import com.boyue.pay.service.PayService; + +public interface IAliPayService extends PayService { + public void callback(Map params); +} diff --git a/boyue-pay/boyue-pay-alipay/src/main/java/com/boyue/pay/alipay/service/Impl/AliPayService.java b/boyue-pay/boyue-pay-alipay/src/main/java/com/boyue/pay/alipay/service/Impl/AliPayService.java new file mode 100644 index 0000000..396eb89 --- /dev/null +++ b/boyue-pay/boyue-pay-alipay/src/main/java/com/boyue/pay/alipay/service/Impl/AliPayService.java @@ -0,0 +1,126 @@ +package com.boyue.pay.alipay.service.Impl; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; + +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse; +import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse; +import com.boyue.common.exception.ServiceException; +import com.boyue.pay.alipay.service.IAliPayService; +import com.boyue.pay.domain.PayOrder; +import com.boyue.pay.service.IPayOrderService; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Service("pay:service:alipay") +@ConditionalOnProperty(prefix = "pay.alipay", name = "enabled", havingValue = "true") +public class AliPayService implements IAliPayService { + public void callback(Map params) { + } + + @Autowired + private IPayOrderService payOrderService; + + public String payUrl(PayOrder payOrder) { + + try { + AlipayTradePagePayResponse response = Factory.Payment.Page().pay( + payOrder.getOrderContent(), + payOrder.getOrderNumber(), + payOrder.getActualAmount(), + ""); + return response.getBody(); + } catch (Exception e) { + throw new ServiceException("创建支付宝支付URL失败"); + } + } + + @Override + public String notify(HttpServletRequest request, HttpServletResponse response) { + if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) { + + Map params = new HashMap<>(); + Map requestParams = request.getParameterMap(); + for (String name : requestParams.keySet()) { + params.put(name, request.getParameter(name)); + } + String orderNumber = params.get("out_trade_no"); + try { + if (Factory.Payment.Common().verifyNotify(params)) { + payOrderService.updateStatus(orderNumber, "已支付"); + } + return "success"; + } catch (Exception e) { + e.printStackTrace(); + } + } + return "fail"; + } + + @Override + public PayOrder query(PayOrder payOrder) { + try { + // 使用支付宝SDK查询订单状态 + com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse response = Factory.Payment.Common() + .query(payOrder.getOrderNumber()); + + // 根据查询结果更新订单状态 + if ("10000".equals(response.code)) { + String tradeStatus = response.tradeStatus; + String orderStatus = ""; + + // 根据支付宝交易状态映射到系统订单状态 + switch (tradeStatus) { + case "TRADE_SUCCESS": + case "TRADE_FINISHED": + orderStatus = "已支付"; + break; + case "WAIT_BUYER_PAY": + orderStatus = "待支付"; + break; + case "TRADE_CLOSED": + orderStatus = "已关闭"; + break; + default: + orderStatus = "未知状态"; + } + + // 更新订单信息 + payOrderService.updateStatus(payOrder.getOrderNumber(), orderStatus); + } else { + throw new ServiceException("查询支付宝订单失败:" + response.subMsg); + } + + return payOrder; + } catch (Exception e) { + throw new ServiceException("查询支付宝订单异常:" + e.getMessage()); + } + } + + @Override + public PayOrder refund(PayOrder payOrder) { + try { + // 使用支付宝SDK进行退款 + AlipayTradeRefundResponse response = Factory.Payment.Common().refund( + payOrder.getOrderNumber(), + payOrder.getActualAmount()); + + // 处理退款结果 + if ("10000".equals(response.code)) { + payOrderService.updateStatus(payOrder.getOrderNumber(), "已退款"); + } else { + throw new ServiceException("支付宝退款失败:" + response.subMsg); + } + + return payOrder; + } catch (Exception e) { + throw new ServiceException("支付宝退款异常:" + e.getMessage()); + } + } +} diff --git a/boyue-pay/boyue-pay-alipay/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/boyue-pay/boyue-pay-alipay/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000..9d3fbe3 --- /dev/null +++ b/boyue-pay/boyue-pay-alipay/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,29 @@ +{ + "properties": [ + { + "name": "pay.alipay.enabled", + "type": "java.lang.Boolean", + "description": "是否启用支付宝支付" + }, + { + "name": "pay.alipay.appId", + "type": "java.lang.String", + "description": "支付宝appid" + }, + { + "name": "pay.alipay.appPrivateKey", + "type": "java.lang.String", + "description": "支付宝应用私钥,可以直接用字符串,也可以是基于classpath的文件路径" + }, + { + "name": "pay.alipay.alipayPublicKey", + "type": "java.lang.String", + "description": "支付宝应用公钥,可以直接用字符串,也可以是基于classpath的文件路径" + }, + { + "name": "pay.alipay.notifyUrl", + "type": "java.lang.String", + "description": "支付宝支付回调地址" + } + ] +} \ No newline at end of file diff --git a/boyue-pay/boyue-pay-common/pom.xml b/boyue-pay/boyue-pay-common/pom.xml new file mode 100644 index 0000000..5dc0f07 --- /dev/null +++ b/boyue-pay/boyue-pay-common/pom.xml @@ -0,0 +1,28 @@ + + + + boyue-pay + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-pay-common + + + 支付基础模块 + + + + + + + com.boyue + boyue-common + + + + + \ No newline at end of file diff --git a/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/domain/PayInvoice.java b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/domain/PayInvoice.java new file mode 100644 index 0000000..87174ff --- /dev/null +++ b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/domain/PayInvoice.java @@ -0,0 +1,168 @@ +package com.boyue.pay.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 发票对象 pay_invoice + * + * @author boyue + * @date 2024-06-11 + */ +@Schema(description = "发票对象") +public class PayInvoice extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + + /** 发票id */ + @Schema(title = "发票id") + private Long invoiceId; + + /** 订单号 */ + @Schema(title = "订单号") + @Excel(name = "订单号") + private String orderNumber; + + /** 发票类型 */ + @Schema(title = "发票类型") + @Excel(name = "发票类型") + private String invoiceType; + + /** 发票抬头 */ + @Schema(title = "发票抬头") + @Excel(name = "发票抬头") + private String invoiceHeader; + + /** 纳税人识别号 */ + @Schema(title = "纳税人识别号") + @Excel(name = "纳税人识别号") + private String invoiceNumber; + + /** 收票人手机号 */ + @Schema(title = "收票人手机号") + @Excel(name = "收票人手机号") + private String invoicePhone; + + /** 收票人邮箱 */ + @Schema(title = "收票人邮箱") + @Excel(name = "收票人邮箱") + private String invoiceEmail; + + /** 发票备注 */ + @Schema(title = "发票备注") + @Excel(name = "发票备注") + private String invoiceRemark; + public void setInvoiceId(Long invoiceId) + { + this.invoiceId = invoiceId; + } + + public Long getInvoiceId() + { + return invoiceId; + } + + + public void setOrderNumber(String orderNumber) + { + this.orderNumber = orderNumber; + } + + public String getOrderNumber() + { + return orderNumber; + } + + + public void setInvoiceType(String invoiceType) + { + this.invoiceType = invoiceType; + } + + public String getInvoiceType() + { + return invoiceType; + } + + + public void setInvoiceHeader(String invoiceHeader) + { + this.invoiceHeader = invoiceHeader; + } + + public String getInvoiceHeader() + { + return invoiceHeader; + } + + + public void setInvoiceNumber(String invoiceNumber) + { + this.invoiceNumber = invoiceNumber; + } + + public String getInvoiceNumber() + { + return invoiceNumber; + } + + + public void setInvoicePhone(String invoicePhone) + { + this.invoicePhone = invoicePhone; + } + + public String getInvoicePhone() + { + return invoicePhone; + } + + + public void setInvoiceEmail(String invoiceEmail) + { + this.invoiceEmail = invoiceEmail; + } + + public String getInvoiceEmail() + { + return invoiceEmail; + } + + + public void setInvoiceRemark(String invoiceRemark) + { + this.invoiceRemark = invoiceRemark; + } + + public String getInvoiceRemark() + { + return invoiceRemark; + } + + + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("invoiceId", getInvoiceId()) + .append("orderNumber", getOrderNumber()) + .append("invoiceType", getInvoiceType()) + .append("invoiceHeader", getInvoiceHeader()) + .append("invoiceNumber", getInvoiceNumber()) + .append("invoicePhone", getInvoicePhone()) + .append("invoiceEmail", getInvoiceEmail()) + .append("invoiceRemark", getInvoiceRemark()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/domain/PayOrder.java b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/domain/PayOrder.java new file mode 100644 index 0000000..4de2ec4 --- /dev/null +++ b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/domain/PayOrder.java @@ -0,0 +1,141 @@ +package com.boyue.pay.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 订单对象 pay_order + * + * @author boyue + * @date 2024-06-11 + */ +@Schema(description = "订单对象") +public class PayOrder extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** 订单ID */ + @Schema(title = "订单ID") + private Long orderId; + + /** 订单号 */ + @Schema(title = "商户订单号") + @Excel(name = "商户订单号") + private String orderNumber; + + /** 第三方订单号 */ + @Schema(title = "第三方订单号") + @Excel(name = "第三方订单号") + private String thirdNumber; + + /** 订单状态 */ + @Schema(title = "订单状态") + @Excel(name = "订单状态") + private String orderStatus; + + /** 订单总金额 */ + @Schema(title = "订单总金额") + @Excel(name = "订单总金额") + private String totalAmount; + + /** 实际支付金额 */ + @Schema(title = "实际支付金额") + @Excel(name = "实际支付金额") + private String actualAmount; + + /** 订单内容 */ + @Schema(title = "订单内容") + @Excel(name = "订单内容") + private String orderContent; + + /** 负载信息 */ + @Schema(title = "负载信息") + @Excel(name = "负载信息") + private String orderMessage; + + public void setOrderId(Long orderId) { + this.orderId = orderId; + } + + public Long getOrderId() { + return orderId; + } + + public void setOrderNumber(String orderNumber) { + this.orderNumber = orderNumber; + } + + public String getOrderNumber() { + return orderNumber; + } + + public void setThirdNumber(String thirdNumber) { + this.thirdNumber = thirdNumber; + } + + public String getThirdNumber() { + return thirdNumber; + } + + public void setOrderStatus(String orderStatus) { + this.orderStatus = orderStatus; + } + + public String getOrderStatus() { + return orderStatus; + } + + public void setTotalAmount(String totalAmount) { + this.totalAmount = totalAmount; + } + + public String getTotalAmount() { + return totalAmount; + } + + public void setActualAmount(String actualAmount) { + this.actualAmount = actualAmount; + } + + public String getActualAmount() { + return actualAmount; + } + + public void setOrderContent(String orderContent) { + this.orderContent = orderContent; + } + + public String getOrderContent() { + return orderContent; + } + + public void setOrderMessage(String orderMessage) { + this.orderMessage = orderMessage; + } + + public String getOrderMessage() { + return orderMessage; + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("orderId", getOrderId()) + .append("orderNumber", getOrderNumber()) + .append("orderStatus", getOrderStatus()) + .append("totalAmount", getTotalAmount()) + .append("actualAmount", getActualAmount()) + .append("orderContent", getOrderContent()) + .append("orderMessage", getOrderMessage()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/mapper/PayInvoiceMapper.java b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/mapper/PayInvoiceMapper.java new file mode 100644 index 0000000..af9db39 --- /dev/null +++ b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/mapper/PayInvoiceMapper.java @@ -0,0 +1,62 @@ +package com.boyue.pay.mapper; + +import java.util.List; + +import com.boyue.pay.domain.PayInvoice; + +/** + * 发票Mapper接口 + * + * @author boyue + * @date 2024-06-11 + */ +public interface PayInvoiceMapper +{ + /** + * 查询发票 + * + * @param invoiceId 发票主键 + * @return 发票 + */ + public PayInvoice selectPayInvoiceByInvoiceId(Long invoiceId); + + /** + * 查询发票列表 + * + * @param payInvoice 发票 + * @return 发票集合 + */ + public List selectPayInvoiceList(PayInvoice payInvoice); + + /** + * 新增发票 + * + * @param payInvoice 发票 + * @return 结果 + */ + public int insertPayInvoice(PayInvoice payInvoice); + + /** + * 修改发票 + * + * @param payInvoice 发票 + * @return 结果 + */ + public int updatePayInvoice(PayInvoice payInvoice); + + /** + * 删除发票 + * + * @param invoiceId 发票主键 + * @return 结果 + */ + public int deletePayInvoiceByInvoiceId(Long invoiceId); + + /** + * 批量删除发票 + * + * @param invoiceIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deletePayInvoiceByInvoiceIds(Long[] invoiceIds); +} diff --git a/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/mapper/PayOrderMapper.java b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/mapper/PayOrderMapper.java new file mode 100644 index 0000000..a649a44 --- /dev/null +++ b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/mapper/PayOrderMapper.java @@ -0,0 +1,73 @@ +package com.boyue.pay.mapper; + +import java.util.List; + +import com.boyue.pay.domain.PayOrder; + +/** + * 订单Mapper接口 + * + * @author Dftre + * @date 2024-02-15 + */ +public interface PayOrderMapper +{ + /** + * 查询订单 + * + * @param orderId 订单主键 + * @return 订单 + */ + public PayOrder selectPayOrderByOrderId(Long orderId); + + /** + * 查询订单 + * + * @param orderNumber 订单号 + * @return 订单集合 + */ + public PayOrder selectPayOrderByOrderNumber(String orderNumber); + + /** + * 查询订单列表 + * + * @param payOrder 订单 + * @return 订单集合 + */ + public List selectPayOrderList(PayOrder payOrder); + + /** + * 新增订单 + * + * @param payOrder 订单 + * @return 结果 + */ + public int insertPayOrder(PayOrder payOrder); + + /** + * 修改订单 + * + * @param payOrder 订单 + * @return 结果 + */ + public int updatePayOrder(PayOrder payOrder); + + /** + * 删除订单 + * + * @param orderId 订单主键 + * @return 结果 + */ + public int deletePayOrderByOrderId(Long orderId); + + /** + * 批量删除订单 + * + * @param orderIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deletePayOrderByOrderIds(Long[] orderIds); + + public int deletePayOrderByOrderNumber(String orderNumber); + public int updateStatus(String orderNumber, String orderStatus); +} diff --git a/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/service/IPayInvoiceService.java b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/service/IPayInvoiceService.java new file mode 100644 index 0000000..2fe0c8b --- /dev/null +++ b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/service/IPayInvoiceService.java @@ -0,0 +1,62 @@ +package com.boyue.pay.service; + +import java.util.List; + +import com.boyue.pay.domain.PayInvoice; + +/** + * 发票Service接口 + * + * @author boyue + * @date 2024-06-11 + */ +public interface IPayInvoiceService +{ + /** + * 查询发票 + * + * @param invoiceId 发票主键 + * @return 发票 + */ + public PayInvoice selectPayInvoiceByInvoiceId(Long invoiceId); + + /** + * 查询发票列表 + * + * @param payInvoice 发票 + * @return 发票集合 + */ + public List selectPayInvoiceList(PayInvoice payInvoice); + + /** + * 新增发票 + * + * @param payInvoice 发票 + * @return 结果 + */ + public int insertPayInvoice(PayInvoice payInvoice); + + /** + * 修改发票 + * + * @param payInvoice 发票 + * @return 结果 + */ + public int updatePayInvoice(PayInvoice payInvoice); + + /** + * 批量删除发票 + * + * @param invoiceIds 需要删除的发票主键集合 + * @return 结果 + */ + public int deletePayInvoiceByInvoiceIds(Long[] invoiceIds); + + /** + * 删除发票信息 + * + * @param invoiceId 发票主键 + * @return 结果 + */ + public int deletePayInvoiceByInvoiceId(Long invoiceId); +} diff --git a/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/service/IPayOrderService.java b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/service/IPayOrderService.java new file mode 100644 index 0000000..65cb176 --- /dev/null +++ b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/service/IPayOrderService.java @@ -0,0 +1,80 @@ +package com.boyue.pay.service; + +import java.util.List; + +import com.boyue.pay.domain.PayOrder; + +/** + * 订单Service接口 + * + * @author boyue + * @date 2024-06-11 + */ +public interface IPayOrderService +{ + /** + * 查询订单 + * + * @param orderId 订单主键 + * @return 订单 + */ + public PayOrder selectPayOrderByOrderId(Long orderId); + + /** + * 查询订单 + * + * @param orderNumber 订单号 + * @return 订单集合 + */ + public PayOrder selectPayOrderByOrderNumber(String orderNumber); + + /** + * 查询订单列表 + * + * @param payOrder 订单 + * @return 订单集合 + */ + public List selectPayOrderList(PayOrder payOrder); + + /** + * 新增订单 + * + * @param payOrder 订单 + * @return 结果 + */ + public int insertPayOrder(PayOrder payOrder); + + /** + * 修改订单 + * + * @param payOrder 订单 + * @return 结果 + */ + public int updatePayOrder(PayOrder payOrder); + + /** + * 批量删除订单 + * + * @param orderIds 需要删除的订单主键集合 + * @return 结果 + */ + public int deletePayOrderByOrderIds(Long[] orderIds); + + + /** + * 删除订单信息 + * + * @param orderId 订单主键 + * @return 结果 + */ + public int deletePayOrderByOrderNumber(String orderNumber); + + /** + * 删除订单信息 + * + * @param orderId 订单主键 + * @return 结果 + */ + public int deletePayOrderByOrderId(Long orderId); + public int updateStatus(String orderNumber, String orderStatus); +} diff --git a/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/service/PayService.java b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/service/PayService.java new file mode 100644 index 0000000..7f532ee --- /dev/null +++ b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/service/PayService.java @@ -0,0 +1,16 @@ +package com.boyue.pay.service; + +import com.boyue.pay.domain.PayOrder; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +public interface PayService { + String payUrl(PayOrder payOrder); + + String notify(HttpServletRequest servletRequest, HttpServletResponse response); + + PayOrder query(PayOrder payOrder); + + PayOrder refund(PayOrder payOrder); +} diff --git a/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/service/impl/PayInvoiceServiceImpl.java b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/service/impl/PayInvoiceServiceImpl.java new file mode 100644 index 0000000..04ae0d4 --- /dev/null +++ b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/service/impl/PayInvoiceServiceImpl.java @@ -0,0 +1,98 @@ +package com.boyue.pay.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.boyue.common.utils.DateUtils; +import com.boyue.pay.domain.PayInvoice; +import com.boyue.pay.mapper.PayInvoiceMapper; +import com.boyue.pay.service.IPayInvoiceService; + +/** + * 发票Service业务层处理 + * + * @author boyue + * @date 2024-06-11 + */ +@Service +public class PayInvoiceServiceImpl implements IPayInvoiceService +{ + @Autowired + private PayInvoiceMapper payInvoiceMapper; + + /** + * 查询发票 + * + * @param invoiceId 发票主键 + * @return 发票 + */ + @Override + public PayInvoice selectPayInvoiceByInvoiceId(Long invoiceId) + { + return payInvoiceMapper.selectPayInvoiceByInvoiceId(invoiceId); + } + + /** + * 查询发票列表 + * + * @param payInvoice 发票 + * @return 发票 + */ + @Override + public List selectPayInvoiceList(PayInvoice payInvoice) + { + return payInvoiceMapper.selectPayInvoiceList(payInvoice); + } + + /** + * 新增发票 + * + * @param payInvoice 发票 + * @return 结果 + */ + @Override + public int insertPayInvoice(PayInvoice payInvoice) + { + payInvoice.setCreateTime(DateUtils.getNowDate()); + return payInvoiceMapper.insertPayInvoice(payInvoice); + } + + /** + * 修改发票 + * + * @param payInvoice 发票 + * @return 结果 + */ + @Override + public int updatePayInvoice(PayInvoice payInvoice) + { + payInvoice.setUpdateTime(DateUtils.getNowDate()); + return payInvoiceMapper.updatePayInvoice(payInvoice); + } + + /** + * 批量删除发票 + * + * @param invoiceIds 需要删除的发票主键 + * @return 结果 + */ + @Override + public int deletePayInvoiceByInvoiceIds(Long[] invoiceIds) + { + return payInvoiceMapper.deletePayInvoiceByInvoiceIds(invoiceIds); + } + + /** + * 删除发票信息 + * + * @param invoiceId 发票主键 + * @return 结果 + */ + @Override + public int deletePayInvoiceByInvoiceId(Long invoiceId) + { + return payInvoiceMapper.deletePayInvoiceByInvoiceId(invoiceId); + } +} diff --git a/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/service/impl/PayOrderServiceImpl.java b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/service/impl/PayOrderServiceImpl.java new file mode 100644 index 0000000..7bf5aaf --- /dev/null +++ b/boyue-pay/boyue-pay-common/src/main/java/com/boyue/pay/service/impl/PayOrderServiceImpl.java @@ -0,0 +1,117 @@ +package com.boyue.pay.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.boyue.common.utils.DateUtils; +import com.boyue.pay.domain.PayOrder; +import com.boyue.pay.mapper.PayOrderMapper; +import com.boyue.pay.service.IPayOrderService; + +/** + * 订单Service业务层处理 + * + * @author boyue + * @date 2024-06-11 + */ +@Service +public class PayOrderServiceImpl implements IPayOrderService { + @Autowired + private PayOrderMapper payOrderMapper; + + /** + * 查询订单 + * + * @param orderId 订单主键 + * @return 订单 + */ + @Override + public PayOrder selectPayOrderByOrderId(Long orderId) { + return payOrderMapper.selectPayOrderByOrderId(orderId); + } + + /** + * 查询订单 + * + * @param orderNumber 订单号 + * @return 订单集合 + */ + @Override + public PayOrder selectPayOrderByOrderNumber(String orderNumber) { + return payOrderMapper.selectPayOrderByOrderNumber(orderNumber); + } + + /** + * 查询订单列表 + * + * @param payOrder 订单 + * @return 订单 + */ + @Override + public List selectPayOrderList(PayOrder payOrder) { + return payOrderMapper.selectPayOrderList(payOrder); + } + + /** + * 新增订单 + * + * @param payOrder 订单 + * @return 结果 + */ + @Override + public int insertPayOrder(PayOrder payOrder) { + return payOrderMapper.insertPayOrder(payOrder); + } + + /** + * 修改订单 + * + * @param payOrder 订单 + * @return 结果 + */ + @Override + public int updatePayOrder(PayOrder payOrder) { + payOrder.setUpdateTime(DateUtils.getNowDate()); + return payOrderMapper.updatePayOrder(payOrder); + } + + /** + * 批量删除订单 + * + * @param orderIds 需要删除的订单主键 + * @return 结果 + */ + @Override + public int deletePayOrderByOrderIds(Long[] orderIds) { + return payOrderMapper.deletePayOrderByOrderIds(orderIds); + } + + /** + * 删除订单信息 + * + * @param orderId 订单主键 + * @return 结果 + */ + @Override + public int deletePayOrderByOrderId(Long orderId) { + return payOrderMapper.deletePayOrderByOrderId(orderId); + } + + /** + * 删除订单信息 + * + * @param orderIds 需要删除的订单主键 + * @return 结果 + */ + @Override + public int deletePayOrderByOrderNumber(String orderNumber) { + return payOrderMapper.deletePayOrderByOrderNumber(orderNumber); + } + + @Override + public int updateStatus(String orderNumber, String orderStatus) { + return payOrderMapper.updateStatus(orderNumber, orderStatus); + } +} diff --git a/boyue-pay/boyue-pay-common/src/main/resources/mapper/pay/PayInvoiceMapper.xml b/boyue-pay/boyue-pay-common/src/main/resources/mapper/pay/PayInvoiceMapper.xml new file mode 100644 index 0000000..ce52464 --- /dev/null +++ b/boyue-pay/boyue-pay-common/src/main/resources/mapper/pay/PayInvoiceMapper.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + select invoice_id, order_number, invoice_type, invoice_header, invoice_number, invoice_phone, invoice_email, invoice_remark, create_by, create_time, update_by, update_time, remark from pay_invoice + + + + + + + + insert into pay_invoice + + invoice_id, + order_number, + invoice_type, + invoice_header, + invoice_number, + invoice_phone, + invoice_email, + invoice_remark, + create_by, + create_time, + update_by, + update_time, + remark, + + + #{invoiceId}, + #{orderNumber}, + #{invoiceType}, + #{invoiceHeader}, + #{invoiceNumber}, + #{invoicePhone}, + #{invoiceEmail}, + #{invoiceRemark}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + + + + + update pay_invoice + + order_number = #{orderNumber}, + invoice_type = #{invoiceType}, + invoice_header = #{invoiceHeader}, + invoice_number = #{invoiceNumber}, + invoice_phone = #{invoicePhone}, + invoice_email = #{invoiceEmail}, + invoice_remark = #{invoiceRemark}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where pay_invoice.invoice_id = #{invoiceId} + + + + delete from pay_invoice where invoice_id = #{invoiceId} + + + + delete from pay_invoice where invoice_id in + + #{invoiceId} + + + \ No newline at end of file diff --git a/boyue-pay/boyue-pay-common/src/main/resources/mapper/pay/PayOrderMapper.xml b/boyue-pay/boyue-pay-common/src/main/resources/mapper/pay/PayOrderMapper.xml new file mode 100644 index 0000000..128bb9f --- /dev/null +++ b/boyue-pay/boyue-pay-common/src/main/resources/mapper/pay/PayOrderMapper.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + select order_id, order_number, order_status, total_amount, actual_amount, order_content, order_message, create_by, create_time, update_by, update_time, remark from pay_order + + + + + + + + + + insert into pay_order + + order_number, + third_number, + order_status, + total_amount, + actual_amount, + order_content, + order_message, + create_by, + create_time, + update_by, + update_time, + remark, + + + #{orderNumber}, + #{thirdNumber}, + #{orderStatus}, + #{totalAmount}, + #{actualAmount}, + #{orderContent}, + #{orderMessage}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + + + + + update pay_order + + order_number = #{orderNumber}, + third_number = #{thirdNumber}, + order_status = #{orderStatus}, + total_amount = #{totalAmount}, + actual_amount = #{actualAmount}, + order_content = #{orderContent}, + order_message = #{orderMessage}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where pay_order.order_id = #{orderId} + + + + delete from pay_order where order_id = #{orderId} + + + + delete from pay_order where order_number= #{orderNumber} + + + + delete from pay_order where order_id in + + #{orderId} + + + + + update pay_order set order_status = #{orderStatus} where order_number = #{orderNumber} + + \ No newline at end of file diff --git a/boyue-pay/boyue-pay-sqb/pom.xml b/boyue-pay/boyue-pay-sqb/pom.xml new file mode 100644 index 0000000..949f3eb --- /dev/null +++ b/boyue-pay/boyue-pay-sqb/pom.xml @@ -0,0 +1,27 @@ + + + + boyue-pay + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-pay-sqb + + + 收钱吧支付模块 + + + + + + com.boyue + boyue-pay-common + + + + + \ No newline at end of file diff --git a/boyue-pay/boyue-pay-sqb/src/main/java/com/boyue/pay/sqb/config/SqbConfig.java b/boyue-pay/boyue-pay-sqb/src/main/java/com/boyue/pay/sqb/config/SqbConfig.java new file mode 100644 index 0000000..ac5d2cb --- /dev/null +++ b/boyue-pay/boyue-pay-sqb/src/main/java/com/boyue/pay/sqb/config/SqbConfig.java @@ -0,0 +1,116 @@ +package com.boyue.pay.sqb.config; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.ApplicationContext; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Component; + +@Component +@ConditionalOnProperty(prefix = "pay.sqb", name = "enabled", havingValue = "true") +public class SqbConfig { + @Value("${pay.sqb.apiDomain}") + private String apiDomain; + + @Value("${pay.sqb.terminalSn}") + private String terminalSn; + + @Value("${pay.sqb.terminalKey}") + private String terminalKey; + + @Value("${pay.sqb.appId}") + private String appId; + + @Value("${pay.sqb.vendorSn}") + private String vendorSn; + + @Value("${pay.sqb.vendorKey}") + private String vendorKey; + + @Value("${pay.sqb.notifyUrl}") + private String notifyUrl; + + @Value("${pay.sqb.publicKey}") + private String publicKey; + + @Autowired + private ApplicationContext applicationContext; + + public String getPublicKey() throws Exception { + if (publicKey.startsWith("classpath")) { + Resource resource = applicationContext.getResource(publicKey); + InputStream inputStream = resource.getInputStream(); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + String alipayPublicKeyValue = bufferedReader.lines().collect(Collectors.joining(System.lineSeparator())); + bufferedReader.close(); + publicKey = alipayPublicKeyValue; + } + return publicKey; + } + + public void setPublicKey(String publicKey) { + this.publicKey = publicKey; + } + + public String getNotifyUrl() { + return notifyUrl; + } + + public void setNotifyUrl(String notifyUrl) { + this.notifyUrl = notifyUrl; + } + + public String getApiDomain() { + return apiDomain; + } + + public void setApiDomain(String apiDomain) { + this.apiDomain = apiDomain; + } + + public String getTerminalSn() { + return terminalSn; + } + + public void setTerminalSn(String terminalSn) { + this.terminalSn = terminalSn; + } + + public String getTerminalKey() { + return terminalKey; + } + + public void setTerminalKey(String terminalKey) { + this.terminalKey = terminalKey; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getVendorSn() { + return vendorSn; + } + + public void setVendorSn(String vendorSn) { + this.vendorSn = vendorSn; + } + + public String getVendorKey() { + return vendorKey; + } + + public void setVendorKey(String vendorKey) { + this.vendorKey = vendorKey; + } +} diff --git a/boyue-pay/boyue-pay-sqb/src/main/java/com/boyue/pay/sqb/service/ISqbPayService.java b/boyue-pay/boyue-pay-sqb/src/main/java/com/boyue/pay/sqb/service/ISqbPayService.java new file mode 100644 index 0000000..2d97ae0 --- /dev/null +++ b/boyue-pay/boyue-pay-sqb/src/main/java/com/boyue/pay/sqb/service/ISqbPayService.java @@ -0,0 +1,6 @@ +package com.boyue.pay.sqb.service; + +import com.boyue.pay.service.PayService; + +public interface ISqbPayService extends PayService { +} diff --git a/boyue-pay/boyue-pay-sqb/src/main/java/com/boyue/pay/sqb/service/Impl/SQBServiceImpl.java b/boyue-pay/boyue-pay-sqb/src/main/java/com/boyue/pay/sqb/service/Impl/SQBServiceImpl.java new file mode 100644 index 0000000..17e22da --- /dev/null +++ b/boyue-pay/boyue-pay-sqb/src/main/java/com/boyue/pay/sqb/service/Impl/SQBServiceImpl.java @@ -0,0 +1,333 @@ +package com.boyue.pay.sqb.service.Impl; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.Signature; +import java.security.UnrecoverableKeyException; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; +import org.springframework.util.StreamUtils; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.http.HttpClientUtil; +import com.boyue.common.utils.sign.Md5Utils; +import com.boyue.pay.domain.PayOrder; +import com.boyue.pay.service.IPayOrderService; +import com.boyue.pay.sqb.config.SqbConfig; +import com.boyue.pay.sqb.service.ISqbPayService; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service("pay:service:sqb") +@ConditionalOnProperty(prefix = "pay.sqb", name = "enabled", havingValue = "true") +public class SQBServiceImpl implements ISqbPayService { + @Autowired + private SqbConfig sqbConfig; + + @Autowired + private IPayOrderService payOrderService; + + /** + * http POST 请求 + * + * @param url:请求地址 + * @param body: body实体字符串 + * @param sign:签名 + * @param sn: 序列号 + * @return + */ + public static String httpPost(String url, Object body, String sign, String sn) + throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException { + String xmlRes = "{}"; + try { + Map header = new HashMap<>(); + header.put("Authorization", sn + " " + sign); + xmlRes = HttpClientUtil.sendHttpPost(url, body, header); + } catch (Exception e) { + } + return xmlRes; + } + + /** + * 计算字符串的MD5值 + * + * @param signStr:签名字符串 + * @return + */ + private String getSign(String signStr) { + try { + String md5 = Md5Utils.encryptMd5(signStr); + return md5; + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return null; + } + } + + /** + * 终端激活 + * + * @param code:激活码 + * @return {terminal_sn:"$终端号",terminal_key:"$终端密钥"} + */ + public JSONObject activate(String code, String deviceId, String clientSn, String name) { + String url = sqbConfig.getApiDomain() + "/terminal/activate"; + JSONObject params = new JSONObject(); + try { + params.put("app_id", sqbConfig.getAppId()); // app_id,必填 + params.put("code", code); // 激活码,必填 + params.put("device_id", deviceId); // 客户方收银终端序列号,需保证同一app_id下唯一,必填。为方便识别,建议格式为“品牌名+门店编号+‘POS’+POS编号“ + params.put("client_sn", clientSn); // 客户方终端编号,一般客户方或系统给收银终端的编号,必填 + params.put("name", name); // 客户方终端名称,必填 + String sign = getSign(params.toString() + sqbConfig.getVendorKey()); + String result = httpPost(url, params.toString(), sign, sqbConfig.getVendorSn()); + JSONObject retObj = JSON.parseObject(result); + String resCode = retObj.get("result_code").toString(); + if (!"200".equals(resCode)) { + return null; + } + String responseStr = retObj.get("biz_response").toString(); + JSONObject terminal = JSON.parseObject(responseStr); + if (terminal.get("terminal_sn") == null || terminal.get("terminal_key") == null) { + return null; + } + return terminal; + } catch (Exception e) { + return null; + } + } + + /** + * 终端签到 + * + * @return {terminal_sn:"$终端号",terminal_key:"$终端密钥"} + */ + public JSONObject checkin() { + String url = sqbConfig.getApiDomain() + "/terminal/checkin"; + JSONObject params = new JSONObject(); + try { + params.put("terminal_sn", sqbConfig.getTerminalSn()); + params.put("device_id", "HUISUAN001POS01"); + params.put("os_info", "Mac OS"); + params.put("sdk_version", "Java SDK v1.0"); + String sign = getSign(params.toString() + sqbConfig.getTerminalKey()); + String result = httpPost(url, params.toString(), sign, sqbConfig.getTerminalSn()); + JSONObject retObj = JSON.parseObject(result); + String resCode = retObj.get("result_code").toString(); + if (!"200".equals(resCode)) { + return null; + } + String responseStr = retObj.get("biz_response").toString(); + JSONObject terminal = JSON.parseObject(responseStr); + if (terminal.get("terminal_sn") == null || terminal.get("terminal_key") == null) { + return null; + } + return terminal; + } catch (Exception e) { + return null; + } + } + + /** + * 退款 + * + * @return + */ + public PayOrder refund(PayOrder payOrder) { + String url = sqbConfig.getApiDomain() + "/upay/v2/refund"; + JSONObject params = new JSONObject(); + try { + params.put("terminal_sn", sqbConfig.getTerminalSn()); // 收钱吧终端ID + params.put("client_sn", payOrder.getOrderNumber()); // 商户系统订单号,必须在商户系统内唯一;且长度不超过64字节 + params.put("refund_amount", payOrder.getTotalAmount()); // 退款金额 + params.put("refund_request_no", "1"); // 商户退款所需序列号,表明是第几次退款 + params.put("operator", "kay"); // 门店操作员 + + String sign = getSign(params.toString() + sqbConfig.getTerminalKey()); + String result = httpPost(url, params, sign, sqbConfig.getTerminalSn()); + JSONObject retObj = JSON.parseObject(result); + JSONObject bizResponse = retObj.getJSONObject("biz_response"); + if ("REFUNDED".equals(bizResponse.getString("order_status"))) { + payOrderService.updateStatus(payOrder.getOrderNumber(), "已退款"); + } else { + log.error("退款失败"); + } + return payOrder; + } catch (Exception e) { + return null; + } + } + + /** + * 查询 + * + * @return + */ + @Override + public PayOrder query(PayOrder payOrder) { + String url = sqbConfig.getApiDomain() + "/upay/v2/query"; + JSONObject params = new JSONObject(); + try { + params.put("terminal_sn", sqbConfig.getTerminalSn()); // 终端号 + params.put("client_sn", payOrder.getOrderNumber()); // 商户系统订单号,必须在商户系统内唯一;且长度不超过64字节 + System.out.println(params.toString() + sqbConfig.getTerminalKey()); + String sign = getSign(params.toString() + sqbConfig.getTerminalKey()); + String result = httpPost(url, params, sign, sqbConfig.getTerminalSn()); + JSONObject retObj = JSON.parseObject(result); + String resCode = retObj.get("result_code").toString(); + if (!"200".equals(resCode)) { + throw new ServiceException("查询支付订单失败"); + } else { + JSONObject response = retObj.getJSONObject("biz_response"); + System.out.println(response); + } + return payOrder; + } catch (Exception e) { + return null; + } + } + + @Override + public String payUrl(PayOrder payOrder) { + return payUrl(payOrder, null); + } + + public String payUrl(PayOrder payOrder, String notifyBaseUrl) { + if (payOrder.getRemark() == null) { + payOrder.setRemark("支付"); + } + String orderNotifyUrl = sqbConfig.getNotifyUrl(); + String param = "" + + "client_sn=" + payOrder.getOrderNumber() + + "¬ify_url=" + orderNotifyUrl + + "&operator=" + payOrder.getCreateBy() + + "&return_url=" + "https://www.shouqianba.com/" + + "&subject=" + payOrder.getRemark() + + "&terminal_sn=" + sqbConfig.getTerminalSn() + + "&total_amount=" + Long.valueOf(payOrder.getTotalAmount().toString()); + String urlParam; + try { + urlParam = "" + + "client_sn=" + payOrder.getOrderNumber() + + "¬ify_url=" + URLEncoder.encode(orderNotifyUrl, "UTF-8") + + "&operator=" + URLEncoder.encode(payOrder.getCreateBy(), "UTF-8") + + "&return_url=" + "https://www.shouqianba.com/" + + "&subject=" + URLEncoder.encode(payOrder.getRemark(), "UTF-8") + + "&terminal_sn=" + sqbConfig.getTerminalSn() + + "&total_amount=" + Long.valueOf(payOrder.getTotalAmount().toString()); + + String sign = getSign(param + "&key=" + sqbConfig.getTerminalKey()); + return "https://qr.shouqianba.com/gateway?" + urlParam + "&sign=" + sign.toUpperCase(); + } catch (Exception e) { + throw new ServiceException("生成收钱吧支付链接失败"); + } + } + + /** + * 预下单 + * + * @return + */ + public String precreate(PayOrder payOrder, String sn, String payway) { + String url = sqbConfig.getApiDomain() + "/upay/v2/precreate"; + JSONObject params = new JSONObject(); + try { + params.put("terminal_sn", sqbConfig.getTerminalSn()); // 收钱吧终端ID + params.put("client_sn", payOrder.getOrderNumber()); // 商户系统订单号,必须在商户系统内唯一;且长度不超过32字节 + params.put("total_amount", payOrder.getTotalAmount()); // 交易总金额 + // params.put("payway", payway); // 支付方式 + params.put("subject", "无简介"); // 交易简介 + params.put("operator", SecurityUtils.getUsername()); // 门店操作员 + + String sign = getSign(params.toString() + sqbConfig.getTerminalKey()); + String result = httpPost(url, params.toString(), sign, sqbConfig.getTerminalSn()); + return result; + } catch (Exception e) { + return null; + } + } + + /** + * 自动撤单 + * + * @param terminal_sn:终端号 + * @param terminal_key:终端密钥 + * @return + */ + public String cancel(String terminal_sn, String terminal_key) { + String url = sqbConfig.getApiDomain() + "/upay/v2/cancel"; + JSONObject params = new JSONObject(); + try { + params.put("terminal_sn", terminal_sn); // 终端号 + params.put("client_sn", "18348290098298292838"); // 商户系统订单号,必须在商户系统内唯一;且长度不超过64字节 + + String sign = getSign(params.toString() + terminal_key); + String result = httpPost(url, params.toString(), sign, terminal_sn); + + return result; + } catch (Exception e) { + return null; + } + } + + public boolean validateSign(String data, String sign) { + try { + // 使用SHA256WithRSA算法 + Signature signature = Signature.getInstance("SHA256WithRSA"); + + // 获取公钥 + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey localPublicKey = keyFactory + .generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(sqbConfig.getPublicKey()))); + // 初始化验证过程 + signature.initVerify(localPublicKey); + signature.update(data.getBytes()); + + // 解码签名 + byte[] bytesSign = Base64.getDecoder().decode(sign); + + // 验证签名 + return signature.verify(bytesSign); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + @Override + public String notify(HttpServletRequest request, HttpServletResponse response) { + try { + String requestBody = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8); + JSONObject jsonObject = JSONObject.parseObject(requestBody); + String sign = request.getHeader("Authorization"); + if (!validateSign(requestBody, sign)) { + throw new ServiceException("收钱吧支付回调验签失败"); + } + System.out.println(jsonObject); + return "success"; + } catch (IOException e) { + e.printStackTrace(); + return "fail"; + } + } + +} diff --git a/boyue-pay/boyue-pay-sqb/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/boyue-pay/boyue-pay-sqb/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000..cf85b11 --- /dev/null +++ b/boyue-pay/boyue-pay-sqb/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,49 @@ +{ + "properties": [ + { + "name": "pay.sqb.enabled", + "type": "java.lang.Boolean", + "description": "启用收钱吧支付" + }, + { + "name": "pay.sqb.appId", + "type": "java.lang.String", + "description": "收钱吧appId" + }, + { + "name": "pay.sqb.apiDomain", + "type": "java.lang.String", + "description": "收钱吧apiDomain" + }, + { + "name": "pay.sqb.terminalSn", + "type": "java.lang.String", + "description": "收钱吧terminalSn" + }, + { + "name": "pay.sqb.terminalKey", + "type": "java.lang.String", + "description": "收钱吧terminalKey" + }, + { + "name": "pay.sqb.vendorSn", + "type": "java.lang.String", + "description": "收钱吧vendorSn" + }, + { + "name": "pay.sqb.vendorKey", + "type": "java.lang.String", + "description": "收钱吧vendorKey" + }, + { + "name": "pay.sqb.publicKey", + "type": "java.lang.String", + "description": "收钱吧公钥,可以直接用字符串,也可以是基于classpath的文件路径" + }, + { + "name": "pay.sqb.notifyUrl", + "type": "java.lang.String", + "description": "收钱吧支付回调地址" + } + ] +} \ No newline at end of file diff --git a/boyue-pay/boyue-pay-starter/pom.xml b/boyue-pay/boyue-pay-starter/pom.xml new file mode 100644 index 0000000..8a2a69c --- /dev/null +++ b/boyue-pay/boyue-pay-starter/pom.xml @@ -0,0 +1,46 @@ + + + + boyue-pay + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-pay-starter + + + 第三方支付模块 + + + + + + com.boyue + boyue-pay-common + + + + + com.boyue + boyue-pay-sqb + + + + + com.boyue + boyue-pay-alipay + + + + + com.boyue + boyue-pay-wx + + + + + + \ No newline at end of file diff --git a/boyue-pay/boyue-pay-starter/src/main/java/com/boyue/pay/controller/PayController.java b/boyue-pay/boyue-pay-starter/src/main/java/com/boyue/pay/controller/PayController.java new file mode 100644 index 0000000..06e3732 --- /dev/null +++ b/boyue-pay/boyue-pay-starter/src/main/java/com/boyue/pay/controller/PayController.java @@ -0,0 +1,98 @@ +package com.boyue.pay.controller; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Anonymous; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.pay.domain.PayOrder; +import com.boyue.pay.service.IPayOrderService; +import com.boyue.pay.service.PayService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.PostConstruct; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Tag(name = "支付业务") +@RequestMapping("/pay/{channel}") +@RestController +public class PayController extends BaseController { + + @Autowired(required = false) + private Map payServiceMap; // alipay wechat sqb + + @PostConstruct + public void init() { + if (payServiceMap == null) { + payServiceMap = new HashMap<>(); + logger.warn("请注意,没有加载任何支付服务"); + } else { + payServiceMap.forEach((k, v) -> { + logger.info("已加载支付服务 {}", k); + }); + } + } + + @Autowired + private IPayOrderService payOrderService; + + @Operation(summary = "支付") + @Parameters({ + @Parameter(name = "channel", description = "支付方式", required = true), + @Parameter(name = "orderNumber", description = "订单号", required = true) + }) + @GetMapping("/url/{orderNumber}") + public AjaxResult url(@PathVariable String channel, @PathVariable String orderNumber) throws Exception { + PayService payService = payServiceMap.get("pay:service:" + channel ); + PayOrder payOrder = payOrderService.selectPayOrderByOrderNumber(orderNumber); + return success(payService.payUrl(payOrder)); + } + + @Anonymous + @Operation(summary = "支付查询订单") + @Parameters({ + @Parameter(name = "channel", description = "支付方式", required = true) + }) + @PostMapping("/notify") + public String notify(@PathVariable String channel, HttpServletRequest request, HttpServletResponse response) + throws Exception { + PayService payService = payServiceMap.get("pay:service:" + channel ); + return payService.notify(request, response); + } + + @Operation(summary = "查询支付状态") + @Parameters({ + @Parameter(name = "channel", description = "支付方式", required = true), + @Parameter(name = "orderNumber", description = "订单号", required = true) + }) + @PostMapping("/query/{orderNumber}") + public AjaxResult query(@PathVariable String channel, @PathVariable(name = "orderNumber") String orderNumber) + throws Exception { + PayService payService = payServiceMap.get("pay:service:" + channel ); + PayOrder payOrder = payOrderService.selectPayOrderByOrderNumber(orderNumber); + return success(payService.query(payOrder)); + } + + @Operation(summary = "退款") + @PostMapping("/refund") + @Parameters({ + @Parameter(name = "channel", description = "支付方式", required = true), + }) + public AjaxResult refund(@PathVariable String channel, @RequestBody PayOrder payOrder) { + PayService payService = payServiceMap.get("pay:service:" + channel ); + return success(payService.refund(payOrder)); + } +} diff --git a/boyue-pay/boyue-pay-starter/src/main/java/com/boyue/pay/controller/PayInvoiceController.java b/boyue-pay/boyue-pay-starter/src/main/java/com/boyue/pay/controller/PayInvoiceController.java new file mode 100644 index 0000000..de951bf --- /dev/null +++ b/boyue-pay/boyue-pay-starter/src/main/java/com/boyue/pay/controller/PayInvoiceController.java @@ -0,0 +1,116 @@ +package com.boyue.pay.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.pay.domain.PayInvoice; +import com.boyue.pay.service.IPayInvoiceService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 发票Controller + * + * @author boyue + * @date 2024-06-11 + */ +@RestController +@RequestMapping("/pay/invoice") +@Tag(name = "【发票】管理") +public class PayInvoiceController extends BaseController +{ + @Autowired + private IPayInvoiceService payInvoiceService; + + /** + * 查询发票列表 + */ + @Operation(summary = "查询发票列表") + @PreAuthorize("@ss.hasPermi('pay:invoice:list')") + @GetMapping("/list") + public TableDataInfo list(PayInvoice payInvoice) + { + startPage(); + List list = payInvoiceService.selectPayInvoiceList(payInvoice); + return getDataTable(list); + } + + /** + * 导出发票列表 + */ + @Operation(summary = "导出发票列表") + @PreAuthorize("@ss.hasPermi('pay:invoice:export')") + @Log(title = "发票", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, PayInvoice payInvoice) + { + List list = payInvoiceService.selectPayInvoiceList(payInvoice); + ExcelUtil util = new ExcelUtil(PayInvoice.class); + util.exportExcel(response, list, "发票数据"); + } + + /** + * 获取发票详细信息 + */ + @Operation(summary = "获取发票详细信息") + @PreAuthorize("@ss.hasPermi('pay:invoice:query')") + @GetMapping(value = "/{invoiceId}") + public AjaxResult getInfo(@PathVariable("invoiceId") Long invoiceId) + { + return success(payInvoiceService.selectPayInvoiceByInvoiceId(invoiceId)); + } + + /** + * 新增发票 + */ + @Operation(summary = "新增发票") + @PreAuthorize("@ss.hasPermi('pay:invoice:add')") + @Log(title = "发票", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody PayInvoice payInvoice) + { + return toAjax(payInvoiceService.insertPayInvoice(payInvoice)); + } + + /** + * 修改发票 + */ + @Operation(summary = "修改发票") + @PreAuthorize("@ss.hasPermi('pay:invoice:edit')") + @Log(title = "发票", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody PayInvoice payInvoice) + { + return toAjax(payInvoiceService.updatePayInvoice(payInvoice)); + } + + /** + * 删除发票 + */ + @Operation(summary = "删除发票") + @PreAuthorize("@ss.hasPermi('pay:invoice:remove')") + @Log(title = "发票", businessType = BusinessType.DELETE) + @DeleteMapping("/{invoiceIds}") + public AjaxResult remove(@PathVariable( name = "invoiceIds" ) Long[] invoiceIds) + { + return toAjax(payInvoiceService.deletePayInvoiceByInvoiceIds(invoiceIds)); + } +} diff --git a/boyue-pay/boyue-pay-starter/src/main/java/com/boyue/pay/controller/PayOrderController.java b/boyue-pay/boyue-pay-starter/src/main/java/com/boyue/pay/controller/PayOrderController.java new file mode 100644 index 0000000..33286b9 --- /dev/null +++ b/boyue-pay/boyue-pay-starter/src/main/java/com/boyue/pay/controller/PayOrderController.java @@ -0,0 +1,133 @@ +package com.boyue.pay.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.common.utils.uuid.Seq; +import com.boyue.pay.domain.PayOrder; +import com.boyue.pay.service.IPayOrderService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 订单Controller + * + * @author Dftre + * @date 2024-02-15 + */ +@RestController +@RequestMapping("/pay/order") +@Tag(name = "【订单】管理") +public class PayOrderController extends BaseController +{ + @Autowired + private IPayOrderService payOrderService; + + /** + * 查询订单列表 + */ + @Operation(summary = "查询订单列表") + @PreAuthorize("@ss.hasPermi('pay:order:list')") + @GetMapping("/list") + public TableDataInfo list(PayOrder payOrder) + { + startPage(); + List list = payOrderService.selectPayOrderList(payOrder); + return getDataTable(list); + } + + /** + * 导出订单列表 + */ + @Operation(summary = "导出订单列表") + @PreAuthorize("@ss.hasPermi('pay:order:export')") + @Log(title = "订单", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, PayOrder payOrder) + { + List list = payOrderService.selectPayOrderList(payOrder); + ExcelUtil util = new ExcelUtil(PayOrder.class); + util.exportExcel(response, list, "订单数据"); + } + + /** + * 获取订单详细信息 + */ + @Operation(summary = "获取订单详细信息") + @PreAuthorize("@ss.hasPermi('pay:order:query')") + @GetMapping(value = "/{orderId}") + public AjaxResult getInfo(@PathVariable("orderId") Long orderId) + { + return success(payOrderService.selectPayOrderByOrderId(orderId)); + } + + /** + * 新增订单 + */ + @Operation(summary = "新增订单") + @PreAuthorize("@ss.hasPermi('pay:order:add')") + @Log(title = "订单", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody PayOrder payOrder) + { + payOrder.setCreateBy(getUsername()); + payOrder.setOrderNumber(Seq.getId().toString()); + AjaxResult result = toAjax(payOrderService.insertPayOrder(payOrder)); + result.put(AjaxResult.DATA_TAG, payOrder); + return result; + } + + /** + * 修改订单 + */ + @Operation(summary = "修改订单") + @PreAuthorize("@ss.hasPermi('pay:order:edit')") + @Log(title = "订单", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody PayOrder payOrder) + { + return toAjax(payOrderService.updatePayOrder(payOrder)); + } + + /** + * 删除订单 + */ + @Operation(summary = "通过订单号删除订单") + @PreAuthorize("@ss.hasPermi('pay:order:remove')") + @Log(title = "订单", businessType = BusinessType.DELETE) + @DeleteMapping("/orderNumber/{orderNumber}") + public AjaxResult removeByOrderNumber(@PathVariable( name = "orderNumber" ) String orderNumbers) + { + return toAjax(payOrderService.deletePayOrderByOrderNumber(orderNumbers)); + } + + /** + * 删除订单 + */ + @Operation(summary = "删除订单") + @PreAuthorize("@ss.hasPermi('pay:order:remove')") + @Log(title = "订单", businessType = BusinessType.DELETE) + @DeleteMapping("/{orderIds}") + public AjaxResult remove(@PathVariable( name = "orderIds" ) Long[] orderIds) + { + return toAjax(payOrderService.deletePayOrderByOrderIds(orderIds)); + } +} diff --git a/boyue-pay/boyue-pay-wx/pom.xml b/boyue-pay/boyue-pay-wx/pom.xml new file mode 100644 index 0000000..fb36e8e --- /dev/null +++ b/boyue-pay/boyue-pay-wx/pom.xml @@ -0,0 +1,31 @@ + + + + boyue-pay + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-pay-wx + + + 微信支付模块 + + + + + + com.boyue + boyue-pay-common + + + + com.github.wechatpay-apiv3 + wechatpay-java + + + + + \ No newline at end of file diff --git a/boyue-pay/boyue-pay-wx/src/main/java/com/boyue/pay/wx/config/WxPayConfig.java b/boyue-pay/boyue-pay-wx/src/main/java/com/boyue/pay/wx/config/WxPayConfig.java new file mode 100644 index 0000000..b354dbd --- /dev/null +++ b/boyue-pay/boyue-pay-wx/src/main/java/com/boyue/pay/wx/config/WxPayConfig.java @@ -0,0 +1,139 @@ +package com.boyue.pay.wx.config; + +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.Resource; + +import com.wechat.pay.java.core.RSAAutoCertificateConfig; +import com.wechat.pay.java.core.notification.NotificationParser; +import com.wechat.pay.java.service.payments.nativepay.NativePayService; +import com.wechat.pay.java.service.refund.RefundService; + +/** + * 配置我们自己的信息 + * + * @author ZlH + */ +@Configuration +@ConditionalOnProperty(prefix = "pay.wechat", name = "enabled", havingValue = "true") +public class WxPayConfig { + + /** 商户号 */ + @Value("${pay.wechat.merchantId}") + private String merchantId; + + /** 商户证书序列号 */ + @Value("${pay.wechat.merchantSerialNumber}") + private String merchantSerialNumber; + + /** 商户APIV3密钥 */ + @Value("${pay.wechat.apiV3Key}") + private String apiV3Key; + + /** 商户API私钥路径 */ + @Value("${pay.wechat.privateKeyPath}") + private String privateKeyPath; + + @Value("${pay.wechat.appId}") + private String appId; + + @Value("${pay.wechat.notifyUrl}") + private String notifyUrl; + + public String getMerchantId() { + return merchantId; + } + + public void setMerchantId(String merchantId) { + this.merchantId = merchantId; + } + + public String getMerchantSerialNumber() { + return merchantSerialNumber; + } + + public void setMerchantSerialNumber(String merchantSerialNumber) { + this.merchantSerialNumber = merchantSerialNumber; + } + + public String getApiV3Key() { + return apiV3Key; + } + + public void setApiV3Key(String apiV3Key) { + this.apiV3Key = apiV3Key; + } + + public void setPrivateKeyPath(String privateKeyPath) { + this.privateKeyPath = privateKeyPath; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getNotifyUrl() { + return notifyUrl; + } + + public void setNotifyUrl(String notifyUrl) { + this.notifyUrl = notifyUrl; + } + + @Bean + public RSAAutoCertificateConfig wxpayBaseConfig() throws Exception { + return new RSAAutoCertificateConfig.Builder() + .merchantId(getMerchantId()) + .privateKeyFromPath(getPrivateKeyPath()) + .merchantSerialNumber(getMerchantSerialNumber()) + .apiV3Key(getApiV3Key()) + .build(); + } + + @Bean + public NativePayService nativePayService() throws Exception { + return new NativePayService.Builder().config(wxpayBaseConfig()).build(); + } + + @Bean + public RefundService refundService() throws Exception { + return new RefundService.Builder().config(wxpayBaseConfig()).build(); + } + + @Bean + public NotificationParser notificationParser() throws Exception { + return new NotificationParser(wxpayBaseConfig()); + } + + @Autowired + private ApplicationContext applicationContext; + + public String getPrivateKeyPath() throws Exception { + if (privateKeyPath.startsWith("classpath:")) { + Resource resource = applicationContext.getResource(privateKeyPath); + String tempFilePath = System.getProperty("java.io.tmpdir") + "/temp_wxcert.pem"; + try (InputStream inputStream = resource.getInputStream()) { + Files.copy(inputStream, Paths.get(tempFilePath), StandardCopyOption.REPLACE_EXISTING); + privateKeyPath = tempFilePath; + } catch (Exception e) { + Files.deleteIfExists(Paths.get(tempFilePath)); + throw new RuntimeException("微信支付证书文件读取失败", e); + } + } + return privateKeyPath; + } + +} diff --git a/boyue-pay/boyue-pay-wx/src/main/java/com/boyue/pay/wx/service/IWxPayService.java b/boyue-pay/boyue-pay-wx/src/main/java/com/boyue/pay/wx/service/IWxPayService.java new file mode 100644 index 0000000..f61b0fb --- /dev/null +++ b/boyue-pay/boyue-pay-wx/src/main/java/com/boyue/pay/wx/service/IWxPayService.java @@ -0,0 +1,6 @@ +package com.boyue.pay.wx.service; + +import com.boyue.pay.service.PayService; + +public interface IWxPayService extends PayService { +} diff --git a/boyue-pay/boyue-pay-wx/src/main/java/com/boyue/pay/wx/service/Impl/WxPayService.java b/boyue-pay/boyue-pay-wx/src/main/java/com/boyue/pay/wx/service/Impl/WxPayService.java new file mode 100644 index 0000000..0ac22bd --- /dev/null +++ b/boyue-pay/boyue-pay-wx/src/main/java/com/boyue/pay/wx/service/Impl/WxPayService.java @@ -0,0 +1,124 @@ +package com.boyue.pay.wx.service.Impl; + +import java.nio.charset.StandardCharsets; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; +import org.springframework.util.StreamUtils; + +import com.boyue.pay.domain.PayOrder; +import com.boyue.pay.service.IPayOrderService; +import com.boyue.pay.wx.config.WxPayConfig; +import com.boyue.pay.wx.service.IWxPayService; +import com.wechat.pay.java.core.exception.ServiceException; +import com.wechat.pay.java.core.notification.NotificationParser; +import com.wechat.pay.java.core.notification.RequestParam; +import com.wechat.pay.java.service.payments.model.Transaction; +import com.wechat.pay.java.service.payments.model.Transaction.TradeStateEnum; +import com.wechat.pay.java.service.payments.nativepay.NativePayService; +import com.wechat.pay.java.service.payments.nativepay.model.Amount; +import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest; +import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse; +import com.wechat.pay.java.service.payments.nativepay.model.QueryOrderByIdRequest; +import com.wechat.pay.java.service.refund.RefundService; +import com.wechat.pay.java.service.refund.model.CreateRequest; +import com.wechat.pay.java.service.refund.model.Refund; +import com.wechat.pay.java.service.refund.model.Status; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Service("pay:service:wechat") +@ConditionalOnProperty(prefix = "pay.wechat", name = "enabled", havingValue = "true") +public class WxPayService implements IWxPayService { + + @Autowired + private IPayOrderService payOrderService; + + @Autowired + private NativePayService nativePayService; + + @Autowired + private WxPayConfig wxPayAppConfig; + + @Autowired + private NotificationParser notificationParser; + + @Autowired + private RefundService refundService; + + @Override + public String payUrl(PayOrder payOrder) { + PrepayRequest request = new PrepayRequest(); + Amount amount = new Amount(); + amount.setTotal(Integer.parseInt(payOrder.getActualAmount())); + request.setAmount(amount); + request.setAppid(wxPayAppConfig.getAppId()); + request.setMchid(wxPayAppConfig.getMerchantId()); + request.setDescription(payOrder.getOrderContent()); + request.setNotifyUrl(wxPayAppConfig.getNotifyUrl()); + request.setOutTradeNo(payOrder.getOrderNumber()); + PrepayResponse response = nativePayService.prepay(request); + return response.getCodeUrl(); + } + + @Override + public String notify(HttpServletRequest request, HttpServletResponse response) { + String timeStamp = request.getHeader("Wechatpay-Timestamp"); + String nonce = request.getHeader("Wechatpay-Nonce"); + String signature = request.getHeader("Wechatpay-Signature"); + String certSn = request.getHeader("Wechatpay-Serial"); + try { + String requestBody = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8); + RequestParam requestParam = new RequestParam.Builder() + .serialNumber(certSn) + .nonce(nonce) + .signature(signature) + .timestamp(timeStamp) + .body(requestBody) + .build(); + Transaction transaction = notificationParser.parse(requestParam, Transaction.class); + String orderNumber = transaction.getOutTradeNo(); + String otherOrderNumber = transaction.getTransactionId(); + TradeStateEnum orderState = transaction.getTradeState(); + System.out.println("orderNumber: " + orderNumber); + System.out.println("otherOrderNumber: " + otherOrderNumber); + System.out.println("orderState: " + orderState); + return "success"; + } catch (Exception e) { + e.printStackTrace(); + return "fail"; + } + } + + @Override + public PayOrder query(PayOrder payOrder) { + QueryOrderByIdRequest queryRequest = new QueryOrderByIdRequest(); + queryRequest.setMchid(wxPayAppConfig.getMerchantId()); + queryRequest.setTransactionId(payOrder.getOrderNumber()); + try { + Transaction result = nativePayService.queryOrderById(queryRequest); + System.out.println(result.getTradeState()); + } catch (ServiceException e) { + System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage()); + System.out.printf("reponse body=[%s]\n", e.getResponseBody()); + } + return payOrder; + } + + @Override + public PayOrder refund(PayOrder payOrder) { + CreateRequest request = new CreateRequest(); + request.setTransactionId(payOrder.getOrderNumber()); + request.setOutRefundNo(payOrder.getOrderNumber()); + request.setOutTradeNo(payOrder.getOrderNumber()); + Refund refund = refundService.create(request); + Status status = refund.getStatus(); + if (status.equals(Status.SUCCESS)) { + payOrderService.updateStatus(payOrder.getOrderNumber(), "已退款"); + } + return payOrder; + } + +} diff --git a/boyue-pay/boyue-pay-wx/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/boyue-pay/boyue-pay-wx/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000..edafe82 --- /dev/null +++ b/boyue-pay/boyue-pay-wx/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,39 @@ +{ + "properties": [ + { + "name": "pay.wechat.enabled", + "type": "java.lang.Boolean", + "description": "是否启用微信支付" + }, + { + "name": "pay.wechat.appId", + "type": "java.lang.String", + "description": "微信支付appid" + }, + { + "name": "pay.wechat.apiV3Key", + "type": "java.lang.String", + "description": "微信支付apiV3Key" + }, + { + "name": "pay.wechat.privateKeyPath", + "type": "java.lang.String", + "description": "微信支付私钥,可以直接用字符串,也可以是基于classpath的文件路径" + }, + { + "name": "pay.wechat.merchantId", + "type": "java.lang.String", + "description": "微信支付merchantId" + }, + { + "name": "pay.wechat.merchantSerialNumber", + "type": "java.lang.String", + "description": "微信支付merchantSerialNumber" + }, + { + "name": "pay.wechat.notifyUrl", + "type": "java.lang.String", + "description": "微信支付回调地址" + } + ] +} \ No newline at end of file diff --git a/boyue-pay/pom.xml b/boyue-pay/pom.xml new file mode 100644 index 0000000..289706c --- /dev/null +++ b/boyue-pay/pom.xml @@ -0,0 +1,75 @@ + + + + boyuehasfj-java + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-pay + + + 0.2.12 + 2.2.0 + + + + 支付模块 + + + + + + com.github.wechatpay-apiv3 + wechatpay-java + ${wechatpay.version} + + + + com.alipay.sdk + alipay-easysdk + ${alipay.version} + + + + + com.boyue + boyue-pay-common + ${boyue.version} + + + + + com.boyue + boyue-pay-sqb + ${boyue.version} + + + + + com.boyue + boyue-pay-alipay + ${boyue.version} + + + + + com.boyue + boyue-pay-wx + ${boyue.version} + + + + + + + boyue-pay-sqb + boyue-pay-alipay + boyue-pay-wx + boyue-pay-common + boyue-pay-starter + + pom + \ No newline at end of file diff --git a/boyue-plugins/boyue-atomikos/pom.xml b/boyue-plugins/boyue-atomikos/pom.xml new file mode 100644 index 0000000..069aea9 --- /dev/null +++ b/boyue-plugins/boyue-atomikos/pom.xml @@ -0,0 +1,33 @@ + + + + boyue-plugins + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-atomikos + + + boyue-atomikos + + + + + + + com.boyue + boyue-common + + + + + com.atomikos + transactions-spring-boot3-starter + + + + + diff --git a/boyue-plugins/boyue-atomikos/src/main/java/com/boyue/atomikos/config/AtomikosConfig.java b/boyue-plugins/boyue-atomikos/src/main/java/com/boyue/atomikos/config/AtomikosConfig.java new file mode 100644 index 0000000..e505b95 --- /dev/null +++ b/boyue-plugins/boyue-atomikos/src/main/java/com/boyue/atomikos/config/AtomikosConfig.java @@ -0,0 +1,65 @@ +package com.boyue.atomikos.config; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.jta.JtaTransactionManager; + +import com.atomikos.icatch.jta.UserTransactionImp; +import com.atomikos.icatch.jta.UserTransactionManager; +import com.atomikos.jdbc.AtomikosDataSourceBean; + +import jakarta.annotation.PreDestroy; +import jakarta.transaction.TransactionManager; +import jakarta.transaction.UserTransaction; + +/** + * JTA 事务配置 + * + * @author boyue + */ +@Configuration +@ConditionalOnProperty(name = "atomikos.enabled", havingValue = "true") +public class AtomikosConfig { + @Bean(name = "userTransaction") + public UserTransaction userTransaction() throws Throwable { + UserTransaction userTransaction = new UserTransactionImp(); + // 设置事务超时时间为10000毫秒 + userTransaction.setTransactionTimeout(10000); + return userTransaction; + } + + @Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close") + public TransactionManager atomikosTransactionManager() throws Throwable { + UserTransactionManager userTransactionManager = new UserTransactionManager(); + // 设置是否强制关闭事务管理器为false + userTransactionManager.setForceShutdown(false); + return userTransactionManager; + } + + @Bean(name = "transactionManager") + @DependsOn({ "userTransaction", "atomikosTransactionManager" }) + public PlatformTransactionManager transactionManager() throws Throwable { + UserTransaction userTransaction = userTransaction(); + TransactionManager atomikosTransactionManager = atomikosTransactionManager(); + return new JtaTransactionManager(userTransaction, atomikosTransactionManager); + } + + private List atomikosDataSourceBeans = new ArrayList<>(); + + public List getAtomikosDataSourceBeans() { + return atomikosDataSourceBeans; + } + + @PreDestroy + public void destroy() { + for (AtomikosDataSourceBean aDataSourceBean : this.atomikosDataSourceBeans) { + aDataSourceBean.close(); + } + } +} \ No newline at end of file diff --git a/boyue-plugins/boyue-atomikos/src/main/java/com/boyue/atomikos/datasource/AtomikosDataSourceCreate.java b/boyue-plugins/boyue-atomikos/src/main/java/com/boyue/atomikos/datasource/AtomikosDataSourceCreate.java new file mode 100644 index 0000000..37d98cd --- /dev/null +++ b/boyue-plugins/boyue-atomikos/src/main/java/com/boyue/atomikos/datasource/AtomikosDataSourceCreate.java @@ -0,0 +1,41 @@ +package com.boyue.atomikos.datasource; + +import java.util.Properties; + +import javax.sql.CommonDataSource; +import javax.sql.DataSource; +import javax.sql.XADataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; + +import com.atomikos.spring.AtomikosDataSourceBean; +import com.boyue.atomikos.config.AtomikosConfig; +import com.boyue.common.service.datasource.AfterCreateDataSource; + +@Component +@ConditionalOnProperty(name = "atomikos.enabled", havingValue = "true") +@DependsOn({ "transactionManager" }) +public class AtomikosDataSourceCreate implements AfterCreateDataSource { + + @Autowired + private AtomikosConfig atomikosConfig; + + public DataSource afterCreateDataSource(String name, Properties prop, CommonDataSource dataSource) { + AtomikosDataSourceBean ds = new AtomikosDataSourceBean(); + atomikosConfig.getAtomikosDataSourceBeans().add(ds); + ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource"); + ds.setUniqueResourceName(name); + ds.setXaDataSource((XADataSource) dataSource); + ds.setXaProperties(prop); + if (prop.getProperty("minIdle") != null) { + ds.setMinPoolSize(Integer.parseInt(prop.getProperty("minIdle"))); + } + if (prop.getProperty("maxActive") != null) { + ds.setMaxPoolSize(Integer.parseInt(prop.getProperty("maxActive"))); + } + return ds; + } +} diff --git a/boyue-plugins/boyue-ehcache/pom.xml b/boyue-plugins/boyue-ehcache/pom.xml new file mode 100644 index 0000000..c1f4687 --- /dev/null +++ b/boyue-plugins/boyue-ehcache/pom.xml @@ -0,0 +1,33 @@ + + + + boyue-plugins + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-ehcache + + + 中间件 + + + + + + + com.boyue + boyue-common + + + + + org.ehcache + ehcache + + + + + diff --git a/boyue-plugins/boyue-ehcache/src/main/java/com/boyue/ehcache/config/Ehcache3Cache.java b/boyue-plugins/boyue-ehcache/src/main/java/com/boyue/ehcache/config/Ehcache3Cache.java new file mode 100644 index 0000000..41a541f --- /dev/null +++ b/boyue-plugins/boyue-ehcache/src/main/java/com/boyue/ehcache/config/Ehcache3Cache.java @@ -0,0 +1,62 @@ +package com.boyue.ehcache.config; + +import java.lang.reflect.Field; +import java.util.HashSet; +import java.util.Set; + +import org.ehcache.core.EhcacheBase; +import org.ehcache.impl.internal.concurrent.ConcurrentHashMap; +import org.ehcache.impl.internal.store.heap.OnHeapStore; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cache.Cache; +import org.springframework.cache.jcache.JCacheCache; +import org.springframework.cache.jcache.JCacheCacheManager; +import org.springframework.stereotype.Component; + +import com.boyue.common.service.cache.CacheKeys; +import com.boyue.common.service.cache.CacheNoTimeOut; + +@Component +@ConditionalOnProperty(prefix = "spring.cache", name = { "type" }, havingValue = "jcache", matchIfMissing = false) +public class Ehcache3Cache implements CacheNoTimeOut, CacheKeys { + + @Autowired + private JCacheCacheManager jCacheCacheManager; + + @Override + @SuppressWarnings(value = { "unchecked", "rawtypes" }) + public Set getCachekeys(Cache cache) { + Set keyset = new HashSet<>(); + try { + JCacheCache jehcache = (JCacheCache) cache; + // org.ehcache.jsr107.Eh107Cache 不公开 + Object nativeCache = jehcache.getNativeCache(); + Class nativeCacheClass = nativeCache.getClass(); + Field ehCacheField = nativeCacheClass.getDeclaredField("ehCache"); + ehCacheField.setAccessible(true); + EhcacheBase ehcache = (EhcacheBase) ehCacheField.get(nativeCache); + Field storeField = EhcacheBase.class.getDeclaredField("store"); + storeField.setAccessible(true); + OnHeapStore store = (OnHeapStore) storeField.get(ehcache); + Field mapField = OnHeapStore.class.getDeclaredField("map"); + mapField.setAccessible(true); + // org.ehcache.impl.internal.store.heap.Backend 不公开 + Object map = mapField.get(store); + Class mapClass = map.getClass(); + Field realMapField = mapClass.getDeclaredField("realMap"); + realMapField.setAccessible(true); + ConcurrentHashMap realMap = (ConcurrentHashMap) realMapField.get(map); + keyset = realMap.keySet(); + } catch (Exception e) { + } + return keyset; + } + + @Override + public void setCacheObject(String cacheName, String key, T value) { + Cache cache = jCacheCacheManager.getCache(cacheName); + cache.put(cacheName, value); + } + +} diff --git a/boyue-plugins/boyue-ehcache/src/main/java/com/boyue/ehcache/config/Ehcache3Config.java b/boyue-plugins/boyue-ehcache/src/main/java/com/boyue/ehcache/config/Ehcache3Config.java new file mode 100644 index 0000000..00d0ee4 --- /dev/null +++ b/boyue-plugins/boyue-ehcache/src/main/java/com/boyue/ehcache/config/Ehcache3Config.java @@ -0,0 +1,52 @@ +package com.boyue.ehcache.config; + +import java.util.concurrent.TimeUnit; + +import javax.cache.CacheManager; +import javax.cache.Caching; +import javax.cache.configuration.MutableConfiguration; +import javax.cache.expiry.CreatedExpiryPolicy; +import javax.cache.expiry.Duration; + +import org.ehcache.jsr107.EhcacheCachingProvider; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.jcache.JCacheCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableCaching +@ConditionalOnProperty(prefix = "spring.cache", name = { "type" }, havingValue = "jcache", matchIfMissing = false) +public class Ehcache3Config { + + @Bean + public JCacheCacheManager ehcacheManager() { + EhcacheCachingProvider cachingProvider = (EhcacheCachingProvider) Caching.getCachingProvider(); + + CacheManager cacheManager = cachingProvider.getCacheManager(); + MutableConfiguration mutableConfiguration = new MutableConfiguration<>(); + mutableConfiguration.setTypes(String.class, Object.class); + mutableConfiguration.setStoreByValue(false); // 默认值为 true,可根据需求调整 + mutableConfiguration.setManagementEnabled(true); // 启用管理功能(可选) + mutableConfiguration.setStatisticsEnabled(true); // 启用统计功能(可选) + // 设置缓存过期策略(以 timeToIdle 为例,根据实际需求调整) + mutableConfiguration.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.HOURS, 1))); + + cacheManager.createCache("temp_cache", mutableConfiguration); + cacheManager.createCache("eternal_cache", mutableConfiguration); + cacheManager.createCache("sys_dict", mutableConfiguration); + cacheManager.createCache("sys_config", mutableConfiguration); + cacheManager.createCache("repeat_submit", mutableConfiguration); + cacheManager.createCache("captcha_codes", mutableConfiguration); + cacheManager.createCache("login_tokens", mutableConfiguration); + cacheManager.createCache("ip_err_cnt_key", mutableConfiguration); + cacheManager.createCache("rate_limit", mutableConfiguration); + cacheManager.createCache("pwd_err_cnt", mutableConfiguration); + + JCacheCacheManager jCacheCacheManager = new JCacheCacheManager(cacheManager); + + return jCacheCacheManager; + + } +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/pom.xml b/boyue-plugins/boyue-mybatis-interceptor/pom.xml new file mode 100644 index 0000000..5deb580 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/pom.xml @@ -0,0 +1,26 @@ + + + + boyue-plugins + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-mybatis-interceptor + + + + com.boyue + boyue-common + + + + org.springframework.boot + spring-boot-starter-aop + + + + diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/annotation/DataSecurity.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/annotation/DataSecurity.java new file mode 100644 index 0000000..d1096f5 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/annotation/DataSecurity.java @@ -0,0 +1,16 @@ +package com.boyue.mybatisinterceptor.annotation; + +import com.boyue.mybatisinterceptor.enums.DataSecurityStrategy; + +import java.lang.annotation.*; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataSecurity { + public DataSecurityStrategy strategy() default DataSecurityStrategy.CREEATE_BY; + + public String table() default ""; + + public String joinTableAlise() default ""; +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/annotation/MybatisHandlerOrder.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/annotation/MybatisHandlerOrder.java new file mode 100644 index 0000000..28c6cfc --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/annotation/MybatisHandlerOrder.java @@ -0,0 +1,10 @@ +package com.boyue.mybatisinterceptor.annotation; + +import java.lang.annotation.*; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface MybatisHandlerOrder { + public int value() default 0; +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/aspectj/DataSecurityAspect.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/aspectj/DataSecurityAspect.java new file mode 100644 index 0000000..e661f5e --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/aspectj/DataSecurityAspect.java @@ -0,0 +1,77 @@ +package com.boyue.mybatisinterceptor.aspectj; + +import com.boyue.mybatisinterceptor.annotation.DataSecurity; +import com.boyue.mybatisinterceptor.context.sqlContext.SqlContextHolder; +import com.boyue.mybatisinterceptor.model.JoinTableModel; +import com.boyue.mybatisinterceptor.model.WhereModel; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.After; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.stereotype.Component; + +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; + +@Aspect +@Component +public class DataSecurityAspect { + + @Before(value = "@annotation(dataSecurity)") + public void doBefore(final JoinPoint point, DataSecurity dataSecurity) throws Throwable { + SqlContextHolder.startDataSecurity(); + switch (dataSecurity.strategy()) { + case CREEATE_BY: + WhereModel createByModel = new WhereModel(); + createByModel.setTable(dataSecurity.table()); + createByModel.setValue("\"" + SecurityUtils.getUsername() + "\""); + createByModel.setWhereColumn("create_by"); + createByModel.setMethod(WhereModel.METHOD_EQUAS); + createByModel.setConnectType(WhereModel.CONNECT_AND); + SqlContextHolder.addWhereParam(createByModel); + break; + case USER_ID: + WhereModel userIdModel = new WhereModel(); + userIdModel.setTable(dataSecurity.table()); + userIdModel.setTable("user_id"); + userIdModel.setValue(SecurityUtils.getUserId()); + userIdModel.setConnectType(WhereModel.CONNECT_AND); + userIdModel.setMethod(WhereModel.METHOD_EQUAS); + SqlContextHolder.addWhereParam(userIdModel); + break; + case JOINTABLE_CREATE_BY: + JoinTableModel createByTableModel = new JoinTableModel(); + createByTableModel.setFromTable(dataSecurity.table()); + createByTableModel.setFromTableAlise(dataSecurity.table()); + createByTableModel.setJoinTable("sys_user"); + if (!StringUtils.isEmpty(dataSecurity.joinTableAlise())) { + createByTableModel.setJoinTableAlise(dataSecurity.joinTableAlise()); + } + createByTableModel.setFromTableColumn("create_by"); + createByTableModel.setJoinTableColumn("user_name"); + SqlContextHolder.addJoinTable(createByTableModel); + break; + case JOINTABLE_USER_ID: + JoinTableModel userIdTableModel = new JoinTableModel(); + userIdTableModel.setFromTable(dataSecurity.table()); + userIdTableModel.setFromTableAlise(dataSecurity.table()); + userIdTableModel.setJoinTable("sys_user"); + if (!StringUtils.isEmpty(dataSecurity.joinTableAlise())) { + userIdTableModel.setJoinTableAlise(dataSecurity.joinTableAlise()); + } + userIdTableModel.setFromTableColumn("user_id"); + userIdTableModel.setJoinTableColumn("user_id"); + SqlContextHolder.addJoinTable(userIdTableModel); + break; + default: + break; + } + + } + + @After(value = " @annotation(dataSecurity)") + public void doAfter(final JoinPoint point, DataSecurity dataSecurity) { + SqlContextHolder.clearCache(); + } +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/context/page/PageContextHolder.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/context/page/PageContextHolder.java new file mode 100644 index 0000000..7502519 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/context/page/PageContextHolder.java @@ -0,0 +1,44 @@ +package com.boyue.mybatisinterceptor.context.page; + +import com.alibaba.fastjson2.JSONObject; +import com.boyue.mybatisinterceptor.context.page.model.PageInfo; + +public class PageContextHolder { + private static final ThreadLocal PAGE_CONTEXT_HOLDER = new ThreadLocal<>(); + + private static final String PAGE_FLAG = "isPage"; + + private static final String PAGE_INFO = "pageInfo"; + + private static final String TOTAL = "total"; + + public static void startPage() { + JSONObject jsonObject = new JSONObject(); + jsonObject.put(PAGE_FLAG, Boolean.TRUE); + PAGE_CONTEXT_HOLDER.set(jsonObject); + } + + public static void setPageInfo() { + PAGE_CONTEXT_HOLDER.get().put(PAGE_INFO, PageInfo.defaultPageInfo()); + } + + public static PageInfo getPageInfo() { + return (PageInfo) PAGE_CONTEXT_HOLDER.get().get(PAGE_INFO); + } + + public static void clear() { + PAGE_CONTEXT_HOLDER.remove(); + } + + public static boolean isPage() { + return PAGE_CONTEXT_HOLDER.get() != null && PAGE_CONTEXT_HOLDER.get().getBooleanValue(PAGE_FLAG); + } + + public static void setTotal(Long total) { + PAGE_CONTEXT_HOLDER.get().put(TOTAL, total); + } + + public static Long getTotal() { + return PAGE_CONTEXT_HOLDER.get().getLong(TOTAL); + } +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/context/page/model/BoYueTableData.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/context/page/model/BoYueTableData.java new file mode 100644 index 0000000..543d12e --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/context/page/model/BoYueTableData.java @@ -0,0 +1,25 @@ +package com.boyue.mybatisinterceptor.context.page.model; + +import java.util.List; + +public class BoYueTableData { + private Long total; + private List data; + + public Long getTotal() { + return total; + } + + public void setTotal(Long total) { + this.total = total; + } + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } + +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/context/page/model/PageInfo.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/context/page/model/PageInfo.java new file mode 100644 index 0000000..ec95da6 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/context/page/model/PageInfo.java @@ -0,0 +1,63 @@ +package com.boyue.mybatisinterceptor.context.page.model; + +import com.boyue.common.core.text.Convert; +import com.boyue.common.utils.ServletUtils; + +public class PageInfo { + + private Long pageNumber; + + private Long pageSize; + + /** + * 当前记录起始索引 + */ + public static final String PAGE_NUM = "pageNum"; + + /** + * 每页显示记录数 + */ + public static final String PAGE_SIZE = "pageSize"; + + /** + * 排序列 + */ + public static final String ORDER_BY_COLUMN = "orderByColumn"; + + /** + * 排序的方向 "desc" 或者 "asc". + */ + public static final String IS_ASC = "isAsc"; + + /** + * 分页参数合理化 + */ + public static final String REASONABLE = "reasonable"; + + public Long getPageNumber() { + return pageNumber; + } + + public void setPageNumber(Long pageNumber) { + this.pageNumber = pageNumber; + } + + public Long getPageSize() { + return pageSize; + } + + public void setPageSize(Long pageSize) { + this.pageSize = pageSize; + } + + public static PageInfo defaultPageInfo() { + PageInfo pageInfo = new PageInfo(); + pageInfo.setPageNumber(Long.valueOf(Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1))); + pageInfo.setPageSize(Long.valueOf(Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10))); + return pageInfo; + } + + public Long getOffeset() { + return (pageNumber.longValue() - 1L) * pageSize; + } +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/context/page/model/TableInfo.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/context/page/model/TableInfo.java new file mode 100644 index 0000000..e12c12d --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/context/page/model/TableInfo.java @@ -0,0 +1,22 @@ +package com.boyue.mybatisinterceptor.context.page.model; + +import java.util.ArrayList; +import java.util.List; + +public class TableInfo extends ArrayList { + + private Long total; + + public TableInfo(List list) { + super(list); + } + + public Long getTotal() { + return total; + } + + public void setTotal(Long total) { + this.total = total; + } + +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/context/sqlContext/SqlContextHolder.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/context/sqlContext/SqlContextHolder.java new file mode 100644 index 0000000..346cac2 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/context/sqlContext/SqlContextHolder.java @@ -0,0 +1,55 @@ +package com.boyue.mybatisinterceptor.context.sqlContext; + +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.boyue.mybatisinterceptor.enums.SqlType; +import com.boyue.mybatisinterceptor.model.JoinTableModel; +import com.boyue.mybatisinterceptor.model.WhereModel; + +public class SqlContextHolder { + private static final ThreadLocal SQL_CONTEXT_HOLDER = new ThreadLocal<>(); + + public static void startDataSecurity() { + SQL_CONTEXT_HOLDER.get().put("isSecurity", Boolean.TRUE); + } + + public static void startLogicSelect() { + SQL_CONTEXT_HOLDER.get().put("isLogic", Boolean.TRUE); + } + + public static void addWhereParam(WhereModel whereModel) { + SQL_CONTEXT_HOLDER.get().getJSONArray(SqlType.WHERE.getSqlType()).add(whereModel); + } + + public static void clearCache() { + SQL_CONTEXT_HOLDER.remove(); + } + + public static boolean isSecurity() { + return SQL_CONTEXT_HOLDER.get() != null + && SQL_CONTEXT_HOLDER.get().getBooleanValue("isSecurity"); + } + + public static JSONArray getWhere() { + return SQL_CONTEXT_HOLDER.get().getJSONArray(SqlType.WHERE.getSqlType()); + } + + public static void addJoinTable(JoinTableModel joinTableModel) { + SQL_CONTEXT_HOLDER.get().getJSONArray(SqlType.JOIN.getSqlType()).add(joinTableModel); + } + + public static JSONArray getJoinTables() { + return SQL_CONTEXT_HOLDER.get().getJSONArray(SqlType.JOIN.getSqlType()); + } + + public static void startInterceptor() { + JSONObject jsonObject = SQL_CONTEXT_HOLDER.get(); + if (jsonObject != null) { + return; + } + JSONObject object = new JSONObject(); + object.put(SqlType.JOIN.getSqlType(), new JSONArray()); + object.put(SqlType.WHERE.getSqlType(), new JSONArray()); + SQL_CONTEXT_HOLDER.set(object); + } +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/enums/DataSecurityStrategy.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/enums/DataSecurityStrategy.java new file mode 100644 index 0000000..f1338f8 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/enums/DataSecurityStrategy.java @@ -0,0 +1,12 @@ +package com.boyue.mybatisinterceptor.enums; + +public enum DataSecurityStrategy { + /** 通过创建人字段关联表 */ + JOINTABLE_CREATE_BY, + /** 通过用户ID字段关联表 */ + JOINTABLE_USER_ID, + /** 通过创建人字段 */ + CREEATE_BY, + /** 通过用户ID字段 */ + USER_ID; +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/enums/SqlType.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/enums/SqlType.java new file mode 100644 index 0000000..8844f5b --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/enums/SqlType.java @@ -0,0 +1,22 @@ +package com.boyue.mybatisinterceptor.enums; + +public enum SqlType { + /** where */ + WHERE("where"), + /** join */ + JOIN("join"), + /** select */ + SELECT("select"), + /** limit */ + LIMIT("limit"); + + private String sqlType; + + public String getSqlType() { + return sqlType; + } + + private SqlType(String sqlType) { + this.sqlType = sqlType; + } +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/handler/MybatisAfterHandler.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/handler/MybatisAfterHandler.java new file mode 100644 index 0000000..d1090ab --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/handler/MybatisAfterHandler.java @@ -0,0 +1,7 @@ +package com.boyue.mybatisinterceptor.handler; + +public interface MybatisAfterHandler { + + Object handleObject(Object object) throws Throwable; + +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/handler/MybatisPreHandler.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/handler/MybatisPreHandler.java new file mode 100644 index 0000000..33c1150 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/handler/MybatisPreHandler.java @@ -0,0 +1,15 @@ +package com.boyue.mybatisinterceptor.handler; + +import org.apache.ibatis.cache.CacheKey; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; + +public interface MybatisPreHandler { + + void preHandle(Executor executor, MappedStatement mappedStatement, Object params, + RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) + throws Throwable; +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/handler/dataSecurity/DataSecurityPreHandler.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/handler/dataSecurity/DataSecurityPreHandler.java new file mode 100644 index 0000000..d61a7d2 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/handler/dataSecurity/DataSecurityPreHandler.java @@ -0,0 +1,133 @@ +package com.boyue.mybatisinterceptor.handler.dataSecurity; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +import org.apache.ibatis.cache.CacheKey; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.springframework.stereotype.Component; +import org.springframework.util.ReflectionUtils; + +import com.alibaba.fastjson2.JSONArray; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.sql.SqlUtil; +import com.boyue.mybatisinterceptor.annotation.MybatisHandlerOrder; +import com.boyue.mybatisinterceptor.context.sqlContext.SqlContextHolder; +import com.boyue.mybatisinterceptor.handler.MybatisPreHandler; +import com.boyue.mybatisinterceptor.model.JoinTableModel; +import com.boyue.mybatisinterceptor.model.WhereModel; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.operators.relational.EqualsTo; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.select.Join; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.update.Update; + +@MybatisHandlerOrder(1) +@Component +public class DataSecurityPreHandler implements MybatisPreHandler { + + private static final Field sqlFiled = ReflectionUtils.findField(BoundSql.class, "sql"); + static { + sqlFiled.setAccessible(true); + } + + @Override + public void preHandle(Executor executor, MappedStatement mappedStatement, Object params, RowBounds rowBounds, + ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws Throwable { + if (SqlContextHolder.isSecurity()) { + Statement sql = parseSql(SqlUtil.parseSql(boundSql.getSql())); + sqlFiled.set(boundSql, sql.toString()); + } + } + + private static Statement parseSql(Statement statement) throws JSQLParserException { + if (statement instanceof Select) { + Select select = (Select) statement; + // plain.setWhere(CCJSqlParserUtil.parseCondExpression(handleWhere(expWhere))); + handleWhere(select); + handleJoin(select); + return select; + } else { + return statement; + } + } + + private static void handleWhere(Statement statement) throws JSQLParserException { + if (statement instanceof Select) { + Select select = (Select) statement; + PlainSelect plainSelect = select.getPlainSelect(); + plainSelect.setWhere(getConfigedWhereExpression(plainSelect.getWhere())); + } else if (statement instanceof Update) { + Update update = (Update) statement; + update.setWhere(getConfigedWhereExpression(update.getWhere())); + } else if (statement instanceof Delete) { + Delete delete = (Delete) statement; + delete.setWhere(getConfigedWhereExpression(delete.getWhere())); + } + + } + + private static Expression getConfigedWhereExpression(Expression expWhere) throws JSQLParserException { + StringBuilder whereParam = new StringBuilder(" "); + String where = expWhere != null ? expWhere.toString() : null; + if (SqlContextHolder.getWhere() == null || SqlContextHolder.getWhere().size() <= 0) { + return expWhere; + } + JSONArray wehreArray = SqlContextHolder.getWhere(); + wehreArray.forEach(item -> { + whereParam.append(((WhereModel) item).getSqlString()); + }); + WhereModel whereModel = (WhereModel) wehreArray.get(0); + where = StringUtils.isEmpty(where) + ? whereParam.toString().substring(whereModel.getConnectType().length() + 2, whereParam.length()) + : where + " " + whereParam.toString(); + return CCJSqlParserUtil.parseCondExpression(where); + } + + private static void handleJoin(Statement statement) { + if (SqlContextHolder.getJoinTables() == null || SqlContextHolder.getJoinTables().size() <= 0) { + return; + } + if (statement instanceof Select) { + Select select = (Select) statement; + select.getPlainSelect().addJoins(getConfigedJoinExpression()); + } else if (statement instanceof Update) { + Update update = (Update) statement; + update.addJoins(getConfigedJoinExpression()); + } else if (statement instanceof Delete) { + Delete delete = (Delete) statement; + delete.addJoins(getConfigedJoinExpression()); + } + } + + private static List getConfigedJoinExpression() { + List joins = new ArrayList<>(); + SqlContextHolder.getJoinTables().forEach(item -> { + JoinTableModel tableModel = (JoinTableModel) item; + Table table = new Table(tableModel.getJoinTable()); + table.setAlias(new Alias(tableModel.getJoinTableAlise())); + Join join = new Join(); + join.setRightItem(table); + join.setInner(true); + Expression onExpression = new EqualsTo(new Column(tableModel.getFromTableColumnString()), + new Column(tableModel.getJoinTableColumnString())); + join.setOnExpressions(List.of(onExpression)); + joins.add(join); + }); + return joins; + } +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/handler/page/PageAfterHandler.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/handler/page/PageAfterHandler.java new file mode 100644 index 0000000..81185b2 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/handler/page/PageAfterHandler.java @@ -0,0 +1,30 @@ +package com.boyue.mybatisinterceptor.handler.page; + +import java.util.List; + +import org.springframework.stereotype.Component; + +import com.boyue.mybatisinterceptor.annotation.MybatisHandlerOrder; +import com.boyue.mybatisinterceptor.context.page.PageContextHolder; +import com.boyue.mybatisinterceptor.context.page.model.TableInfo; +import com.boyue.mybatisinterceptor.handler.MybatisAfterHandler; + +@MybatisHandlerOrder(1) +@Component +public class PageAfterHandler implements MybatisAfterHandler { + + @Override + public Object handleObject(Object object) throws Throwable { + if (PageContextHolder.isPage()) { + if (object instanceof List) { + TableInfo tableInfo = new TableInfo((List) object); + tableInfo.setTotal(PageContextHolder.getTotal()); + PageContextHolder.clear(); + return tableInfo; + } + return object; + } + return object; + } + +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/handler/page/PagePreHandler.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/handler/page/PagePreHandler.java new file mode 100644 index 0000000..206fe90 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/handler/page/PagePreHandler.java @@ -0,0 +1,144 @@ +package com.boyue.mybatisinterceptor.handler.page; + +import java.lang.reflect.Field; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.cache.CacheKey; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.ResultMap; +import org.apache.ibatis.mapping.ResultMapping; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.springframework.stereotype.Component; +import org.springframework.util.ReflectionUtils; + +import com.boyue.common.utils.sql.SqlUtil; +import com.boyue.mybatisinterceptor.annotation.MybatisHandlerOrder; +import com.boyue.mybatisinterceptor.context.page.PageContextHolder; +import com.boyue.mybatisinterceptor.context.page.model.PageInfo; +import com.boyue.mybatisinterceptor.handler.MybatisPreHandler; + +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.select.Limit; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SelectItem; + +@Component +@MybatisHandlerOrder(2) +public class PagePreHandler implements MybatisPreHandler { + + private static final List EMPTY_RESULTMAPPING = new ArrayList(0); + + private static final String SELECT_COUNT_SUFIX = "_SELECT_COUNT"; + private static final Field sqlFiled = ReflectionUtils.findField(BoundSql.class, "sql"); + static { + sqlFiled.setAccessible(true); + } + + @Override + public void preHandle(Executor executor, MappedStatement mappedStatement, Object params, RowBounds rowBounds, + ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws Throwable { + if (PageContextHolder.isPage()) { + String originSql = boundSql.getSql(); + Statement sql = SqlUtil.parseSql(originSql); + if (sql instanceof Select) { + PageInfo pageInfo = PageContextHolder.getPageInfo(); + Statement handleLimit = handleLimit((Select) sql, pageInfo); + Statement countSql = getCountSql((Select) sql); + Long count = getCount(executor, mappedStatement, params, boundSql, rowBounds, resultHandler, + countSql.toString()); + PageContextHolder.setTotal(count); + sqlFiled.set(boundSql, handleLimit.toString()); + cacheKey = executor.createCacheKey(mappedStatement, params, rowBounds, boundSql); + } + } + + } + + private static MappedStatement createCountMappedStatement(MappedStatement ms, String newMsId) { + MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), newMsId, + ms.getSqlSource(), + ms.getSqlCommandType()); + builder.resource(ms.getResource()); + builder.fetchSize(ms.getFetchSize()); + builder.statementType(ms.getStatementType()); + builder.keyGenerator(ms.getKeyGenerator()); + if (ms.getKeyProperties() != null && ms.getKeyProperties().length != 0) { + StringBuilder keyProperties = new StringBuilder(); + for (String keyProperty : ms.getKeyProperties()) { + keyProperties.append(keyProperty).append(","); + } + keyProperties.delete(keyProperties.length() - 1, keyProperties.length()); + builder.keyProperty(keyProperties.toString()); + } + builder.timeout(ms.getTimeout()); + builder.parameterMap(ms.getParameterMap()); + // count查询返回值int + List resultMaps = new ArrayList(); + ResultMap resultMap = new ResultMap.Builder(ms.getConfiguration(), ms.getId(), Long.class, + EMPTY_RESULTMAPPING) + .build(); + resultMaps.add(resultMap); + builder.resultMaps(resultMaps); + builder.resultSetType(ms.getResultSetType()); + builder.cache(ms.getCache()); + builder.flushCacheRequired(ms.isFlushCacheRequired()); + builder.useCache(ms.isUseCache()); + return builder.build(); + } + + public static Long getCount(Executor executor, MappedStatement mappedStatement, Object parameter, + BoundSql boundSql, RowBounds rowBounds, ResultHandler resultHandler, String countSql) + throws SQLException { + + Map additionalParameters = boundSql.getAdditionalParameters(); + + BoundSql countBoundSql = new BoundSql(mappedStatement.getConfiguration(), countSql, + boundSql.getParameterMappings(), parameter); + for (String key : additionalParameters.keySet()) { + countBoundSql.setAdditionalParameter(key, additionalParameters.get(key)); + } + CacheKey countKey = executor.createCacheKey(mappedStatement, parameter, RowBounds.DEFAULT, countBoundSql); + + List query = executor.query( + createCountMappedStatement(mappedStatement, getCountMSId(mappedStatement)), + parameter, RowBounds.DEFAULT, resultHandler, countKey, + countBoundSql); + return (Long) query.get(0); + } + + private static String getCountMSId(MappedStatement mappedStatement) { + return mappedStatement.getId() + SELECT_COUNT_SUFIX; + } + + public static Statement getCountSql(Select select) { + PlainSelect plain = select.getPlainSelect(); + PlainSelect countPlain = new PlainSelect(); + countPlain.setSelectItems(List.of(new SelectItem<>(new Column("COUNT(0)")))); + countPlain.setJoins(plain.getJoins()); + countPlain.setWhere(plain.getWhere()); + countPlain.setFromItem(plain.getFromItem()); + countPlain.setDistinct(plain.getDistinct()); + countPlain.setHaving(plain.getHaving()); + countPlain.setIntoTables(plain.getIntoTables()); + // countPlain.setOrderByElements(plain.getOrderByElements()); + return plain; + } + + private static Statement handleLimit(Select select, PageInfo pageInfo) { + Limit limit = new Limit(); + limit.setRowCount(new Column(pageInfo.getPageSize().toString())); + limit.setOffset(new Column(pageInfo.getOffeset().toString())); + PlainSelect plain = select.getPlainSelect(); + plain.setLimit(limit); + return select; + } + +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/interceptor/mybatis/MybatisInterceptor.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/interceptor/mybatis/MybatisInterceptor.java new file mode 100644 index 0000000..dcf8813 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/interceptor/mybatis/MybatisInterceptor.java @@ -0,0 +1,108 @@ +package com.boyue.mybatisinterceptor.interceptor.mybatis; + +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.ibatis.cache.CacheKey; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.plugin.Intercepts; +import org.apache.ibatis.plugin.Invocation; +import org.apache.ibatis.plugin.Signature; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.boyue.mybatisinterceptor.annotation.MybatisHandlerOrder; +import com.boyue.mybatisinterceptor.handler.MybatisAfterHandler; +import com.boyue.mybatisinterceptor.handler.MybatisPreHandler; + +import jakarta.annotation.PostConstruct; + +@Component +@Intercepts({ + @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, + RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class }), + @Signature(type = Executor.class, method = "query", args = { + MappedStatement.class, Object.class, RowBounds.class, + ResultHandler.class }) + +}) +public class MybatisInterceptor implements Interceptor { + + @Autowired + private List preHandlerBeans; + + @Autowired + private List afterHandlerBeans; + + private static List preHandlersChain; + + private static List afterHandlersChain; + + @PostConstruct + public void init() { + // 对处理器按注解排序 + preHandlersChain = sortHandlers(preHandlerBeans); + afterHandlersChain = sortHandlers(afterHandlerBeans); + } + + /** + * 通用的处理器排序方法 + */ + private List sortHandlers(List handlers) { + return handlers.stream() + .sorted((item1, item2) -> { + MybatisHandlerOrder ann1 = item1.getClass().getAnnotation(MybatisHandlerOrder.class); + MybatisHandlerOrder ann2 = item2.getClass().getAnnotation(MybatisHandlerOrder.class); + int a = ann1 == null ? 0 : ann1.value(); + int b = ann2 == null ? 0 : ann2.value(); + return a - b; + }).collect(Collectors.toList()); + } + + @Override + public Object intercept(Invocation invocation) throws Throwable { + Executor targetExecutor = (Executor) invocation.getTarget(); + Object[] args = invocation.getArgs(); + if (args.length < 6) { + if (preHandlersChain != null && preHandlersChain.size() > 0) { + MappedStatement ms = (MappedStatement) args[0]; + Object parameterObject = args[1]; + RowBounds rowBounds = (RowBounds) args[2]; + Executor executor = (Executor) invocation.getTarget(); + BoundSql boundSql = ms.getBoundSql(parameterObject); + // 可以对参数做各种处理 + CacheKey cacheKey = executor.createCacheKey(ms, parameterObject, rowBounds, boundSql); + for (MybatisPreHandler item : preHandlersChain) { + item.preHandle(targetExecutor, ms, args[1], (RowBounds) args[2], + (ResultHandler) args[3], cacheKey, boundSql); + } + } + Object result = invocation.proceed(); + if (afterHandlersChain != null && afterHandlersChain.size() > 0) { + for (MybatisAfterHandler item : afterHandlersChain) { + item.handleObject(result); + } + } + return result; + } + if (preHandlersChain != null && preHandlersChain.size() > 0) { + for (MybatisPreHandler item : preHandlersChain) { + item.preHandle(targetExecutor, (MappedStatement) args[0], args[1], (RowBounds) args[2], + (ResultHandler) args[3], (CacheKey) args[4], (BoundSql) args[5]); + } + } + Object result = invocation.proceed(); + if (afterHandlersChain != null && afterHandlersChain.size() > 0) { + for (MybatisAfterHandler item : afterHandlersChain) { + result = item.handleObject(result); + } + } + return result; + } + +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/model/JoinTableModel.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/model/JoinTableModel.java new file mode 100644 index 0000000..e9e3a42 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/model/JoinTableModel.java @@ -0,0 +1,85 @@ +package com.boyue.mybatisinterceptor.model; + +import com.boyue.common.utils.StringUtils; + +public class JoinTableModel { + private String joinTable; + + private String joinTableAlise; + + private String fromTable; + + private String fromTableAlise; + + private String joinTableColumn; + + private String fromTableColumn; + + public String getJoinTable() { + return joinTable; + } + + public void setJoinTable(String joinTable) { + this.joinTable = joinTable; + } + + public String getJoinTableAlise() { + if (StringUtils.isEmpty(this.joinTableAlise)) { + return this.joinTable; + } + return joinTableAlise; + } + + public void setJoinTableAlise(String joinTableAlise) { + + this.joinTableAlise = joinTableAlise; + } + + public String getFromTable() { + return fromTable; + } + + public void setFromTable(String fromTable) { + this.fromTable = fromTable; + } + + public String getFromTableAlise() { + if (StringUtils.isEmpty(this.fromTableAlise)) { + return this.fromTable; + } + return fromTableAlise; + } + + public void setFromTableAlise(String fromTableAlise) { + this.fromTableAlise = fromTableAlise; + } + + public String getJoinTableColumn() { + + return joinTableColumn; + } + + public void setJoinTableColumn(String joinTableColumn) { + this.joinTableColumn = joinTableColumn; + } + + public String getFromTableColumn() { + return fromTableColumn; + } + + public void setFromTableColumn(String fromTableColumn) { + this.fromTableColumn = fromTableColumn; + } + + public String getJoinTableColumnString() { + return this.getJoinTableAlise() + "." + this.joinTableColumn; + } + + public String getFromTableColumnString() { + if (StringUtils.isEmpty(this.getFromTableAlise())) { + return this.fromTableColumn; + } + return this.getFromTableAlise() + "." + this.fromTableColumn; + } + +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/model/WhereModel.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/model/WhereModel.java new file mode 100644 index 0000000..0091a0b --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/model/WhereModel.java @@ -0,0 +1,67 @@ +package com.boyue.mybatisinterceptor.model; + +import com.boyue.common.utils.StringUtils; + +public class WhereModel { + private String whereColumn; + private String table; + private Object value; + private String connectType; + private String method; + + public static final String METHOD_EQUAS = "="; + public static final String METHOD_LIKE = "like"; + public static final String CONNECT_AND = "AND"; + public static final String CONNECT_OR = "OR"; + + public String getWhereColumn() { + return whereColumn; + } + + public void setWhereColumn(String whereColumn) { + this.whereColumn = whereColumn; + } + + public String getTable() { + return table; + } + + public void setTable(String table) { + this.table = table; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + public String getFullTableColumn() { + if (StringUtils.isEmpty(this.table)) { + return this.whereColumn; + } + return this.table + "." + this.whereColumn; + } + + public String getConnectType() { + return connectType; + } + + public void setConnectType(String connectType) { + this.connectType = connectType; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getSqlString() { + return String.format(" %s %s %s %s ", this.getConnectType(), this.getFullTableColumn(), this.method, this.value); + } +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/util/DataSecurityUtil.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/util/DataSecurityUtil.java new file mode 100644 index 0000000..bd6c5c0 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/util/DataSecurityUtil.java @@ -0,0 +1,14 @@ +package com.boyue.mybatisinterceptor.util; + +import com.boyue.mybatisinterceptor.context.sqlContext.SqlContextHolder; + +public class DataSecurityUtil { + + public static void closeDataSecurity() { + SqlContextHolder.clearCache(); + } + + public static void startDataSecurity() { + SqlContextHolder.startDataSecurity(); + } +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/util/PageUtils.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/util/PageUtils.java new file mode 100644 index 0000000..d9e1026 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/util/PageUtils.java @@ -0,0 +1,30 @@ +package com.boyue.mybatisinterceptor.util; + +import java.util.List; + +import com.boyue.mybatisinterceptor.context.page.PageContextHolder; +import com.boyue.mybatisinterceptor.context.page.model.BoYueTableData; +import com.boyue.mybatisinterceptor.context.page.model.TableInfo; + +public class PageUtils { + public static BoYueTableData toTableInfo(List list) { + if (list instanceof TableInfo) { + TableInfo tableInfo = (TableInfo) list; + BoYueTableData BoYueTableData = new BoYueTableData(); + BoYueTableData.setData(list); + BoYueTableData.setTotal(tableInfo.getTotal()); + return BoYueTableData; + } + BoYueTableData BoYueTableData = new BoYueTableData(); + BoYueTableData.setData(list); + BoYueTableData.setTotal(-1L); + return BoYueTableData; + + } + + public static void boyueStartPage() { + PageContextHolder.startPage(); + PageContextHolder.setPageInfo(); + } + +} diff --git a/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/util/SqlUtil.java b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/util/SqlUtil.java new file mode 100644 index 0000000..1ebd96f --- /dev/null +++ b/boyue-plugins/boyue-mybatis-interceptor/src/main/java/com/boyue/mybatisinterceptor/util/SqlUtil.java @@ -0,0 +1,64 @@ +package com.boyue.mybatisinterceptor.util; + +import com.boyue.common.exception.UtilException; +import com.boyue.common.utils.StringUtils; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserManager; +import net.sf.jsqlparser.statement.Statement; + +import java.io.StringReader; + +/** + * sql操作工具类 + * + * @author boyue + */ +public class SqlUtil { + /** + * 定义常用的 sql关键字 + */ + public static String SQL_REGEX = "and |extractvalue|updatexml|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |+|user()"; + + /** + * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) + */ + public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; + + private static final CCJSqlParserManager parserManager = new CCJSqlParserManager(); + + /** + * 检查字符,防止注入绕过 + */ + public static String escapeOrderBySql(String value) { + if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) { + throw new UtilException("参数不符合规范,不能进行查询"); + } + return value; + } + + /** + * 验证 order by 语法是否符合规范 + */ + public static boolean isValidOrderBySql(String value) { + return value.matches(SQL_PATTERN); + } + + /** + * SQL关键字检查 + */ + public static void filterKeyword(String value) { + if (StringUtils.isEmpty(value)) { + return; + } + String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|"); + for (String sqlKeyword : sqlKeywords) { + if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) { + throw new UtilException("参数存在SQL注入风险"); + } + } + } + + public static Statement parseSql(String sql) throws JSQLParserException { + return parserManager.parse(new StringReader(sql)); + } +} diff --git a/boyue-plugins/boyue-mybatis-jpa/pom.xml b/boyue-plugins/boyue-mybatis-jpa/pom.xml new file mode 100644 index 0000000..fb92d44 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/pom.xml @@ -0,0 +1,33 @@ + + + + boyue-plugins + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-mybatis-jpa + + + boyue-mybatis-jpa + + + + + + + com.boyue + boyue-common + + + + com.baomidou + mybatis-plus-spring-boot3-starter + true + + + + + diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/annotation/Column.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/annotation/Column.java new file mode 100644 index 0000000..73f7263 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/annotation/Column.java @@ -0,0 +1,18 @@ +package com.boyue.mybatis.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 标注数据库字段 + * + * @author Dftre + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Column { + String name(); // 对应数据库字段名 + boolean primaryKey() default false; // 是否是主键 +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/annotation/ColumnMap.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/annotation/ColumnMap.java new file mode 100644 index 0000000..9dae5f2 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/annotation/ColumnMap.java @@ -0,0 +1,25 @@ +package com.boyue.mybatis.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 标注数据库映射字段 + * + * @author Dftre + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ColumnMap { + String name(); // 对应数据库字段 + + String target(); // 映射表来源 + + String on() default ""; // 映射表字段 + + String onLeft() default ""; // 映射表左字段 + + String onRight() default ""; // 映射表右字段 +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/annotation/EnableTableMap.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/annotation/EnableTableMap.java new file mode 100644 index 0000000..35559b0 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/annotation/EnableTableMap.java @@ -0,0 +1,35 @@ +package com.boyue.mybatis.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 开启数据库关联 + * + * @author Dftre + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface EnableTableMap { + String name() default "t"; + + String dept() default ""; + + String user() default ""; + + String userOn() default "user_id"; + + String userOnLeft() default ""; + + String userOnRight() default ""; + + String deptOn() default "dept_id"; + + String deptOnLeft() default ""; + + String deptOnRight() default ""; + + String deptFrom() default ""; +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/annotation/Query.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/annotation/Query.java new file mode 100644 index 0000000..c98a7bf --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/annotation/Query.java @@ -0,0 +1,27 @@ +package com.boyue.mybatis.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.boyue.mybatis.enums.QueryEnum; + +/** + * 标注查询条件 + * + * @author Dftre + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Query { + QueryEnum operation() default QueryEnum.eq; // 操作符,如 eq, like, gt 等 + + String[] sections() default { "begin", "end" }; + + String section() default "section"; + + boolean params() default false; + + String sql() default ""; +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/annotation/Table.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/annotation/Table.java new file mode 100644 index 0000000..a12ab7d --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/annotation/Table.java @@ -0,0 +1,14 @@ +package com.boyue.mybatis.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Table { + String name(); + String[] columns() default {}; + String[] orderBy() default {}; +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/domain/BaseColumnInfo.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/domain/BaseColumnInfo.java new file mode 100644 index 0000000..31e94b3 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/domain/BaseColumnInfo.java @@ -0,0 +1,54 @@ +package com.boyue.mybatis.domain; + +import java.lang.reflect.Field; + +import com.boyue.mybatis.annotation.Query; +import com.boyue.mybatis.utils.QueryUtil; + +public class BaseColumnInfo { + protected String columnName; + protected String fieldName; + protected Field field; + protected Query query; + protected String querySql; + + public Field getField() { + return field; + } + + public Query getQuery() { + return query; + } + + public String getTemplate() { + return getTemplate(false); + } + + public String getColumnName() { + return columnName; + } + + public String getUnqualifiedColumnName() { + return columnName; + } + + public String getTemplate(boolean params) { + if (params) { + return "#{params." + fieldName + "}"; + } else { + return "#{" + fieldName + "}"; + } + } + + public boolean fieldQueryIsNotNull(Object entity) { + return QueryUtil.fieldQueryIsNotNull(entity, field, query); + } + + public boolean fieldIsNotNull(Object entity) { + try { + return this.field.get(entity) != null; + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to access field for building query conditions.", e); + } + } +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/domain/ColumnInfo.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/domain/ColumnInfo.java new file mode 100644 index 0000000..916fd79 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/domain/ColumnInfo.java @@ -0,0 +1,39 @@ +package com.boyue.mybatis.domain; + +import java.lang.reflect.Field; + +import org.springframework.core.annotation.AnnotationUtils; + +import com.boyue.mybatis.annotation.Column; +import com.boyue.mybatis.annotation.Query; +import com.boyue.mybatis.utils.QueryUtil; + +public class ColumnInfo extends BaseColumnInfo { + private Column column; + + public ColumnInfo(Field field) { + this.field = field; + this.column = AnnotationUtils.findAnnotation(this.field, Column.class); + this.query = AnnotationUtils.findAnnotation(this.field, Query.class); + this.columnName = this.column.name(); + this.fieldName = this.field.getName(); + this.field.setAccessible(true); + this.querySql = this.getQuerySql(this.query); + } + + public boolean isPrimaryKey() { + return this.column.primaryKey(); + } + + public String getQuerySql(Query query) { + return QueryUtil.getQuerySql(this.getColumnName(), getTemplate(), query); + } + + public String getQuerySql() { + return this.querySql; + } + + public String getFullyQualifiedColumnName(String tableName) { + return tableName + "." + this.getColumnName(); + } +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/domain/MapColumnInfo.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/domain/MapColumnInfo.java new file mode 100644 index 0000000..acf6f9a --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/domain/MapColumnInfo.java @@ -0,0 +1,45 @@ +package com.boyue.mybatis.domain; + +import java.lang.reflect.Field; + +import org.springframework.core.annotation.AnnotationUtils; + +import com.boyue.mybatis.annotation.ColumnMap; +import com.boyue.mybatis.annotation.Query; +import com.boyue.mybatis.utils.QueryUtil; + +/** + * 数据库关联字段信息 + * + * @author Dftre + */ +public class MapColumnInfo extends BaseColumnInfo { + private ColumnMap columnMap; + + public MapColumnInfo(Field field) { + this.field = field; + this.columnMap = AnnotationUtils.findAnnotation(this.field, ColumnMap.class); + this.columnName = this.columnMap.name(); + this.query = AnnotationUtils.findAnnotation(this.field, Query.class); + this.fieldName = this.field.getName(); + this.field.setAccessible(true); + this.querySql = this.getQuerySql(this.query); + } + + public ColumnMap getJoin() { + return this.columnMap; + } + + public String getQuerySql(Query query) { + return QueryUtil.getQuerySql(this.getColumnName(), getTemplate(), query); + } + + public String getQuerySql() { + return this.columnMap.target() + "." + this.querySql; + } + + public String getFullyQualifiedColumnName() { + return this.columnMap.target() + "." + this.getColumnName(); + } + +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/domain/TableInfo.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/domain/TableInfo.java new file mode 100644 index 0000000..a8a82fb --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/domain/TableInfo.java @@ -0,0 +1,206 @@ +package com.boyue.mybatis.domain; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.springframework.core.annotation.AnnotationUtils; + +import com.boyue.common.utils.StringUtils; +import com.boyue.mybatis.annotation.Column; +import com.boyue.mybatis.annotation.ColumnMap; +import com.boyue.mybatis.annotation.EnableTableMap; +import com.boyue.mybatis.annotation.Table; +import com.boyue.mybatis.utils.QueryUtil; + +/** + * 数据库表信息 + * + * @author Dftre + */ +public class TableInfo { + private String tableName; + private EnableTableMap enableTableMap; + private Table table; + private List columns = new ArrayList<>(); // 所有标记column注解的字段 + private List primaryKeys = new ArrayList<>(); + private List mapColumns = new ArrayList<>(); + private Set joinSql = new HashSet<>(); + boolean hasDataScopeValue = false; + + public TableInfo(Class cls) { + this.table = AnnotationUtils.findAnnotation(cls, Table.class); + if (this.table == null) { + throw new RuntimeException("error , not find tableName"); + } + this.tableName = this.table.name(); + this.enableTableMap = AnnotationUtils.findAnnotation(cls, EnableTableMap.class); + + Arrays.stream(cls.getDeclaredFields()) + .filter(field -> AnnotationUtils.findAnnotation(field, Column.class) != null) + .map(ColumnInfo::new) + .forEach(this.columns::add); + + Arrays.stream(cls.getDeclaredFields()) + .filter(field -> AnnotationUtils.findAnnotation(field, ColumnMap.class) != null) + .map(MapColumnInfo::new) + .forEach(this.mapColumns::add); + + this.getColumns().stream() + .filter(ColumnInfo::isPrimaryKey) + .forEach(this.primaryKeys::add); + + this.getMapColumns().stream() + .map(MapColumnInfo::getJoin) + .map(join -> { + String lf = join.onLeft(); + String rf = join.onRight(); + String lt = this.getTableNameT(); + String rt = join.target(); + if (StringUtils.isEmpty(lf) || StringUtils.isEmpty(rf)) { + lf = join.on(); + rf = join.on(); + } + return QueryUtil.getJoinSql(lt, rt, lf, rf); + }) + .forEach(joinSql::add); + + if (this.enableTableMap != null) { + if (StringUtils.isNotEmpty(this.enableTableMap.user())) { + String lf = this.enableTableMap.userOnLeft(); + String rf = this.enableTableMap.userOnRight(); + String lt = this.getTableNameT(); + String rt = this.enableTableMap.user(); + if (StringUtils.isEmpty(lf) || StringUtils.isEmpty(rf)) { + lf = this.enableTableMap.userOn(); + rf = this.enableTableMap.userOn(); + } + this.joinSql.add("sys_user " + QueryUtil.getJoinSql(lt, rt, lf, rf)); + this.hasDataScopeValue = true; + } + + if (StringUtils.isNotEmpty(this.enableTableMap.dept())) { + String lf = this.enableTableMap.deptOnLeft(); + String rf = this.enableTableMap.deptOnRight(); + String lt = StringUtils.isNotEmpty(this.enableTableMap.deptFrom()) ? this.enableTableMap.deptFrom() + : this.getTableNameT(); + String rt = this.enableTableMap.dept(); + if (StringUtils.isEmpty(lf) || StringUtils.isEmpty(rf)) { + lf = this.enableTableMap.deptOn(); + rf = this.enableTableMap.deptOn(); + } + this.joinSql.add("sys_dept " + QueryUtil.getJoinSql(lt, rt, lf, rf)); + this.hasDataScopeValue = true; + } + } + } + + public String[] getOrderBy() { + return this.table.orderBy(); + } + + public boolean hasDataScope() { + return this.hasDataScopeValue; + } + + public Set getJoinSql() { + return this.joinSql; + } + + public Boolean isEnbleMap() { + return this.enableTableMap != null; + } + + public String getTableNameT() { + return this.enableTableMap.name(); + } + + public String getTableNameFrom() { + if (this.isEnbleMap()){ + return this.tableName + " " + this.enableTableMap.name(); + }else{ + return this.tableName; + } + } + + public List getQueryColumnNames() { + List columns = Arrays.asList(this.table.columns()); + if (columns.size() <= 0) { + columns = this.columns.stream() + .map(ColumnInfo::getColumnName) + .collect(Collectors.toList()); + } + if (this.isEnbleMap()) { + columns = columns.stream() + .map(column -> this.getTableNameT() + "." + column) + .collect(Collectors.toList()); + this.mapColumns.stream() + .map(MapColumnInfo::getFullyQualifiedColumnName) + .forEach(columns::add); + } + + return columns; + + } + + public List getColumnNames() { + List columns = this.columns.stream() + .map(ColumnInfo::getColumnName) + .collect(Collectors.toList()); + + if (this.isEnbleMap()) { + columns = columns.stream() + .map(column -> this.getTableNameT() + "." + column) + .collect(Collectors.toList()); + this.mapColumns.stream() + .map(MapColumnInfo::getFullyQualifiedColumnName) + .forEach(columns::add); + } + + return columns; + } + + public List getColumns() { + return columns; + } + + public List getMapColumns() { + return mapColumns; + } + + public List getNotNullColumnsForQuery(T entity) { + return this.columns.stream() + .filter(column -> column.fieldQueryIsNotNull(entity)) + .collect(Collectors.toList()); + } + + public List getNotNullColumns(T entity) { + return this.columns.stream() + .filter(column -> column.fieldIsNotNull(entity)) + .collect(Collectors.toList()); + } + + public List getNotNullMapColumnsForQuery(T entity) { + return this.mapColumns.stream() + .filter(column -> column.fieldQueryIsNotNull(entity)) + .collect(Collectors.toList()); + } + + public List getNotNullMapColumns(T entity) { + return this.mapColumns.stream() + .filter(column -> column.fieldIsNotNull(entity)) + .collect(Collectors.toList()); + } + + public List getPrimaryKeys() { + return primaryKeys; + } + + public String getTableName() { + return tableName; + } + +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/enums/QueryEnum.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/enums/QueryEnum.java new file mode 100644 index 0000000..f42576f --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/enums/QueryEnum.java @@ -0,0 +1,29 @@ +package com.boyue.mybatis.enums; + +/** + * 数据库查询枚举 + * + * @author Dftre + */ +public enum QueryEnum { + eq, // 等于 = + ne, // 不等于 <> + gt, // 大于 > + ge, // 大于等于 >= + lt, // 小于 < + le, // 小于等于 <= + like, // 模糊查询 + notLike, + likeLeft, // 左模糊查询 + likeRight, // 右模糊查询 + notLikeLeft, + notLikeRight, + in, // in + notIn, // not in + between, // between and + notBetween, // not between and + isNull, //is null + isNotNull, + inSql, + notInSql; +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/mapper/JPAMapper.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/mapper/JPAMapper.java new file mode 100644 index 0000000..615fc58 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/mapper/JPAMapper.java @@ -0,0 +1,30 @@ +package com.boyue.mybatis.mapper; + +import java.util.List; + +import org.apache.ibatis.annotations.DeleteProvider; +import org.apache.ibatis.annotations.InsertProvider; +import org.apache.ibatis.annotations.Options; +import org.apache.ibatis.annotations.SelectProvider; +import org.apache.ibatis.annotations.UpdateProvider; + +import com.boyue.common.core.domain.BaseEntity; +import com.boyue.mybatis.utils.SQLGenerator; + +public interface JPAMapper { + @SelectProvider(value = SQLGenerator.class, method = SQLGenerator.Method.SELECT_BY_ID) + public T selectById(T entity); + + @SelectProvider(value = SQLGenerator.class, method = SQLGenerator.Method.LIST) + public List selectList(T entity); + + @InsertProvider(value = SQLGenerator.class, method = SQLGenerator.Method.INSERT) + @Options(useGeneratedKeys = true) + public int insert(T entity); + + @UpdateProvider(value = SQLGenerator.class, method = SQLGenerator.Method.UPDATE) + public int update(T entity); + + @DeleteProvider(value = SQLGenerator.class, method = SQLGenerator.Method.DELETE_BY_ID) + public int deleteById(T entity); +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/service/JPAService.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/service/JPAService.java new file mode 100644 index 0000000..3f6e807 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/service/JPAService.java @@ -0,0 +1,18 @@ +package com.boyue.mybatis.service; + +import java.util.List; + +import com.boyue.common.core.domain.BaseEntity; + +public interface JPAService { + + public T get(T entity); + + public List list(T entity); + + public int add(T entity); + + public int update(T entity); + + public int del(T entity); +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/service/impl/JPAServiceImpl.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/service/impl/JPAServiceImpl.java new file mode 100644 index 0000000..387bf26 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/service/impl/JPAServiceImpl.java @@ -0,0 +1,40 @@ +package com.boyue.mybatis.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.boyue.common.core.domain.BaseEntity; +import com.boyue.mybatis.mapper.JPAMapper; +import com.boyue.mybatis.service.JPAService; + +public class JPAServiceImpl implements JPAService { + + @Autowired + private JPAMapper mapper; + + @Override + public T get(T entity) { + return mapper.selectById(entity); + }; + + @Override + public List list(T entity) { + return mapper.selectList(entity); + } + + @Override + public int add(T entity) { + return mapper.insert(entity); + } + + @Override + public int update(T entity) { + return mapper.update(entity); + } + + @Override + public int del(T entity) { + return mapper.deleteById(entity); + } +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/utils/QueryUtil.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/utils/QueryUtil.java new file mode 100644 index 0000000..1e8265c --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/utils/QueryUtil.java @@ -0,0 +1,105 @@ +package com.boyue.mybatis.utils; + +import java.io.Serializable; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import com.boyue.common.core.domain.BaseEntity; +import com.boyue.mybatis.annotation.Query; + +public class QueryUtil { + + /** + * 判断该字段是否可以被列为查询条件 + * @param entity 参与判断的对象 + * @param field 参与判断的字段 + * @param query 参与判断的查询注解 + * @return + */ + public static boolean fieldQueryIsNotNull(Object entity, Field field, Query query) { + try { + if (query == null)return false; + BaseEntity baseEntity = (BaseEntity) entity; + Map map = baseEntity.getParams(); + return switch(query.operation()){ + case between -> map.get(query.sections()[0]) != null && map.get(query.sections()[1]) != null; + case in -> { + Object section = map.get(query.section()); + if (section == null) yield false; + if (section instanceof String) { + List list = new ArrayList<>(); + for (String split : ((String) section).split(",")) { + list.add("\"" + split + "\""); + } + map.put(query.section() + "_operation", String.join(",", list)); + yield true; + } else if (section instanceof Collection) { + List list = new ArrayList<>(); + for (Object split : ((Collection) section)) { + list.add("\"" + split.toString() + "\""); + } + map.put(query.section() + "_operation", String.join(",", list)); + yield true; + } else { + yield false; + } + } + default ->field.get(entity) != null; + }; + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to access field for building query conditions.", e); + } + } + + public static String getJoinSql(String leftTable, String rightTable, String leftField, String rightField) { + return rightTable + " on " + + leftTable + "." + leftField + " = " + + rightTable + "." + rightField; + } + + public static String getQuerySql(String column, String iField, Query query) { + if (query == null) + return ""; + String begin = "#{params." + query.sections()[0] + "}"; + String end = "#{params." + query.sections()[1] + "}"; + String inParams = "${params." + query.section() + "_operation" + "}"; + return switch (query.operation()) { + case eq -> column + " = " + iField; + case ne -> column + " <> " + iField; + case gt -> column + " > " + iField; + case ge -> column + " >= " + iField; + case le -> column + " < " + iField; + case lt -> column + " <= " + iField; + case between -> column + " between " + begin + " and " + end; + case notBetween -> column + " not between " + begin + " and " + end; + case like -> column + " like concat('%'," + iField + ",'%')"; + case notLike -> column + "not like concat('%'," + iField + ",'%')"; + case likeLeft -> column + "like concat('%'," + iField + ")"; + case likeRight -> column + "like concat(" + iField + ",'%')"; + case notLikeLeft -> column + "not like concat('%'," + iField + ")"; + case notLikeRight -> column + "not like concat(" + iField + ",'%')"; + case isNull -> column + " is null"; + case isNotNull -> column + " is not null"; + case in -> column + " in (" + inParams + ")"; + case notIn -> column + " not in (" + inParams + ")"; + case inSql -> column + " in (" + query.sql() + ")"; + case notInSql -> column + " not in (" + query.sql() + ")"; + default -> throw new IllegalArgumentException( + "Unsupported operation: " + query.operation()); + }; + } + + public static String listToInSQL(Collection oList) { + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (Serializable o : oList) { + sb.append(o).append(","); + } + sb.deleteCharAt(sb.length() - 1); + sb.append(")"); + return sb.toString(); + } +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/utils/QueryWrapperUtil.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/utils/QueryWrapperUtil.java new file mode 100644 index 0000000..556e618 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/utils/QueryWrapperUtil.java @@ -0,0 +1,84 @@ +package com.boyue.mybatis.utils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.boyue.common.core.domain.BaseEntity; +import com.boyue.mybatis.annotation.Query; +import com.boyue.mybatis.domain.TableInfo; + +public class QueryWrapperUtil { + public static List getArrayFromParam(Object obj) { + List list = new ArrayList<>(); + if (obj instanceof String) { + for (String split : ((String) obj).split(",")) { + list.add(split); + } + } else if (obj instanceof Collection) { + for (Object split : ((Collection) obj)) { + list.add(split.toString()); + } + } + return list; + } + + public static QueryWrapper initQueryWrapper(T entity) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + TableInfo tableInfo = TableContainer.getTableInfo(entity); + Map params = entity.getParams(); + + tableInfo.getNotNullColumnsForQuery(entity).stream() + .forEach(field -> { + Object fieldValue = null; + try { + fieldValue = field.getField().get(entity); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + Query queryAnnotation = field.getQuery(); + switch (queryAnnotation.operation()) { + case eq -> queryWrapper.eq(field.getUnqualifiedColumnName(), fieldValue); + case ne -> queryWrapper.ne(field.getUnqualifiedColumnName(), fieldValue); + case gt -> queryWrapper.gt(field.getUnqualifiedColumnName(), fieldValue); + case ge -> queryWrapper.ge(field.getUnqualifiedColumnName(), fieldValue); + case le -> queryWrapper.le(field.getUnqualifiedColumnName(), fieldValue); + case lt -> queryWrapper.lt(field.getUnqualifiedColumnName(), fieldValue); + case between -> { + String begin = queryAnnotation.sections()[0]; + String end = queryAnnotation.sections()[1]; + queryWrapper.between(field.getUnqualifiedColumnName(), params.get(begin), params.get(end)); + } + case notBetween -> { + String begin = queryAnnotation.sections()[0]; + String end = queryAnnotation.sections()[1]; + queryWrapper.notBetween(field.getUnqualifiedColumnName(), params.get(begin), + params.get(end)); + } + case like -> queryWrapper.like(field.getUnqualifiedColumnName(), fieldValue); + case notLike -> queryWrapper.notLike(field.getUnqualifiedColumnName(), fieldValue); + case likeLeft -> queryWrapper.likeLeft(field.getUnqualifiedColumnName(), fieldValue); + case likeRight -> queryWrapper.likeRight(field.getUnqualifiedColumnName(), fieldValue); + case notLikeLeft -> queryWrapper.notLikeLeft(field.getUnqualifiedColumnName(), fieldValue); + case notLikeRight -> queryWrapper.notLikeRight(field.getUnqualifiedColumnName(), fieldValue); + case isNull -> queryWrapper.isNull(field.getUnqualifiedColumnName()); + case isNotNull -> queryWrapper.isNotNull(field.getUnqualifiedColumnName()); + case in -> queryWrapper.in(field.getUnqualifiedColumnName(), + getArrayFromParam(params.get(queryAnnotation.section()))); + case notIn -> queryWrapper.notIn(field.getUnqualifiedColumnName(), + getArrayFromParam(params.get(queryAnnotation.section()))); + case inSql -> queryWrapper.inSql(field.getUnqualifiedColumnName(), queryAnnotation.sql()); + case notInSql -> queryWrapper.notInSql(field.getUnqualifiedColumnName(), queryAnnotation.sql()); + default -> + throw new IllegalArgumentException( + "Unsupported operation: " + queryAnnotation.operation()); + } + }); + + return queryWrapper; + } +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/utils/SQLGenerator.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/utils/SQLGenerator.java new file mode 100644 index 0000000..4e8eac4 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/utils/SQLGenerator.java @@ -0,0 +1,196 @@ +package com.boyue.mybatis.utils; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Collection; + +import org.apache.ibatis.jdbc.SQL; + +import com.boyue.common.core.domain.BaseEntity; +import com.boyue.common.utils.StringUtils; +import com.boyue.mybatis.domain.ColumnInfo; +import com.boyue.mybatis.domain.MapColumnInfo; +import com.boyue.mybatis.domain.TableInfo; + +public class SQLGenerator { + + public static class Method { + public final static String LIST = "list"; + public final static String INSERT = "insert"; + public final static String UPDATE = "update"; + public final static String SELECT_BY_ID = "selectById"; + public final static String DELETE_BY_ID = "deleteById"; + public final static String SELECT_BY_IDS = "selectByIds"; + public final static String DELETE_BY_IDS = "deleteByIds"; + public final static String SELECT_BY_ID_WITH_ENTITY = "selectByIdWithEntity"; + public final static String DELETE_BY_ID_WITH_ENTITY = "deleteByIdWithEntity"; + } + + public static String list(T entity) { + SQL sql = new SQL(); + TableInfo tableInfo = TableContainer.getTableInfo(entity); + sql.SELECT(String.join(",", tableInfo.getQueryColumnNames())) + .FROM(tableInfo.getTableNameFrom()); + + if (tableInfo.isEnbleMap()) { + tableInfo.getJoinSql().stream() + .filter(StringUtils::isNotEmpty) + .forEach(sql::LEFT_OUTER_JOIN); + tableInfo.getNotNullMapColumnsForQuery(entity).stream() + .map(MapColumnInfo::getQuerySql) + .forEach(sql::WHERE); + tableInfo.getNotNullColumnsForQuery(entity).stream() + .map(ColumnInfo::getQuerySql) + .map(query -> tableInfo.getTableNameT() + "." + query) + .forEach(sql::WHERE); + if (tableInfo.hasDataScope()) { + sql.WHERE("1=1 ${params.dataScope}"); + } + + Arrays.stream(tableInfo.getOrderBy()) + .filter(StringUtils::isNotEmpty) + .map(order -> tableInfo.getTableNameT() + "." + order) + .forEach(sql::ORDER_BY); + } else { + tableInfo.getNotNullColumnsForQuery(entity).stream() + .map(ColumnInfo::getQuerySql) + .filter(StringUtils::isNotEmpty) + .forEach(sql::WHERE); + Arrays.stream(tableInfo.getOrderBy()) + .filter(StringUtils::isNotEmpty) + .forEach(sql::ORDER_BY); + } + return sql.toString(); + } + + public static String insert(T entity) { + SQL sql = new SQL(); + TableInfo tableInfo = TableContainer.getTableInfo(entity); + sql.INSERT_INTO(tableInfo.getTableName()); + tableInfo.getNotNullColumns(entity).stream() + .forEach(column -> sql.VALUES(column.getColumnName(), column.getTemplate())); + return sql.toString(); + } + + public static String update(T entity) { + SQL sql = new SQL(); + TableInfo tableInfo = TableContainer.getTableInfo(entity); + sql.UPDATE(tableInfo.getTableName()); + tableInfo.getPrimaryKeys().stream() + .map(column -> column.getColumnName() + " = " + column.getTemplate()) + .forEach(sql::WHERE); + if (tableInfo.hasDataScope()) { + sql.WHERE("1=1 ${params.dataScope}"); + } + tableInfo.getNotNullColumns(entity).stream() + .filter(column -> !column.isPrimaryKey()) + .map(column -> column.getColumnName() + " = " + column.getTemplate()) + .forEach(sql::SET); + return sql.toString(); + } + + public static String deleteByIdWithEntity(T entity) { + SQL sql = new SQL(); + TableInfo tableInfo = TableContainer.getTableInfo(entity); + sql.DELETE_FROM(tableInfo.getTableName()); + tableInfo.getPrimaryKeys().stream() + .map(column -> column.getColumnName() + " = " + column.getTemplate()) + .forEach(sql::WHERE); + + if (tableInfo.hasDataScope()) { + sql.WHERE("1=1 ${params.dataScope}"); + } + return sql.toString(); + } + + public static String selectByIdWithEntity(T entity) { + SQL sql = new SQL(); + TableInfo tableInfo = TableContainer.getTableInfo(entity); + sql.SELECT(String.join(",", tableInfo.getColumnNames())) + .FROM(tableInfo.getTableNameFrom()); + if (tableInfo.isEnbleMap()) { + tableInfo.getJoinSql().stream() + .forEach(sql::LEFT_OUTER_JOIN); + + tableInfo.getPrimaryKeys().stream() + .map(column -> tableInfo.getTableNameT() + "." + column.getColumnName() + " = " + + column.getTemplate()) + .forEach(sql::WHERE); + } else { + tableInfo.getPrimaryKeys().stream() + .map(column -> column.getColumnName() + " = " + column.getTemplate()) + .forEach(sql::WHERE); + } + if (tableInfo.hasDataScope()) { + sql.WHERE("1=1 ${params.dataScope}"); + } + return sql.toString(); + } + + public static String selectById(Serializable id, Class clz) { + SQL sql = new SQL(); + TableInfo tableInfo = TableContainer.getTableInfo(clz); + sql.SELECT(String.join(",", tableInfo.getColumnNames())) + .FROM(tableInfo.getTableNameFrom()); + if (tableInfo.isEnbleMap()) { + tableInfo.getJoinSql().stream().forEach(sql::LEFT_OUTER_JOIN); + ColumnInfo columnInfo = tableInfo.getPrimaryKeys().get(0); + String columnName = tableInfo.getTableNameT() + "." + columnInfo.getColumnName(); + sql.WHERE(columnName + " = " + id); + } else { + ColumnInfo columnInfo = tableInfo.getPrimaryKeys().get(0); + sql.WHERE(columnInfo.getColumnName() + " = " + id); + } + if (tableInfo.hasDataScope()) { + sql.WHERE("1=1 ${params.dataScope}"); + } + return sql.toString(); + } + + public static String selectByIds(Collection ids, Class clz) { + SQL sql = new SQL(); + TableInfo tableInfo = TableContainer.getTableInfo(clz); + sql.SELECT(String.join(",", tableInfo.getColumnNames())) + .FROM(tableInfo.getTableNameFrom()); + if (tableInfo.isEnbleMap()) { + tableInfo.getJoinSql().stream() + .forEach(sql::LEFT_OUTER_JOIN); + + ColumnInfo columnInfo = tableInfo.getPrimaryKeys().get(0); + String columnName = tableInfo.getTableNameT() + "." + columnInfo.getColumnName(); + sql.WHERE(columnName + " in " + QueryUtil.listToInSQL(ids)); + } else { + ColumnInfo columnInfo = tableInfo.getPrimaryKeys().get(0); + sql.WHERE(columnInfo.getColumnName() + " in " + QueryUtil.listToInSQL(ids)); + } + if (tableInfo.hasDataScope()) { + sql.WHERE("1=1 ${params.dataScope}"); + } + return sql.toString(); + } + + public static String deleteById(Serializable id, Class clz) { + SQL sql = new SQL(); + TableInfo tableInfo = TableContainer.getTableInfo(clz); + sql.DELETE_FROM(tableInfo.getTableName()); + ColumnInfo columnInfo = tableInfo.getPrimaryKeys().get(0); + sql.WHERE(columnInfo.getColumnName() + " = " + id); + if (tableInfo.hasDataScope()) { + sql.WHERE("1=1 ${params.dataScope}"); + } + return sql.toString(); + } + + public static String deleteByIds(Collection ids, Class clz) { + SQL sql = new SQL(); + TableInfo tableInfo = TableContainer.getTableInfo(clz); + sql.DELETE_FROM(tableInfo.getTableName()); + ColumnInfo columnInfo = tableInfo.getPrimaryKeys().get(0); + sql.WHERE(columnInfo.getColumnName() + " in " + QueryUtil.listToInSQL(ids)); + if (tableInfo.hasDataScope()) { + sql.WHERE("1=1 ${params.dataScope}"); + } + return sql.toString(); + } + +} diff --git a/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/utils/TableContainer.java b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/utils/TableContainer.java new file mode 100644 index 0000000..167eed8 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-jpa/src/main/java/com/boyue/mybatis/utils/TableContainer.java @@ -0,0 +1,31 @@ +package com.boyue.mybatis.utils; + +import java.util.HashMap; +import java.util.Map; + +import com.boyue.common.core.domain.BaseEntity; +import com.boyue.mybatis.domain.TableInfo; + +/** + * sql构建工具 + * + * @author Dftre + */ +public class TableContainer { + + private static final Map, TableInfo> tableInfoMap = new HashMap<>(); + + public static TableInfo getTableInfo(T entity) { + Class clazz = entity.getClass(); + return getTableInfo(clazz); + } + + public static TableInfo getTableInfo(Class clazz) { + TableInfo tableInfo = tableInfoMap.get(clazz); + if (tableInfo == null) { + tableInfo = new TableInfo(clazz); + } + return tableInfo; + } + +} diff --git a/boyue-plugins/boyue-mybatis-plus/pom.xml b/boyue-plugins/boyue-mybatis-plus/pom.xml new file mode 100644 index 0000000..76a9c0e --- /dev/null +++ b/boyue-plugins/boyue-mybatis-plus/pom.xml @@ -0,0 +1,32 @@ + + + + boyue-plugins + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-mybatis-plus + + + boyue-mybatis-plus模块 + + + + + + + com.boyue + boyue-common + + + + + com.baomidou + mybatis-plus-spring-boot3-starter + + + + diff --git a/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/config/MybatisPlusConfig.java b/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/config/MybatisPlusConfig.java new file mode 100644 index 0000000..e2801e1 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/config/MybatisPlusConfig.java @@ -0,0 +1,99 @@ +package com.boyue.mybatisplus.config; + +import javax.sql.DataSource; + +import org.apache.ibatis.io.VFS; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.session.SqlSessionFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.core.io.DefaultResourceLoader; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; +import com.github.pagehelper.PageInterceptor; +import com.github.pagehelper.autoconfigure.PageHelperStandardProperties; +import com.boyue.common.service.mybatis.CreateSqlSessionFactory; +import com.boyue.common.utils.MybatisUtils; +import com.boyue.common.utils.StringUtils; + +/** + * Mybatis Plus 配置 + * + * @author boyue + */ +@Configuration +public class MybatisPlusConfig { + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + // 分页插件 + interceptor.addInnerInterceptor(paginationInnerInterceptor()); + // 乐观锁插件 + interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor()); + // 阻断插件 + interceptor.addInnerInterceptor(blockAttackInnerInterceptor()); + return interceptor; + } + + /** + * 分页插件,自动识别数据库类型 https://baomidou.com/guide/interceptor-pagination.html + */ + public PaginationInnerInterceptor paginationInnerInterceptor() { + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(); + // 设置数据库类型为mysql + paginationInnerInterceptor.setDbType(DbType.MYSQL); + // 设置最大单页限制数量,默认 500 条,-1 不受限制 + paginationInnerInterceptor.setMaxLimit(-1L); + return paginationInnerInterceptor; + } + + /** + * 乐观锁插件 https://baomidou.com/guide/interceptor-optimistic-locker.html + */ + public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() { + return new OptimisticLockerInnerInterceptor(); + } + + /** + * 如果是对全表的删除或更新操作,就会终止该操作 + * https://baomidou.com/guide/interceptor-block-attack.html + */ + public BlockAttackInnerInterceptor blockAttackInnerInterceptor() { + return new BlockAttackInnerInterceptor(); + } + + @Bean + @ConditionalOnProperty(prefix = "createSqlSessionFactory", name = "use", havingValue = "mybatis-plus") + public CreateSqlSessionFactory createSqlSessionFactory(PageHelperStandardProperties packageHelperStandardProperties) { + return new CreateSqlSessionFactory() { + public SqlSessionFactory createSqlSessionFactory(Environment env, DataSource dataSource) throws Exception { + String typeAliasesPackage = env.getProperty("mybatis-plus.typeAliasesPackage"); + String mapperLocations = env.getProperty("mybatis-plus.mapperLocations"); + String configLocation = env.getProperty("mybatis-plus.configLocation"); + typeAliasesPackage = MybatisUtils.setTypeAliasesPackage(typeAliasesPackage); + VFS.addImplClass(SpringBootVFS.class); + + final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean(); + sessionFactory.setPlugins(new Interceptor[] { mybatisPlusInterceptor() }); + sessionFactory.setDataSource(dataSource); + sessionFactory.setTypeAliasesPackage(typeAliasesPackage); + sessionFactory.setMapperLocations( + MybatisUtils.resolveMapperLocations(StringUtils.split(mapperLocations, ","))); + sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation)); + PageInterceptor interceptor = new PageInterceptor(); + interceptor.setProperties(packageHelperStandardProperties.getProperties()); + sessionFactory.addPlugins(interceptor); + return sessionFactory.getObject(); + } + }; + } + +} diff --git a/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/controller/SysStudentController.java b/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/controller/SysStudentController.java new file mode 100644 index 0000000..2f1ac70 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/controller/SysStudentController.java @@ -0,0 +1,107 @@ +package com.boyue.mybatisplus.controller; + + +import java.util.Arrays; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.boyue.common.annotation.Log; +import com.boyue.common.core.controller.BaseController; +import com.boyue.common.core.domain.AjaxResult; +import com.boyue.common.core.page.TableDataInfo; +import com.boyue.common.enums.BusinessType; +import com.boyue.common.utils.poi.ExcelUtil; +import com.boyue.mybatisplus.domain.SysStudent; +import com.boyue.mybatisplus.service.ISysStudentService; + +/** + * 学生信息Controller + * + * @author boyue + */ +@RestController +@RequestMapping("/system/student") +public class SysStudentController extends BaseController +{ + @Autowired + private ISysStudentService sysStudentService; + + /** + * 查询学生信息列表 + */ + @PreAuthorize("@ss.hasPermi('system:student:list')") + @GetMapping("/list") + public TableDataInfo list(SysStudent sysStudent) + { + Page page = new Page(1,2); + List list = sysStudentService.list(page); + return getDataTable(list); + } + + /** + * 导出学生信息列表 + */ + @PreAuthorize("@ss.hasPermi('system:student:export')") + @Log(title = "学生信息", businessType = BusinessType.EXPORT) + @GetMapping("/export") + public AjaxResult export(SysStudent sysStudent) + { + List list = sysStudentService.queryList(sysStudent); + ExcelUtil util = new ExcelUtil(SysStudent.class); + return util.exportExcel(list, "student"); + } + + /** + * 获取学生信息详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:student:query')") + @GetMapping(value = "/{studentId}") + public AjaxResult getInfo(@PathVariable("studentId") Long studentId) + { + return AjaxResult.success(sysStudentService.getById(studentId)); + } + + /** + * 新增学生信息 + */ + @PreAuthorize("@ss.hasPermi('system:student:add')") + @Log(title = "学生信息", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody SysStudent sysStudent) + { + return toAjax(sysStudentService.save(sysStudent)); + } + + /** + * 修改学生信息 + */ + @PreAuthorize("@ss.hasPermi('system:student:edit')") + @Log(title = "学生信息", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody SysStudent sysStudent) + { + return toAjax(sysStudentService.updateById(sysStudent)); + } + + /** + * 删除学生信息 + */ + @PreAuthorize("@ss.hasPermi('system:student:remove')") + @Log(title = "学生信息", businessType = BusinessType.DELETE) + @DeleteMapping("/{studentIds}") + public AjaxResult remove(@PathVariable Long[] studentIds) + { + return toAjax(sysStudentService.removeByIds(Arrays.asList(studentIds))); + } +} \ No newline at end of file diff --git a/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/domain/SysStudent.java b/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/domain/SysStudent.java new file mode 100644 index 0000000..afd4b7f --- /dev/null +++ b/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/domain/SysStudent.java @@ -0,0 +1,132 @@ +package com.boyue.mybatisplus.domain; + +import java.io.Serializable; +import java.util.Date; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.boyue.common.annotation.Excel; + +/** + * 学生信息对象 sys_student + * + * @author boyue + */ +@TableName(value = "sys_student") +public class SysStudent implements Serializable +{ + @TableField(exist = false) + private static final long serialVersionUID = 1L; + + /** 编号 */ + @TableId(type = IdType.AUTO) + private Long studentId; + + /** 学生名称 */ + @Excel(name = "学生名称") + private String studentName; + + /** 年龄 */ + @Excel(name = "年龄") + private Integer studentAge; + + /** 爱好(0代码 1音乐 2电影) */ + @Excel(name = "爱好", readConverterExp = "0=代码,1=音乐,2=电影") + private String studentHobby; + + /** 性别(0男 1女 2未知) */ + @Excel(name = "性别", readConverterExp = "0=男,1=女,2=未知") + private String studentSex; + + /** 状态(0正常 1停用) */ + @Excel(name = "状态", readConverterExp = "0=正常,1=停用") + private String studentStatus; + + /** 生日 */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "生日", width = 30, dateFormat = "yyyy-MM-dd") + private Date studentBirthday; + + public void setStudentId(Long studentId) + { + this.studentId = studentId; + } + + public Long getStudentId() + { + return studentId; + } + public void setStudentName(String studentName) + { + this.studentName = studentName; + } + + public String getStudentName() + { + return studentName; + } + public void setStudentAge(Integer studentAge) + { + this.studentAge = studentAge; + } + + public Integer getStudentAge() + { + return studentAge; + } + public void setStudentHobby(String studentHobby) + { + this.studentHobby = studentHobby; + } + + public String getStudentHobby() + { + return studentHobby; + } + public void setStudentSex(String studentSex) + { + this.studentSex = studentSex; + } + + public String getStudentSex() + { + return studentSex; + } + public void setStudentStatus(String studentStatus) + { + this.studentStatus = studentStatus; + } + + public String getStudentStatus() + { + return studentStatus; + } + public void setStudentBirthday(Date studentBirthday) + { + this.studentBirthday = studentBirthday; + } + + public Date getStudentBirthday() + { + return studentBirthday; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("studentId", getStudentId()) + .append("studentName", getStudentName()) + .append("studentAge", getStudentAge()) + .append("studentHobby", getStudentHobby()) + .append("studentSex", getStudentSex()) + .append("studentStatus", getStudentStatus()) + .append("studentBirthday", getStudentBirthday()) + .toString(); + } +} \ No newline at end of file diff --git a/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/mapper/SysStudentMapper.java b/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/mapper/SysStudentMapper.java new file mode 100644 index 0000000..58f4bf1 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/mapper/SysStudentMapper.java @@ -0,0 +1,14 @@ +package com.boyue.mybatisplus.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.boyue.mybatisplus.domain.SysStudent; + +/** + * 学生信息Mapper接口 + * + * @author boyue + */ +public interface SysStudentMapper extends BaseMapper +{ + +} \ No newline at end of file diff --git a/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/service/ISysStudentService.java b/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/service/ISysStudentService.java new file mode 100644 index 0000000..fcd6d92 --- /dev/null +++ b/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/service/ISysStudentService.java @@ -0,0 +1,21 @@ +package com.boyue.mybatisplus.service; +import java.util.List; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.boyue.mybatisplus.domain.SysStudent; + +/** + * 学生信息Service接口 + * + * @author boyue + */ +public interface ISysStudentService extends IService +{ + /** + * 查询学生信息列表 + * + * @param sysStudent 学生信息 + * @return 学生信息集合 + */ + public List queryList(SysStudent sysStudent); +} \ No newline at end of file diff --git a/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/service/impl/SysStudentServiceImpl.java b/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/service/impl/SysStudentServiceImpl.java new file mode 100644 index 0000000..9452bdb --- /dev/null +++ b/boyue-plugins/boyue-mybatis-plus/src/main/java/com/boyue/mybatisplus/service/impl/SysStudentServiceImpl.java @@ -0,0 +1,43 @@ +package com.boyue.mybatisplus.service.impl; +import java.util.List; + +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.boyue.common.utils.StringUtils; +import com.boyue.mybatisplus.domain.SysStudent; +import com.boyue.mybatisplus.mapper.SysStudentMapper; +import com.boyue.mybatisplus.service.ISysStudentService; + +/** + * 学生信息Service业务层处理 + * + * @author boyue + */ +@Service +public class SysStudentServiceImpl extends ServiceImpl implements ISysStudentService +{ + @Override + public List queryList(SysStudent sysStudent) + { + // 注意:mybatis-plus lambda 模式不支持 eclipse 的编译器 + // LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + // queryWrapper.eq(SysStudent::getStudentName, sysStudent.getStudentName()); + QueryWrapper queryWrapper = Wrappers.query(); + if (StringUtils.isNotEmpty(sysStudent.getStudentName())) + { + queryWrapper.eq("student_name", sysStudent.getStudentName()); + } + if (StringUtils.isNotNull(sysStudent.getStudentAge())) + { + queryWrapper.eq("student_age", sysStudent.getStudentAge()); + } + if (StringUtils.isNotEmpty(sysStudent.getStudentHobby())) + { + queryWrapper.eq("student_hobby", sysStudent.getStudentHobby()); + } + return this.list(queryWrapper); + } +} \ No newline at end of file diff --git a/boyue-plugins/boyue-netty/pom.xml b/boyue-plugins/boyue-netty/pom.xml new file mode 100644 index 0000000..42715f7 --- /dev/null +++ b/boyue-plugins/boyue-netty/pom.xml @@ -0,0 +1,30 @@ + + + + boyue-plugins + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-netty + + + 19 + 19 + UTF-8 + + + + + io.netty + netty-all + + + com.boyue + boyue-common + + + diff --git a/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/NettyServerRunner.java b/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/NettyServerRunner.java new file mode 100644 index 0000000..86096c3 --- /dev/null +++ b/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/NettyServerRunner.java @@ -0,0 +1,28 @@ +package com.boyue.netty.websocket; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +import com.boyue.netty.websocket.nettyServer.NettyWebSocketServer; + +import jakarta.annotation.PreDestroy; + +@Component +public class NettyServerRunner implements ApplicationRunner { + + @Autowired + private NettyWebSocketServer server; + + @Override + public void run(ApplicationArguments args) throws Exception { + server.start(); + } + + @PreDestroy + public void destroy() { + server.shutdown(); + } + +} diff --git a/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/annotations/NettyWebSocketEndpoint.java b/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/annotations/NettyWebSocketEndpoint.java new file mode 100644 index 0000000..0338960 --- /dev/null +++ b/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/annotations/NettyWebSocketEndpoint.java @@ -0,0 +1,12 @@ +package com.boyue.netty.websocket.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface NettyWebSocketEndpoint { + String path(); +} diff --git a/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/endpoints/TestNettyWebSocket.java b/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/endpoints/TestNettyWebSocket.java new file mode 100644 index 0000000..3d0be2f --- /dev/null +++ b/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/endpoints/TestNettyWebSocket.java @@ -0,0 +1,44 @@ +package com.boyue.netty.websocket.endpoints; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.stereotype.Component; + +import com.boyue.netty.websocket.annotations.NettyWebSocketEndpoint; +import com.boyue.netty.websocket.nettyServer.NettyWebSocketEndpointHandler; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.FullHttpMessage; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; + +@Component +@NettyWebSocketEndpoint(path = "/test/{seqNumber}") +public class TestNettyWebSocket extends NettyWebSocketEndpointHandler { + + private static final Map map = new ConcurrentHashMap<>(); + + @Override + public void onMessage(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) { + System.out.println(textWebSocketFrame.text()); + } + + @Override + public void onOpen(ChannelHandlerContext channelHandlerContext, FullHttpMessage fullHttpMessage) { + map.put(getPathParam("seqNumber"), channelHandlerContext); + } + + @Override + public void onClose(ChannelHandlerContext channelHandlerContext) { + map.remove(getPathParam("seqNumber")); + } + + @Override + public void onError(ChannelHandlerContext channelHandlerContext, Throwable throwable) { + + } + + public static void send(String seqNumber, String msg) { + sendMsg(map.get(seqNumber), msg); + } +} diff --git a/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/nettyServer/NettyWebSocketEndpointHandler.java b/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/nettyServer/NettyWebSocketEndpointHandler.java new file mode 100644 index 0000000..17d18cf --- /dev/null +++ b/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/nettyServer/NettyWebSocketEndpointHandler.java @@ -0,0 +1,63 @@ +package com.boyue.netty.websocket.nettyServer; + +import java.util.Map; + +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.FullHttpMessage; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; + +public abstract class NettyWebSocketEndpointHandler { + + + private Map pathParam; + + private Map urlParam; + + + public static void sendMsg(ChannelHandlerContext context, String msg) { + TextWebSocketFrame textWebSocketFrame = new TextWebSocketFrame(msg); + context.channel().writeAndFlush(textWebSocketFrame); + } + + public abstract void onMessage(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame); + + public abstract void onOpen(ChannelHandlerContext channelHandlerContext, FullHttpMessage fullHttpMessage); + + public abstract void onClose(ChannelHandlerContext channelHandlerContext); + + public abstract void onError(ChannelHandlerContext channelHandlerContext, Throwable throwable); + + + public Map getPathParam() { + return pathParam; + } + + public void setPathParam(Map pathParam) { + this.pathParam = pathParam; + } + + public Map getUrlParam() { + return urlParam; + } + + public void setUrlParam(Map urlParam) { + this.urlParam = urlParam; + } + + public Long getLongPathParam(String key) { + return Long.valueOf(pathParam.get(key)); + } + + public String getPathParam(String key) { + return pathParam.get(key); + } + + public Double getDoublePathParam(String key) { + return Double.parseDouble(pathParam.get(key)); + } + + public void closeChannel(ChannelHandlerContext channelHandlerContext) { + channelHandlerContext.close().addListener(ChannelFutureListener.CLOSE); + } +} diff --git a/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/nettyServer/NettyWebSocketServer.java b/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/nettyServer/NettyWebSocketServer.java new file mode 100644 index 0000000..f0ef595 --- /dev/null +++ b/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/nettyServer/NettyWebSocketServer.java @@ -0,0 +1,89 @@ +package com.boyue.netty.websocket.nettyServer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import com.boyue.netty.websocket.nettyServer.handler.WebSocketHandler; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpServerCodec; +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; + +@Component +public class NettyWebSocketServer { + + private static final Logger log = LoggerFactory.getLogger(NettyWebSocketServer.class); + private ServerBootstrap serverBootstrap; + private Channel serverChannel; + + @Value("${netty.websocket.maxMessageSize}") + private Long messageSize; + + @Value("${netty.websocket.bossThreads}") + private Long bossThreads; + + @Value("${netty.websocket.workerThreads}") + private Long workerThreads; + + @Value("${netty.websocket.port}") + private Long port; + + @Value("${netty.websocket.enable}") + private Boolean enable; + + public ServerBootstrap start() throws InterruptedException { + if (!enable) { + return null; + } + ServerBootstrap serverBootstrap = new ServerBootstrap(); + NioEventLoopGroup boss = new NioEventLoopGroup(4); + NioEventLoopGroup worker = new NioEventLoopGroup(workerThreads.intValue()); + serverBootstrap.group(boss, worker); + serverBootstrap.channel(NioServerSocketChannel.class); + serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true); + serverBootstrap.childHandler(new ChannelInitializer() { + @Override + protected void initChannel(NioSocketChannel channel) throws Exception { + ChannelPipeline pipeline = channel.pipeline(); + pipeline.addLast(new HttpServerCodec()); + pipeline.addLast(new HttpObjectAggregator(messageSize.intValue())); + pipeline.addLast(new WebSocketHandler()); + pipeline.addLast(new WebSocketServerProtocolHandler("/", true)); + } + }); + ChannelFuture future = serverBootstrap.bind(port.intValue()).sync(); + serverChannel = future.channel(); + log.info("netty for websocket start success, running in port: {}", this.port); + this.serverBootstrap = serverBootstrap; + return this.serverBootstrap; + } + + public void shutdown() { + if (serverChannel != null) { + serverChannel.close().syncUninterruptibly(); + } + if (serverBootstrap != null) { + EventLoopGroup bossGroup = serverBootstrap.config().group(); + EventLoopGroup workerGroup = serverBootstrap.config().childGroup(); + if (bossGroup != null) { + bossGroup.shutdownGracefully().syncUninterruptibly(); + } + if (workerGroup != null) { + workerGroup.shutdownGracefully().syncUninterruptibly(); + } + } + log.info("netty for websocket shudown success"); + } +} diff --git a/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/nettyServer/handler/WebSocketHandler.java b/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/nettyServer/handler/WebSocketHandler.java new file mode 100644 index 0000000..9bf0772 --- /dev/null +++ b/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/nettyServer/handler/WebSocketHandler.java @@ -0,0 +1,167 @@ +package com.boyue.netty.websocket.nettyServer.handler; + +import java.util.concurrent.ConcurrentHashMap; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import com.boyue.common.utils.StringUtils; +import com.boyue.netty.websocket.annotations.NettyWebSocketEndpoint; +import com.boyue.netty.websocket.nettyServer.NettyWebSocketEndpointHandler; +import com.boyue.netty.websocket.utils.CommonUtil; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelId; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.group.ChannelGroup; +import io.netty.channel.group.DefaultChannelGroup; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import io.netty.util.concurrent.GlobalEventExecutor; +import jakarta.annotation.PostConstruct; + +import java.lang.reflect.Constructor; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; + +@Component +public class WebSocketHandler extends SimpleChannelInboundHandler { + + @Autowired + private List handlers; + + private static final Map uriHandlerMapper = new ConcurrentHashMap<>(); + + public static final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); + + public static final Map channelHandlerMap = new ConcurrentHashMap<>(); + + @PostConstruct + private void init() throws URISyntaxException, NoSuchMethodException, SecurityException { + for (NettyWebSocketEndpointHandler handler : handlers) { + Class handlerClass = handler.getClass(); + NettyWebSocketEndpoint annotation = handlerClass.getAnnotation(NettyWebSocketEndpoint.class); + if (annotation == null || StringUtils.isEmpty(annotation.path())) { + throw new RuntimeException("未配置路径的 netty websocket endpoint "); + } + // uriHandlerMap.put(uri.getPath(), handler); + PathMatchModel pathMachModel = parseHandler(annotation.path(), handlerClass); + uriHandlerMapper.put(pathMachModel.path, pathMachModel); + } + } + + @Override + protected void channelRead0(ChannelHandlerContext context, TextWebSocketFrame webSocketFrame) throws Exception { + NettyWebSocketEndpointHandler handler = channelHandlerMap.get(context.channel().id()); + handler.onMessage(context, webSocketFrame); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + channelGroup.add(ctx.channel()); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + NettyWebSocketEndpointHandler handler = channelHandlerMap.get(ctx.channel().id()); + if (handler != null) { + handler.onClose(ctx); + } + + channelHandlerMap.remove(ctx.channel().id()); + channelGroup.remove(ctx.channel()); + } + + @Override + public void channelRegistered(ChannelHandlerContext ctx) throws Exception { + + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + channelHandlerMap.get(ctx.channel().id()).onError(ctx, cause); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + if (msg instanceof FullHttpRequest) { + FullHttpRequest fullHttpRequest = (FullHttpRequest) msg; + if (channelHandlerMap.get(ctx.channel().id()) != null) { + super.channelRead(ctx, fullHttpRequest); + return; + } + URI uri = new URI(fullHttpRequest.uri()); + PathMatchModel mathPathMachModel = mathPathMachModel(uri.getPath()); + if (mathPathMachModel == null) { + ctx.channel() + .writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND)); + ctx.close().addListener(ChannelFutureListener.CLOSE); + return; + } + NettyWebSocketEndpointHandler newInstance = (NettyWebSocketEndpointHandler) mathPathMachModel.handlerConstructor + .newInstance(); + if (!(mathPathMachModel.pathParams == null || mathPathMachModel.pathParams.isEmpty())) { + newInstance.setPathParam( + CommonUtil.parsePathParam(uri.getPath(), mathPathMachModel.pathParams, mathPathMachModel.path)); + super.channelRead(ctx, msg); + } + newInstance.setUrlParam(CommonUtil.parseQueryParameters(uri.getQuery())); + + channelHandlerMap.put(ctx.channel().id(), newInstance); + newInstance.onOpen(ctx, fullHttpRequest); + } else if (msg instanceof TextWebSocketFrame) { + super.channelRead(ctx, msg); + } + + } + + private static PathMatchModel parseHandler(String path, Class handlerClass) + throws NoSuchMethodException, SecurityException { + List paramName = new ArrayList<>(); + String[] split = path.split("/"); + for (int index = 1; index < split.length; index++) { + String item = split[index]; + if (item.startsWith("{") && item.endsWith("}")) { + paramName.add(item.substring(1, item.length() - 1).trim()); + split[index] = "?"; + } + } + StringBuilder finalPath = new StringBuilder(""); + for (int index = 1; index < split.length; index++) { + finalPath.append("/").append(split[index]); + } + return new PathMatchModel(paramName, finalPath.toString(), handlerClass.getDeclaredConstructor()); + } + + private static PathMatchModel mathPathMachModel(String uri) { + Map map = new HashMap<>(); + for (String key : uriHandlerMapper.keySet()) { + int mathUri = CommonUtil.mathUri(uri, key); + if (mathUri > 0) { + map.put(mathUri, uriHandlerMapper.get(key)); + } + } + if (map.keySet() == null || map.keySet().isEmpty()) { + return null; + } + Integer max = CommonUtil.getMax(map.keySet()); + return map.get(max); + } + + private static final class PathMatchModel { + private final List pathParams; + + private final String path; + + private final Constructor handlerConstructor; + + public PathMatchModel(List pathParams, String path, Constructor handlerConstructor) { + this.pathParams = pathParams; + this.path = path; + this.handlerConstructor = handlerConstructor; + } + + } +} diff --git a/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/utils/CommonUtil.java b/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/utils/CommonUtil.java new file mode 100644 index 0000000..f42a5de --- /dev/null +++ b/boyue-plugins/boyue-netty/src/main/java/com/boyue/netty/websocket/utils/CommonUtil.java @@ -0,0 +1,78 @@ +package com.boyue.netty.websocket.utils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +public class CommonUtil { + + /** + * @param uri + * @param uriTemplates + * @return + */ + public static int mathUri(String uri, String uriTemplate) { + String[] uriSplit = uri.split("/"); + String[] tempalteSplit = uriTemplate.split("/"); + if (uriSplit.length != tempalteSplit.length) { + return -1; + } + int mathLevel = 0; + for (int index = 1; index < tempalteSplit.length; index++) { + if (tempalteSplit[index].equals("?")) { + mathLevel = mathLevel + index; + continue; + } + if (!tempalteSplit[index].equals(uriSplit[index])) { + return -1; + } else { + mathLevel = mathLevel + tempalteSplit.length + 1; + } + } + return mathLevel; + } + + public static Map parseQueryParameters(String query) { + if (query == null || query.isEmpty()) { + return Map.of(); + } + + Map params = new HashMap<>(); + String[] pairs = query.split("&"); + for (String pair : pairs) { + String[] keyValue = pair.split("="); + if (keyValue.length > 1) { + params.put(keyValue[0], keyValue[1]); + } else { + params.put(keyValue[0], ""); + } + } + return params; + } + + public static Map parsePathParam(String uri, List pathParams, String uriTemplate) { + int index = 0; + String[] split = uriTemplate.split("/"); + String[] split2 = uri.split("/"); + Map map = new HashMap<>(); + for (int i = 1; i < split.length; i++) { + if (split[i].equals("?")) { + map.put(pathParams.get(index), split2[i]); + index++; + } + } + return map; + } + + public static Integer getMax(Set set) { + Optional maxNumber = set.stream().max(Integer::compare); + if (maxNumber.isPresent()) { + System.out.println("Max number: " + maxNumber.get()); + } else { + System.out.println("The list is empty"); + } + return maxNumber.get(); + } +} diff --git a/boyue-plugins/boyue-plugins-starter/pom.xml b/boyue-plugins/boyue-plugins-starter/pom.xml new file mode 100644 index 0000000..016fbb2 --- /dev/null +++ b/boyue-plugins/boyue-plugins-starter/pom.xml @@ -0,0 +1,66 @@ + + + + boyue-plugins + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-plugins-starter + + + 中间件 + + + + + + + com.boyue + boyue-common + + + + + com.boyue + boyue-ehcache + + + + + com.boyue + boyue-websocket + + + + + com.boyue + boyue-mybatis-jpa + + + + + com.boyue + boyue-mybatis-plus + + + + com.boyue + boyue-mybatis-interceptor + + + + com.boyue + boyue-netty + + + + + + + diff --git a/boyue-plugins/boyue-websocket/pom.xml b/boyue-plugins/boyue-websocket/pom.xml new file mode 100644 index 0000000..7733196 --- /dev/null +++ b/boyue-plugins/boyue-websocket/pom.xml @@ -0,0 +1,31 @@ + + + + boyue-plugins + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-websocket + + + websocket系统模块 + + + + + com.boyue + boyue-common + + + + + org.springframework.boot + spring-boot-starter-websocket + + + + + diff --git a/boyue-plugins/boyue-websocket/src/main/java/com/boyue/websocket/SemaphoreUtils.java b/boyue-plugins/boyue-websocket/src/main/java/com/boyue/websocket/SemaphoreUtils.java new file mode 100644 index 0000000..fdc6caf --- /dev/null +++ b/boyue-plugins/boyue-websocket/src/main/java/com/boyue/websocket/SemaphoreUtils.java @@ -0,0 +1,59 @@ +package com.boyue.websocket; + +import java.util.concurrent.Semaphore; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 信号量相关处理 + * + * @author boyue + */ +public class SemaphoreUtils +{ + /** + * SemaphoreUtils 日志控制器 + */ + private static final Logger LOGGER = LoggerFactory.getLogger(SemaphoreUtils.class); + + /** + * 获取信号量 + * + * @param semaphore + * @return + */ + public static boolean tryAcquire(Semaphore semaphore) + { + boolean flag = false; + + try + { + flag = semaphore.tryAcquire(); + } + catch (Exception e) + { + LOGGER.error("获取信号量异常", e); + } + + return flag; + } + + /** + * 释放信号量 + * + * @param semaphore + */ + public static void release(Semaphore semaphore) + { + + try + { + semaphore.release(); + } + catch (Exception e) + { + LOGGER.error("释放信号量异常", e); + } + } +} diff --git a/boyue-plugins/boyue-websocket/src/main/java/com/boyue/websocket/WebSocketConfig.java b/boyue-plugins/boyue-websocket/src/main/java/com/boyue/websocket/WebSocketConfig.java new file mode 100644 index 0000000..7fdb7b9 --- /dev/null +++ b/boyue-plugins/boyue-websocket/src/main/java/com/boyue/websocket/WebSocketConfig.java @@ -0,0 +1,20 @@ +package com.boyue.websocket; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + +/** + * websocket 配置 + * + * @author boyue + */ +@Configuration +public class WebSocketConfig +{ + @Bean + public ServerEndpointExporter serverEndpointExporter() + { + return new ServerEndpointExporter(); + } +} diff --git a/boyue-plugins/boyue-websocket/src/main/java/com/boyue/websocket/WebSocketServer.java b/boyue-plugins/boyue-websocket/src/main/java/com/boyue/websocket/WebSocketServer.java new file mode 100644 index 0000000..09dbba6 --- /dev/null +++ b/boyue-plugins/boyue-websocket/src/main/java/com/boyue/websocket/WebSocketServer.java @@ -0,0 +1,105 @@ +package com.boyue.websocket; + +import java.util.concurrent.Semaphore; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import jakarta.websocket.OnClose; +import jakarta.websocket.OnError; +import jakarta.websocket.OnMessage; +import jakarta.websocket.OnOpen; +import jakarta.websocket.Session; +import jakarta.websocket.server.ServerEndpoint; + +/** + * websocket 消息处理 + * + * @author boyue + */ +@Component +@ServerEndpoint("/websocket/message") +public class WebSocketServer +{ + /** + * WebSocketServer 日志控制器 + */ + private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer.class); + + /** + * 默认最多允许同时在线人数100 + */ + public static int socketMaxOnlineCount = 100; + + private static Semaphore socketSemaphore = new Semaphore(socketMaxOnlineCount); + + /** + * 连接建立成功调用的方法 + */ + @OnOpen + public void onOpen(Session session) throws Exception + { + boolean semaphoreFlag = false; + // 尝试获取信号量 + semaphoreFlag = SemaphoreUtils.tryAcquire(socketSemaphore); + if (!semaphoreFlag) + { + // 未获取到信号量 + LOGGER.error("\n 当前在线人数超过限制数- {}", socketMaxOnlineCount); + WebSocketUsers.sendMessageToUserByText(session, "当前在线人数超过限制数:" + socketMaxOnlineCount); + session.close(); + } + else + { + // 添加用户 + WebSocketUsers.put(session.getId(), session); + LOGGER.info("\n 建立连接 - {}", session); + LOGGER.info("\n 当前人数 - {}", WebSocketUsers.getUsers().size()); + WebSocketUsers.sendMessageToUserByText(session, "连接成功"); + } + } + + /** + * 连接关闭时处理 + */ + @OnClose + public void onClose(Session session) + { + LOGGER.info("\n 关闭连接 - {}", session); + // 移除用户 + WebSocketUsers.remove(session.getId()); + // 获取到信号量则需释放 + SemaphoreUtils.release(socketSemaphore); + } + + /** + * 抛出异常时处理 + */ + @OnError + public void onError(Session session, Throwable exception) throws Exception + { + if (session.isOpen()) + { + // 关闭连接 + session.close(); + } + String sessionId = session.getId(); + LOGGER.info("\n 连接异常 - {}", sessionId); + LOGGER.info("\n 异常信息 - {}", exception); + // 移出用户 + WebSocketUsers.remove(sessionId); + // 获取到信号量则需释放 + SemaphoreUtils.release(socketSemaphore); + } + + /** + * 服务器接收到客户端消息时调用的方法 + */ + @OnMessage + public void onMessage(String message, Session session) + { + String msg = message.replace("你", "我").replace("吗", ""); + WebSocketUsers.sendMessageToUserByText(session, msg); + } +} diff --git a/boyue-plugins/boyue-websocket/src/main/java/com/boyue/websocket/WebSocketUsers.java b/boyue-plugins/boyue-websocket/src/main/java/com/boyue/websocket/WebSocketUsers.java new file mode 100644 index 0000000..46bd9a0 --- /dev/null +++ b/boyue-plugins/boyue-websocket/src/main/java/com/boyue/websocket/WebSocketUsers.java @@ -0,0 +1,142 @@ +package com.boyue.websocket; + +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.websocket.Session; + +/** + * websocket 客户端用户集 + * + * @author boyue + */ +public class WebSocketUsers +{ + /** + * WebSocketUsers 日志控制器 + */ + private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketUsers.class); + + /** + * 用户集 + */ + private static Map USERS = new ConcurrentHashMap(); + + /** + * 存储用户 + * + * @param key 唯一键 + * @param session 用户信息 + */ + public static void put(String key, Session session) + { + USERS.put(key, session); + } + + /** + * 移除用户 + * + * @param session 用户信息 + * + * @return 移除结果 + */ + public static boolean remove(Session session) + { + String key = null; + boolean flag = USERS.containsValue(session); + if (flag) + { + Set> entries = USERS.entrySet(); + for (Map.Entry entry : entries) + { + Session value = entry.getValue(); + if (value.equals(session)) + { + key = entry.getKey(); + break; + } + } + } + else + { + return true; + } + return remove(key); + } + + /** + * 移出用户 + * + * @param key 键 + */ + public static boolean remove(String key) + { + LOGGER.info("\n 正在移出用户 - {}", key); + Session remove = USERS.remove(key); + if (remove != null) + { + boolean containsValue = USERS.containsValue(remove); + LOGGER.info("\n 移出结果 - {}", containsValue ? "失败" : "成功"); + return containsValue; + } + else + { + return true; + } + } + + /** + * 获取在线用户列表 + * + * @return 返回用户集合 + */ + public static Map getUsers() + { + return USERS; + } + + /** + * 群发消息文本消息 + * + * @param message 消息内容 + */ + public static void sendMessageToUsersByText(String message) + { + Collection values = USERS.values(); + for (Session value : values) + { + sendMessageToUserByText(value, message); + } + } + + /** + * 发送文本消息 + * + * @param userName 自己的用户名 + * @param message 消息内容 + */ + public static void sendMessageToUserByText(Session session, String message) + { + if (session != null) + { + try + { + session.getBasicRemote().sendText(message); + } + catch (IOException e) + { + LOGGER.error("\n[发送消息异常]", e); + } + } + else + { + LOGGER.info("\n[你已离线]"); + } + } +} diff --git a/boyue-plugins/pom.xml b/boyue-plugins/pom.xml new file mode 100644 index 0000000..b02206a --- /dev/null +++ b/boyue-plugins/pom.xml @@ -0,0 +1,123 @@ + + + + boyuehasfj-java + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-plugins + + + 3.10.8 + 3.5.8 + 4.1.112.Final + 6.0.0 + + + + + + + + + + org.ehcache + ehcache + ${ehcache.version} + + + + com.baomidou + mybatis-plus-spring-boot3-starter + ${mybatis-plus.version} + + + + + com.boyue + boyue-ehcache + ${boyue.version} + + + + + com.boyue + boyue-mybatis-jpa + ${boyue.version} + + + + + com.boyue + boyue-mybatis-plus + ${boyue.version} + + + + + com.boyue + boyue-websocket + ${boyue.version} + + + + + com.boyue + boyue-plugins-starter + ${boyue.version} + + + + com.boyue + boyue-mybatis-interceptor + ${boyue.version} + + + + com.boyue + boyue-netty + ${boyue.version} + + + + io.netty + netty-all + ${netty.version} + + + + + + com.boyue + boyue-atomikos + ${boyue.version} + + + + + + + com.atomikos + transactions-spring-boot3-starter + ${transactions.version} + + + + + + + + boyue-ehcache + boyue-mybatis-jpa + boyue-mybatis-plus + boyue-websocket + boyue-plugins-starter + boyue-mybatis-interceptor + boyue-netty + boyue-atomikos + + pom + diff --git a/boyue-system/pom.xml b/boyue-system/pom.xml new file mode 100644 index 0000000..1a0a9eb --- /dev/null +++ b/boyue-system/pom.xml @@ -0,0 +1,28 @@ + + + + boyuehasfj-java + com.boyue + 3.8.9-G + + 4.0.0 + + boyue-system + + + system系统模块 + + + + + + + com.boyue + boyue-common + + + + + diff --git a/boyue-system/src/main/java/com/boyue/system/domain/SysCache.java b/boyue-system/src/main/java/com/boyue/system/domain/SysCache.java new file mode 100644 index 0000000..fb4779d --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/domain/SysCache.java @@ -0,0 +1,88 @@ +package com.boyue.system.domain; + +import com.boyue.common.utils.StringUtils; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 缓存信息 + * + * @author boyue + */ +@Schema(title = "缓存信息") +public class SysCache +{ + /** 缓存名称 */ + @Schema(title = "缓存名称") + private String cacheName = ""; + + /** 缓存键名 */ + @Schema(title = "缓存键名") + private String cacheKey = ""; + + /** 缓存内容 */ + @Schema(title = "缓存内容") + private String cacheValue = ""; + + /** 备注 */ + @Schema(title = "备注") + private String remark = ""; + + public SysCache() + { + + } + + public SysCache(String cacheName, String remark) + { + this.cacheName = cacheName; + this.remark = remark; + } + + public SysCache(String cacheName, String cacheKey, String cacheValue) + { + this.cacheName = StringUtils.replace(cacheName, ":", ""); + this.cacheKey = StringUtils.replace(cacheKey, cacheName, ""); + this.cacheValue = cacheValue; + } + + public String getCacheName() + { + return cacheName; + } + + public void setCacheName(String cacheName) + { + this.cacheName = cacheName; + } + + public String getCacheKey() + { + return cacheKey; + } + + public void setCacheKey(String cacheKey) + { + this.cacheKey = cacheKey; + } + + public String getCacheValue() + { + return cacheValue; + } + + public void setCacheValue(String cacheValue) + { + this.cacheValue = cacheValue; + } + + public String getRemark() + { + return remark; + } + + public void setRemark(String remark) + { + this.remark = remark; + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/domain/SysConfig.java b/boyue-system/src/main/java/com/boyue/system/domain/SysConfig.java new file mode 100644 index 0000000..c794a5a --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/domain/SysConfig.java @@ -0,0 +1,120 @@ +package com.boyue.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.annotation.Excel.ColumnType; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +/** + * 参数配置表 sys_config + * + * @author boyue + */ +@Schema(title = "参数配置表") +public class SysConfig extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 参数主键 */ + @Schema(title = "参数主键") + @Excel(name = "参数主键", cellType = ColumnType.NUMERIC) + private Long configId; + + /** 参数名称 */ + @Schema(title = "参数名称") + @Excel(name = "参数名称") + private String configName; + + /** 参数键名 */ + @Schema(title = "参数键名") + @Excel(name = "参数键名") + private String configKey; + + /** 参数键值 */ + @Schema(title = "参数键值") + @Excel(name = "参数键值") + private String configValue; + + /** 系统内置(Y是 N否) */ + @Schema(title = "系统内置") + @Excel(name = "系统内置", readConverterExp = "Y=是,N=否") + private String configType; + + public Long getConfigId() + { + return configId; + } + + public void setConfigId(Long configId) + { + this.configId = configId; + } + + @NotBlank(message = "参数名称不能为空") + @Size(min = 0, max = 100, message = "参数名称不能超过100个字符") + public String getConfigName() + { + return configName; + } + + public void setConfigName(String configName) + { + this.configName = configName; + } + + @NotBlank(message = "参数键名长度不能为空") + @Size(min = 0, max = 100, message = "参数键名长度不能超过100个字符") + public String getConfigKey() + { + return configKey; + } + + public void setConfigKey(String configKey) + { + this.configKey = configKey; + } + + @NotBlank(message = "参数键值不能为空") + @Size(min = 0, max = 500, message = "参数键值长度不能超过500个字符") + public String getConfigValue() + { + return configValue; + } + + public void setConfigValue(String configValue) + { + this.configValue = configValue; + } + + public String getConfigType() + { + return configType; + } + + public void setConfigType(String configType) + { + this.configType = configType; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("configId", getConfigId()) + .append("configName", getConfigName()) + .append("configKey", getConfigKey()) + .append("configValue", getConfigValue()) + .append("configType", getConfigType()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/domain/SysLogininfor.java b/boyue-system/src/main/java/com/boyue/system/domain/SysLogininfor.java new file mode 100644 index 0000000..7386d4b --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/domain/SysLogininfor.java @@ -0,0 +1,157 @@ +package com.boyue.system.domain; + +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.boyue.common.annotation.Excel; +import com.boyue.common.annotation.Excel.ColumnType; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 系统访问记录表 sys_logininfor + * + * @author boyue + */ +@Schema(title = "系统访问记录表") +public class SysLogininfor extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** ID */ + @Schema(title = "序号") + @Excel(name = "序号", cellType = ColumnType.NUMERIC) + private Long infoId; + + /** 用户账号 */ + @Schema(title = "用户账号") + @Excel(name = "用户账号") + private String userName; + + /** 登录状态 0成功 1失败 */ + @Schema(title = "登录状态") + @Excel(name = "登录状态", readConverterExp = "0=成功,1=失败") + private String status; + + /** 登录IP地址 */ + @Schema(title = "登录地址") + @Excel(name = "登录地址") + private String ipaddr; + + /** 登录地点 */ + @Schema(title = "登录地点") + @Excel(name = "登录地点") + private String loginLocation; + + /** 浏览器类型 */ + @Schema(title = "浏览器") + @Excel(name = "浏览器") + private String browser; + + /** 操作系统 */ + @Schema(title = "操作系统") + @Excel(name = "操作系统") + private String os; + + /** 提示消息 */ + @Schema(title = "提示消息") + @Excel(name = "提示消息") + private String msg; + + /** 访问时间 */ + @Schema(title = "访问时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "访问时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date loginTime; + + public Long getInfoId() + { + return infoId; + } + + public void setInfoId(Long infoId) + { + this.infoId = infoId; + } + + public String getUserName() + { + return userName; + } + + public void setUserName(String userName) + { + this.userName = userName; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getIpaddr() + { + return ipaddr; + } + + public void setIpaddr(String ipaddr) + { + this.ipaddr = ipaddr; + } + + public String getLoginLocation() + { + return loginLocation; + } + + public void setLoginLocation(String loginLocation) + { + this.loginLocation = loginLocation; + } + + public String getBrowser() + { + return browser; + } + + public void setBrowser(String browser) + { + this.browser = browser; + } + + public String getOs() + { + return os; + } + + public void setOs(String os) + { + this.os = os; + } + + public String getMsg() + { + return msg; + } + + public void setMsg(String msg) + { + this.msg = msg; + } + + public Date getLoginTime() + { + return loginTime; + } + + public void setLoginTime(Date loginTime) + { + this.loginTime = loginTime; + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/domain/SysNotice.java b/boyue-system/src/main/java/com/boyue/system/domain/SysNotice.java new file mode 100644 index 0000000..db577e6 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/domain/SysNotice.java @@ -0,0 +1,111 @@ +package com.boyue.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.core.domain.BaseEntity; +import com.boyue.common.xss.Xss; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +/** + * 通知公告表 sys_notice + * + * @author boyue + */ +@Schema(title = "系统访问记录表") +public class SysNotice extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 公告ID */ + @Schema(title = "公告ID") + private Long noticeId; + + /** 公告标题 */ + @Schema(title = "公告标题") + private String noticeTitle; + + /** 公告类型(1通知 2公告) */ + @Schema(title = "公告类型") + private String noticeType; + + /** 公告内容 */ + @Schema(title = "公告内容") + private String noticeContent; + + /** 公告状态(0正常 1关闭) */ + @Schema(title = "公告状态") + private String status; + + public Long getNoticeId() + { + return noticeId; + } + + public void setNoticeId(Long noticeId) + { + this.noticeId = noticeId; + } + + public void setNoticeTitle(String noticeTitle) + { + this.noticeTitle = noticeTitle; + } + + @Xss(message = "公告标题不能包含脚本字符") + @NotBlank(message = "公告标题不能为空") + @Size(min = 0, max = 50, message = "公告标题不能超过50个字符") + public String getNoticeTitle() + { + return noticeTitle; + } + + public void setNoticeType(String noticeType) + { + this.noticeType = noticeType; + } + + public String getNoticeType() + { + return noticeType; + } + + public void setNoticeContent(String noticeContent) + { + this.noticeContent = noticeContent; + } + + public String getNoticeContent() + { + return noticeContent; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getStatus() + { + return status; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("noticeId", getNoticeId()) + .append("noticeTitle", getNoticeTitle()) + .append("noticeType", getNoticeType()) + .append("noticeContent", getNoticeContent()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/domain/SysOperLog.java b/boyue-system/src/main/java/com/boyue/system/domain/SysOperLog.java new file mode 100644 index 0000000..3da4930 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/domain/SysOperLog.java @@ -0,0 +1,291 @@ +package com.boyue.system.domain; + +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.boyue.common.annotation.Excel; +import com.boyue.common.annotation.Excel.ColumnType; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 操作日志记录表 oper_log + * + * @author boyue + */ +@Schema(title = "操作日志记录表") +public class SysOperLog extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 日志主键 */ + @Schema(title = "操作序号") + @Excel(name = "操作序号", cellType = ColumnType.NUMERIC) + private Long operId; + + /** 操作模块 */ + @Schema(title = "操作模块") + @Excel(name = "操作模块") + private String title; + + /** 业务类型(0其它 1新增 2修改 3删除) */ + @Schema(title = "业务类型") + @Excel(name = "业务类型", readConverterExp = "0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据") + private Integer businessType; + + /** 业务类型数组 */ + @Schema(title = "业务类型数组") + private Integer[] businessTypes; + + /** 请求方法 */ + @Schema(title = "请求方法") + @Excel(name = "请求方法") + private String method; + + /** 请求方式 */ + @Schema(title = "请求方式") + @Excel(name = "请求方式") + private String requestMethod; + + /** 操作类别(0其它 1后台用户 2手机端用户) */ + @Schema(title = "操作类别") + @Excel(name = "操作类别", readConverterExp = "0=其它,1=后台用户,2=手机端用户") + private Integer operatorType; + + /** 操作人员 */ + @Schema(title = "操作人员") + @Excel(name = "操作人员") + private String operName; + + /** 部门名称 */ + @Schema(title = "部门名称") + @Excel(name = "部门名称") + private String deptName; + + /** 请求url */ + @Schema(title = "请求地址") + @Excel(name = "请求地址") + private String operUrl; + + /** 操作地址 */ + @Schema(title = "操作地址") + @Excel(name = "操作地址") + private String operIp; + + /** 操作地点 */ + @Schema(title = "操作地点") + @Excel(name = "操作地点") + private String operLocation; + + /** 请求参数 */ + @Schema(title = "请求参数") + @Excel(name = "请求参数") + private String operParam; + + /** 返回参数 */ + @Schema(title = "返回参数") + @Excel(name = "返回参数") + private String jsonResult; + + /** 操作状态(0正常 1异常) */ + @Schema(title = "操作状态") + @Excel(name = "操作状态", readConverterExp = "0=正常,1=异常") + private Integer status; + + /** 错误消息 */ + @Schema(title = "错误消息") + @Excel(name = "错误消息") + private String errorMsg; + + /** 操作时间 */ + @Schema(title = "操作时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date operTime; + + /** 消耗时间 */ + @Schema(title = "消耗时间") + @Excel(name = "消耗时间", suffix = "毫秒") + private Long costTime; + + public Long getOperId() + { + return operId; + } + + public void setOperId(Long operId) + { + this.operId = operId; + } + + public String getTitle() + { + return title; + } + + public void setTitle(String title) + { + this.title = title; + } + + public Integer getBusinessType() + { + return businessType; + } + + public void setBusinessType(Integer businessType) + { + this.businessType = businessType; + } + + public Integer[] getBusinessTypes() + { + return businessTypes; + } + + public void setBusinessTypes(Integer[] businessTypes) + { + this.businessTypes = businessTypes; + } + + public String getMethod() + { + return method; + } + + public void setMethod(String method) + { + this.method = method; + } + + public String getRequestMethod() + { + return requestMethod; + } + + public void setRequestMethod(String requestMethod) + { + this.requestMethod = requestMethod; + } + + public Integer getOperatorType() + { + return operatorType; + } + + public void setOperatorType(Integer operatorType) + { + this.operatorType = operatorType; + } + + public String getOperName() + { + return operName; + } + + public void setOperName(String operName) + { + this.operName = operName; + } + + public String getDeptName() + { + return deptName; + } + + public void setDeptName(String deptName) + { + this.deptName = deptName; + } + + public String getOperUrl() + { + return operUrl; + } + + public void setOperUrl(String operUrl) + { + this.operUrl = operUrl; + } + + public String getOperIp() + { + return operIp; + } + + public void setOperIp(String operIp) + { + this.operIp = operIp; + } + + public String getOperLocation() + { + return operLocation; + } + + public void setOperLocation(String operLocation) + { + this.operLocation = operLocation; + } + + public String getOperParam() + { + return operParam; + } + + public void setOperParam(String operParam) + { + this.operParam = operParam; + } + + public String getJsonResult() + { + return jsonResult; + } + + public void setJsonResult(String jsonResult) + { + this.jsonResult = jsonResult; + } + + public Integer getStatus() + { + return status; + } + + public void setStatus(Integer status) + { + this.status = status; + } + + public String getErrorMsg() + { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) + { + this.errorMsg = errorMsg; + } + + public Date getOperTime() + { + return operTime; + } + + public void setOperTime(Date operTime) + { + this.operTime = operTime; + } + + public Long getCostTime() + { + return costTime; + } + + public void setCostTime(Long costTime) + { + this.costTime = costTime; + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/domain/SysPost.java b/boyue-system/src/main/java/com/boyue/system/domain/SysPost.java new file mode 100644 index 0000000..04b577a --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/domain/SysPost.java @@ -0,0 +1,134 @@ +package com.boyue.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.boyue.common.annotation.Excel; +import com.boyue.common.annotation.Excel.ColumnType; +import com.boyue.common.core.domain.BaseEntity; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +/** + * 岗位表 sys_post + * + * @author boyue + */ +@Schema(title = "岗位表") +public class SysPost extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 岗位序号 */ + @Schema(title = "岗位序号") + @Excel(name = "岗位序号", cellType = ColumnType.NUMERIC) + private Long postId; + + /** 岗位编码 */ + @Schema(title = "岗位编码") + @Excel(name = "岗位编码") + private String postCode; + + /** 岗位名称 */ + @Schema(title = "岗位名称") + @Excel(name = "岗位名称") + private String postName; + + /** 岗位排序 */ + @Schema(title = "岗位排序") + @Excel(name = "岗位排序") + private Integer postSort; + + /** 状态(0正常 1停用) */ + @Schema(title = "状态") + @Excel(name = "状态", readConverterExp = "0=正常,1=停用") + private String status; + + /** 用户是否存在此岗位标识 默认不存在 */ + @Schema(title = "用户是否存在此岗位标识") + private boolean flag = false; + + public Long getPostId() + { + return postId; + } + + public void setPostId(Long postId) + { + this.postId = postId; + } + + @NotBlank(message = "岗位编码不能为空") + @Size(min = 0, max = 64, message = "岗位编码长度不能超过64个字符") + public String getPostCode() + { + return postCode; + } + + public void setPostCode(String postCode) + { + this.postCode = postCode; + } + + @NotBlank(message = "岗位名称不能为空") + @Size(min = 0, max = 50, message = "岗位名称长度不能超过50个字符") + public String getPostName() + { + return postName; + } + + public void setPostName(String postName) + { + this.postName = postName; + } + + @NotNull(message = "显示顺序不能为空") + public Integer getPostSort() + { + return postSort; + } + + public void setPostSort(Integer postSort) + { + this.postSort = postSort; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public boolean isFlag() + { + return flag; + } + + public void setFlag(boolean flag) + { + this.flag = flag; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("postId", getPostId()) + .append("postCode", getPostCode()) + .append("postName", getPostName()) + .append("postSort", getPostSort()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/domain/SysRoleDept.java b/boyue-system/src/main/java/com/boyue/system/domain/SysRoleDept.java new file mode 100644 index 0000000..ae2fa35 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/domain/SysRoleDept.java @@ -0,0 +1,51 @@ +package com.boyue.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 角色和部门关联 sys_role_dept + * + * @author boyue + */ +@Schema(title = "角色和部门关联") +public class SysRoleDept +{ + /** 角色ID */ + @Schema(title = "角色ID") + private Long roleId; + + /** 部门ID */ + @Schema(title = "部门ID") + private Long deptId; + + public Long getRoleId() + { + return roleId; + } + + public void setRoleId(Long roleId) + { + this.roleId = roleId; + } + + public Long getDeptId() + { + return deptId; + } + + public void setDeptId(Long deptId) + { + this.deptId = deptId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("roleId", getRoleId()) + .append("deptId", getDeptId()) + .toString(); + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/domain/SysRoleMenu.java b/boyue-system/src/main/java/com/boyue/system/domain/SysRoleMenu.java new file mode 100644 index 0000000..c70e04d --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/domain/SysRoleMenu.java @@ -0,0 +1,51 @@ +package com.boyue.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 角色和菜单关联 sys_role_menu + * + * @author boyue + */ +@Schema(title = "角色和菜单关联") +public class SysRoleMenu +{ + /** 角色ID */ + @Schema(title = "角色ID") + private Long roleId; + + /** 菜单ID */ + @Schema(title = "菜单ID") + private Long menuId; + + public Long getRoleId() + { + return roleId; + } + + public void setRoleId(Long roleId) + { + this.roleId = roleId; + } + + public Long getMenuId() + { + return menuId; + } + + public void setMenuId(Long menuId) + { + this.menuId = menuId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("roleId", getRoleId()) + .append("menuId", getMenuId()) + .toString(); + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/domain/SysUserOnline.java b/boyue-system/src/main/java/com/boyue/system/domain/SysUserOnline.java new file mode 100644 index 0000000..31b93ef --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/domain/SysUserOnline.java @@ -0,0 +1,124 @@ +package com.boyue.system.domain; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 当前在线会话 + * + * @author boyue + */ +@Schema(title = "当前在线会话") +public class SysUserOnline +{ + /** 会话编号 */ + @Schema(title = "会话编号") + private String tokenId; + + /** 部门名称 */ + @Schema(title = "部门名称") + private String deptName; + + /** 用户名称 */ + @Schema(title = "用户名称") + private String userName; + + /** 登录IP地址 */ + @Schema(title = "登录IP地址") + private String ipaddr; + + /** 登录地址 */ + @Schema(title = "登录地址") + private String loginLocation; + + /** 浏览器类型 */ + @Schema(title = "浏览器类型") + private String browser; + + /** 操作系统 */ + @Schema(title = "操作系统") + private String os; + + /** 登录时间 */ + @Schema(title = "登录时间") + private Long loginTime; + + public String getTokenId() + { + return tokenId; + } + + public void setTokenId(String tokenId) + { + this.tokenId = tokenId; + } + + public String getDeptName() + { + return deptName; + } + + public void setDeptName(String deptName) + { + this.deptName = deptName; + } + + public String getUserName() + { + return userName; + } + + public void setUserName(String userName) + { + this.userName = userName; + } + + public String getIpaddr() + { + return ipaddr; + } + + public void setIpaddr(String ipaddr) + { + this.ipaddr = ipaddr; + } + + public String getLoginLocation() + { + return loginLocation; + } + + public void setLoginLocation(String loginLocation) + { + this.loginLocation = loginLocation; + } + + public String getBrowser() + { + return browser; + } + + public void setBrowser(String browser) + { + this.browser = browser; + } + + public String getOs() + { + return os; + } + + public void setOs(String os) + { + this.os = os; + } + + public Long getLoginTime() + { + return loginTime; + } + + public void setLoginTime(Long loginTime) + { + this.loginTime = loginTime; + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/domain/SysUserPost.java b/boyue-system/src/main/java/com/boyue/system/domain/SysUserPost.java new file mode 100644 index 0000000..497b4b7 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/domain/SysUserPost.java @@ -0,0 +1,51 @@ +package com.boyue.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 用户和岗位关联 sys_user_post + * + * @author boyue + */ +@Schema(title = "用户和岗位关联") +public class SysUserPost +{ + /** 用户ID */ + @Schema(title = "用户ID") + private Long userId; + + /** 岗位ID */ + @Schema(title = "岗位ID") + private Long postId; + + public Long getUserId() + { + return userId; + } + + public void setUserId(Long userId) + { + this.userId = userId; + } + + public Long getPostId() + { + return postId; + } + + public void setPostId(Long postId) + { + this.postId = postId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("userId", getUserId()) + .append("postId", getPostId()) + .toString(); + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/domain/SysUserRole.java b/boyue-system/src/main/java/com/boyue/system/domain/SysUserRole.java new file mode 100644 index 0000000..9303da2 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/domain/SysUserRole.java @@ -0,0 +1,51 @@ +package com.boyue.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * 用户和角色关联 sys_user_role + * + * @author boyue + */ +@Schema(title = "用户和角色关联") +public class SysUserRole +{ + /** 用户ID */ + @Schema(title = "用户ID") + private Long userId; + + /** 角色ID */ + @Schema(title = "角色ID") + private Long roleId; + + public Long getUserId() + { + return userId; + } + + public void setUserId(Long userId) + { + this.userId = userId; + } + + public Long getRoleId() + { + return roleId; + } + + public void setRoleId(Long roleId) + { + this.roleId = roleId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("userId", getUserId()) + .append("roleId", getRoleId()) + .toString(); + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/domain/vo/MetaVo.java b/boyue-system/src/main/java/com/boyue/system/domain/vo/MetaVo.java new file mode 100644 index 0000000..69f65fb --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/domain/vo/MetaVo.java @@ -0,0 +1,106 @@ +package com.boyue.system.domain.vo; + +import com.boyue.common.utils.StringUtils; + +/** + * 路由显示信息 + * + * @author boyue + */ +public class MetaVo +{ + /** + * 设置该路由在侧边栏和面包屑中展示的名字 + */ + private String title; + + /** + * 设置该路由的图标,对应路径src/assets/icons/svg + */ + private String icon; + + /** + * 设置为true,则不会被 缓存 + */ + private boolean noCache; + + /** + * 内链地址(http(s)://开头) + */ + private String link; + + public MetaVo() + { + } + + public MetaVo(String title, String icon) + { + this.title = title; + this.icon = icon; + } + + public MetaVo(String title, String icon, boolean noCache) + { + this.title = title; + this.icon = icon; + this.noCache = noCache; + } + + public MetaVo(String title, String icon, String link) + { + this.title = title; + this.icon = icon; + this.link = link; + } + + public MetaVo(String title, String icon, boolean noCache, String link) + { + this.title = title; + this.icon = icon; + this.noCache = noCache; + if (StringUtils.ishttp(link)) + { + this.link = link; + } + } + + public boolean isNoCache() + { + return noCache; + } + + public void setNoCache(boolean noCache) + { + this.noCache = noCache; + } + + public String getTitle() + { + return title; + } + + public void setTitle(String title) + { + this.title = title; + } + + public String getIcon() + { + return icon; + } + + public void setIcon(String icon) + { + this.icon = icon; + } + + public String getLink() + { + return link; + } + + public void setLink(String link) + { + this.link = link; + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/domain/vo/RouterVo.java b/boyue-system/src/main/java/com/boyue/system/domain/vo/RouterVo.java new file mode 100644 index 0000000..fe59802 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/domain/vo/RouterVo.java @@ -0,0 +1,148 @@ +package com.boyue.system.domain.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import java.util.List; + +/** + * 路由配置信息 + * + * @author boyue + */ +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class RouterVo +{ + /** + * 路由名字 + */ + private String name; + + /** + * 路由地址 + */ + private String path; + + /** + * 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现 + */ + private boolean hidden; + + /** + * 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 + */ + private String redirect; + + /** + * 组件地址 + */ + private String component; + + /** + * 路由参数:如 {"id": 1, "name": "ry"} + */ + private String query; + + /** + * 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 + */ + private Boolean alwaysShow; + + /** + * 其他元素 + */ + private MetaVo meta; + + /** + * 子路由 + */ + private List children; + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public String getPath() + { + return path; + } + + public void setPath(String path) + { + this.path = path; + } + + public boolean getHidden() + { + return hidden; + } + + public void setHidden(boolean hidden) + { + this.hidden = hidden; + } + + public String getRedirect() + { + return redirect; + } + + public void setRedirect(String redirect) + { + this.redirect = redirect; + } + + public String getComponent() + { + return component; + } + + public void setComponent(String component) + { + this.component = component; + } + + public String getQuery() + { + return query; + } + + public void setQuery(String query) + { + this.query = query; + } + + public Boolean getAlwaysShow() + { + return alwaysShow; + } + + public void setAlwaysShow(Boolean alwaysShow) + { + this.alwaysShow = alwaysShow; + } + + public MetaVo getMeta() + { + return meta; + } + + public void setMeta(MetaVo meta) + { + this.meta = meta; + } + + public List getChildren() + { + return children; + } + + public void setChildren(List children) + { + this.children = children; + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/mapper/SysConfigMapper.java b/boyue-system/src/main/java/com/boyue/system/mapper/SysConfigMapper.java new file mode 100644 index 0000000..7a103a0 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/mapper/SysConfigMapper.java @@ -0,0 +1,76 @@ +package com.boyue.system.mapper; + +import java.util.List; +import com.boyue.system.domain.SysConfig; + +/** + * 参数配置 数据层 + * + * @author boyue + */ +public interface SysConfigMapper +{ + /** + * 查询参数配置信息 + * + * @param config 参数配置信息 + * @return 参数配置信息 + */ + public SysConfig selectConfig(SysConfig config); + + /** + * 通过ID查询配置 + * + * @param configId 参数ID + * @return 参数配置信息 + */ + public SysConfig selectConfigById(Long configId); + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + public List selectConfigList(SysConfig config); + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数键名 + * @return 参数配置信息 + */ + public SysConfig checkConfigKeyUnique(String configKey); + + /** + * 新增参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + public int insertConfig(SysConfig config); + + /** + * 修改参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + public int updateConfig(SysConfig config); + + /** + * 删除参数配置 + * + * @param configId 参数ID + * @return 结果 + */ + public int deleteConfigById(Long configId); + + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + * @return 结果 + */ + public int deleteConfigByIds(Long[] configIds); +} diff --git a/boyue-system/src/main/java/com/boyue/system/mapper/SysDeptMapper.java b/boyue-system/src/main/java/com/boyue/system/mapper/SysDeptMapper.java new file mode 100644 index 0000000..6653c24 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/mapper/SysDeptMapper.java @@ -0,0 +1,118 @@ +package com.boyue.system.mapper; + +import java.util.List; +import org.apache.ibatis.annotations.Param; +import com.boyue.common.core.domain.entity.SysDept; + +/** + * 部门管理 数据层 + * + * @author boyue + */ +public interface SysDeptMapper +{ + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + public List selectDeptList(SysDept dept); + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @param deptCheckStrictly 部门树选择项是否关联显示 + * @return 选中部门列表 + */ + public List selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly); + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + public SysDept selectDeptById(Long deptId); + + /** + * 根据ID查询所有子部门 + * + * @param deptId 部门ID + * @return 部门列表 + */ + public List selectChildrenDeptById(Long deptId); + + /** + * 根据ID查询所有子部门(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + public int selectNormalChildrenDeptById(Long deptId); + + /** + * 是否存在子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + public int hasChildByDeptId(Long deptId); + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 + */ + public int checkDeptExistUser(Long deptId); + + /** + * 校验部门名称是否唯一 + * + * @param deptName 部门名称 + * @param parentId 父部门ID + * @return 结果 + */ + public SysDept checkDeptNameUnique(@Param("deptName") String deptName, @Param("parentId") Long parentId); + + /** + * 新增部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int insertDept(SysDept dept); + + /** + * 修改部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int updateDept(SysDept dept); + + /** + * 修改所在部门正常状态 + * + * @param deptIds 部门ID组 + */ + public void updateDeptStatusNormal(Long[] deptIds); + + /** + * 修改子元素关系 + * + * @param depts 子元素 + * @return 结果 + */ + public int updateDeptChildren(@Param("depts") List depts); + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + public int deleteDeptById(Long deptId); +} diff --git a/boyue-system/src/main/java/com/boyue/system/mapper/SysDictDataMapper.java b/boyue-system/src/main/java/com/boyue/system/mapper/SysDictDataMapper.java new file mode 100644 index 0000000..d7a3fd1 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/mapper/SysDictDataMapper.java @@ -0,0 +1,95 @@ +package com.boyue.system.mapper; + +import java.util.List; +import org.apache.ibatis.annotations.Param; +import com.boyue.common.core.domain.entity.SysDictData; + +/** + * 字典表 数据层 + * + * @author boyue + */ +public interface SysDictDataMapper +{ + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + public List selectDictDataList(SysDictData dictData); + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + public List selectDictDataByType(String dictType); + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + public String selectDictLabel(@Param("dictType") String dictType, @Param("dictValue") String dictValue); + + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + public SysDictData selectDictDataById(Long dictCode); + + /** + * 查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据 + */ + public int countDictDataByType(String dictType); + + /** + * 通过字典ID删除字典数据信息 + * + * @param dictCode 字典数据ID + * @return 结果 + */ + public int deleteDictDataById(Long dictCode); + + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + * @return 结果 + */ + public int deleteDictDataByIds(Long[] dictCodes); + + /** + * 新增字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + public int insertDictData(SysDictData dictData); + + /** + * 修改字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + public int updateDictData(SysDictData dictData); + + /** + * 同步修改字典类型 + * + * @param oldDictType 旧字典类型 + * @param newDictType 新旧字典类型 + * @return 结果 + */ + public int updateDictDataType(@Param("oldDictType") String oldDictType, @Param("newDictType") String newDictType); +} diff --git a/boyue-system/src/main/java/com/boyue/system/mapper/SysDictTypeMapper.java b/boyue-system/src/main/java/com/boyue/system/mapper/SysDictTypeMapper.java new file mode 100644 index 0000000..a22e8ab --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/mapper/SysDictTypeMapper.java @@ -0,0 +1,83 @@ +package com.boyue.system.mapper; + +import java.util.List; +import com.boyue.common.core.domain.entity.SysDictType; + +/** + * 字典表 数据层 + * + * @author boyue + */ +public interface SysDictTypeMapper +{ + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + public List selectDictTypeList(SysDictType dictType); + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + public List selectDictTypeAll(); + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + public SysDictType selectDictTypeById(Long dictId); + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + public SysDictType selectDictTypeByType(String dictType); + + /** + * 通过字典ID删除字典信息 + * + * @param dictId 字典ID + * @return 结果 + */ + public int deleteDictTypeById(Long dictId); + + /** + * 批量删除字典类型信息 + * + * @param dictIds 需要删除的字典ID + * @return 结果 + */ + public int deleteDictTypeByIds(Long[] dictIds); + + /** + * 新增字典类型信息 + * + * @param dictType 字典类型信息 + * @return 结果 + */ + public int insertDictType(SysDictType dictType); + + /** + * 修改字典类型信息 + * + * @param dictType 字典类型信息 + * @return 结果 + */ + public int updateDictType(SysDictType dictType); + + /** + * 校验字典类型称是否唯一 + * + * @param dictType 字典类型 + * @return 结果 + */ + public SysDictType checkDictTypeUnique(String dictType); +} diff --git a/boyue-system/src/main/java/com/boyue/system/mapper/SysLogininforMapper.java b/boyue-system/src/main/java/com/boyue/system/mapper/SysLogininforMapper.java new file mode 100644 index 0000000..a894a11 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/mapper/SysLogininforMapper.java @@ -0,0 +1,42 @@ +package com.boyue.system.mapper; + +import java.util.List; +import com.boyue.system.domain.SysLogininfor; + +/** + * 系统访问日志情况信息 数据层 + * + * @author boyue + */ +public interface SysLogininforMapper +{ + /** + * 新增系统登录日志 + * + * @param logininfor 访问日志对象 + */ + public void insertLogininfor(SysLogininfor logininfor); + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + public List selectLogininforList(SysLogininfor logininfor); + + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + public int deleteLogininforByIds(Long[] infoIds); + + /** + * 清空系统登录日志 + * + * @return 结果 + */ + public int cleanLogininfor(); +} diff --git a/boyue-system/src/main/java/com/boyue/system/mapper/SysMenuMapper.java b/boyue-system/src/main/java/com/boyue/system/mapper/SysMenuMapper.java new file mode 100644 index 0000000..5ed4157 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/mapper/SysMenuMapper.java @@ -0,0 +1,125 @@ +package com.boyue.system.mapper; + +import java.util.List; +import org.apache.ibatis.annotations.Param; +import com.boyue.common.core.domain.entity.SysMenu; + +/** + * 菜单表 数据层 + * + * @author boyue + */ +public interface SysMenuMapper +{ + /** + * 查询系统菜单列表 + * + * @param menu 菜单信息 + * @return 菜单列表 + */ + public List selectMenuList(SysMenu menu); + + /** + * 根据用户所有权限 + * + * @return 权限列表 + */ + public List selectMenuPerms(); + + /** + * 根据用户查询系统菜单列表 + * + * @param menu 菜单信息 + * @return 菜单列表 + */ + public List selectMenuListByUserId(SysMenu menu); + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + public List selectMenuPermsByRoleId(Long roleId); + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + public List selectMenuPermsByUserId(Long userId); + + /** + * 根据用户ID查询菜单 + * + * @return 菜单列表 + */ + public List selectMenuTreeAll(); + + /** + * 根据用户ID查询菜单 + * + * @param userId 用户ID + * @return 菜单列表 + */ + public List selectMenuTreeByUserId(Long userId); + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @param menuCheckStrictly 菜单树选择项是否关联显示 + * @return 选中菜单列表 + */ + public List selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly); + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + public SysMenu selectMenuById(Long menuId); + + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int hasChildByMenuId(Long menuId); + + /** + * 新增菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int insertMenu(SysMenu menu); + + /** + * 修改菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int updateMenu(SysMenu menu); + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int deleteMenuById(Long menuId); + + /** + * 校验菜单名称是否唯一 + * + * @param menuName 菜单名称 + * @param parentId 父菜单ID + * @return 结果 + */ + public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId); +} diff --git a/boyue-system/src/main/java/com/boyue/system/mapper/SysNoticeMapper.java b/boyue-system/src/main/java/com/boyue/system/mapper/SysNoticeMapper.java new file mode 100644 index 0000000..176c08c --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/mapper/SysNoticeMapper.java @@ -0,0 +1,60 @@ +package com.boyue.system.mapper; + +import java.util.List; +import com.boyue.system.domain.SysNotice; + +/** + * 通知公告表 数据层 + * + * @author boyue + */ +public interface SysNoticeMapper +{ + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + public SysNotice selectNoticeById(Long noticeId); + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + public List selectNoticeList(SysNotice notice); + + /** + * 新增公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int insertNotice(SysNotice notice); + + /** + * 修改公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int updateNotice(SysNotice notice); + + /** + * 批量删除公告 + * + * @param noticeId 公告ID + * @return 结果 + */ + public int deleteNoticeById(Long noticeId); + + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + public int deleteNoticeByIds(Long[] noticeIds); +} diff --git a/boyue-system/src/main/java/com/boyue/system/mapper/SysOperLogMapper.java b/boyue-system/src/main/java/com/boyue/system/mapper/SysOperLogMapper.java new file mode 100644 index 0000000..fb80738 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/mapper/SysOperLogMapper.java @@ -0,0 +1,70 @@ +package com.boyue.system.mapper; + +import java.util.List; +import java.util.Map; + +import com.boyue.system.domain.SysOperLog; + +/** + * 操作日志 数据层 + * + * @author boyue + */ +public interface SysOperLogMapper +{ + /** + * 新增操作日志 + * + * @param operLog 操作日志对象 + */ + public void insertOperlog(SysOperLog operLog); + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + public List selectOperLogList(SysOperLog operLog); + + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + public int deleteOperLogByIds(Long[] operIds); + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + public SysOperLog selectOperLogById(Long operId); + + /** + * 清空操作日志 + */ + public void cleanOperLog(); + + /** + * 获取成功操作的统计信息 + */ + public List> getSuccessOperationStats(SysOperLog operLog); + + /** + * 获取失败操作的统计信息 + */ + public List> getFailureOperationStats(SysOperLog operLog); + + /** + * 获取按状态分类的操作统计信息 + */ + public List> getStatusStats(SysOperLog operLog); + + /** + * 获取按模块和操作类型分类的操作统计信息 + */ + public List> getModuleOperationStats(SysOperLog operLog); +} diff --git a/boyue-system/src/main/java/com/boyue/system/mapper/SysPostMapper.java b/boyue-system/src/main/java/com/boyue/system/mapper/SysPostMapper.java new file mode 100644 index 0000000..a321c92 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/mapper/SysPostMapper.java @@ -0,0 +1,99 @@ +package com.boyue.system.mapper; + +import java.util.List; +import com.boyue.system.domain.SysPost; + +/** + * 岗位信息 数据层 + * + * @author boyue + */ +public interface SysPostMapper +{ + /** + * 查询岗位数据集合 + * + * @param post 岗位信息 + * @return 岗位数据集合 + */ + public List selectPostList(SysPost post); + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + public List selectPostAll(); + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + public SysPost selectPostById(Long postId); + + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + public List selectPostListByUserId(Long userId); + + /** + * 查询用户所属岗位组 + * + * @param userName 用户名 + * @return 结果 + */ + public List selectPostsByUserName(String userName); + + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + public int deletePostById(Long postId); + + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 结果 + */ + public int deletePostByIds(Long[] postIds); + + /** + * 修改岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + public int updatePost(SysPost post); + + /** + * 新增岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + public int insertPost(SysPost post); + + /** + * 校验岗位名称 + * + * @param postName 岗位名称 + * @return 结果 + */ + public SysPost checkPostNameUnique(String postName); + + /** + * 校验岗位编码 + * + * @param postCode 岗位编码 + * @return 结果 + */ + public SysPost checkPostCodeUnique(String postCode); +} diff --git a/boyue-system/src/main/java/com/boyue/system/mapper/SysRoleDeptMapper.java b/boyue-system/src/main/java/com/boyue/system/mapper/SysRoleDeptMapper.java new file mode 100644 index 0000000..33fd011 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/mapper/SysRoleDeptMapper.java @@ -0,0 +1,44 @@ +package com.boyue.system.mapper; + +import java.util.List; +import com.boyue.system.domain.SysRoleDept; + +/** + * 角色与部门关联表 数据层 + * + * @author boyue + */ +public interface SysRoleDeptMapper +{ + /** + * 通过角色ID删除角色和部门关联 + * + * @param roleId 角色ID + * @return 结果 + */ + public int deleteRoleDeptByRoleId(Long roleId); + + /** + * 批量删除角色部门关联信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteRoleDept(Long[] ids); + + /** + * 查询部门使用数量 + * + * @param deptId 部门ID + * @return 结果 + */ + public int selectCountRoleDeptByDeptId(Long deptId); + + /** + * 批量新增角色部门信息 + * + * @param roleDeptList 角色部门列表 + * @return 结果 + */ + public int batchRoleDept(List roleDeptList); +} diff --git a/boyue-system/src/main/java/com/boyue/system/mapper/SysRoleMapper.java b/boyue-system/src/main/java/com/boyue/system/mapper/SysRoleMapper.java new file mode 100644 index 0000000..300ae41 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/mapper/SysRoleMapper.java @@ -0,0 +1,107 @@ +package com.boyue.system.mapper; + +import java.util.List; +import com.boyue.common.core.domain.entity.SysRole; + +/** + * 角色表 数据层 + * + * @author boyue + */ +public interface SysRoleMapper +{ + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + public List selectRoleList(SysRole role); + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + public List selectRolePermissionByUserId(Long userId); + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + public List selectRoleAll(); + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + public List selectRoleListByUserId(Long userId); + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + public SysRole selectRoleById(Long roleId); + + /** + * 根据用户ID查询角色 + * + * @param userName 用户名 + * @return 角色列表 + */ + public List selectRolesByUserName(String userName); + + /** + * 校验角色名称是否唯一 + * + * @param roleName 角色名称 + * @return 角色信息 + */ + public SysRole checkRoleNameUnique(String roleName); + + /** + * 校验角色权限是否唯一 + * + * @param roleKey 角色权限 + * @return 角色信息 + */ + public SysRole checkRoleKeyUnique(String roleKey); + + /** + * 修改角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int updateRole(SysRole role); + + /** + * 新增角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int insertRole(SysRole role); + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + public int deleteRoleById(Long roleId); + + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + public int deleteRoleByIds(Long[] roleIds); +} diff --git a/boyue-system/src/main/java/com/boyue/system/mapper/SysRoleMenuMapper.java b/boyue-system/src/main/java/com/boyue/system/mapper/SysRoleMenuMapper.java new file mode 100644 index 0000000..210e296 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/mapper/SysRoleMenuMapper.java @@ -0,0 +1,44 @@ +package com.boyue.system.mapper; + +import java.util.List; +import com.boyue.system.domain.SysRoleMenu; + +/** + * 角色与菜单关联表 数据层 + * + * @author boyue + */ +public interface SysRoleMenuMapper +{ + /** + * 查询菜单使用数量 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int checkMenuExistRole(Long menuId); + + /** + * 通过角色ID删除角色和菜单关联 + * + * @param roleId 角色ID + * @return 结果 + */ + public int deleteRoleMenuByRoleId(Long roleId); + + /** + * 批量删除角色菜单关联信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteRoleMenu(Long[] ids); + + /** + * 批量新增角色菜单信息 + * + * @param roleMenuList 角色菜单列表 + * @return 结果 + */ + public int batchRoleMenu(List roleMenuList); +} diff --git a/boyue-system/src/main/java/com/boyue/system/mapper/SysUserMapper.java b/boyue-system/src/main/java/com/boyue/system/mapper/SysUserMapper.java new file mode 100644 index 0000000..757e827 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/mapper/SysUserMapper.java @@ -0,0 +1,144 @@ +package com.boyue.system.mapper; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.boyue.common.core.domain.entity.SysUser; + +/** + * 用户表 数据层 + * + * @author boyue + */ +public interface SysUserMapper { + /** + * 根据条件分页查询用户列表 + * + * @param sysUser 用户信息 + * @return 用户信息集合信息 + */ + public List selectUserList(SysUser sysUser); + + /** + * 根据条件分页查询已配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List selectAllocatedList(SysUser user); + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List selectUnallocatedList(SysUser user); + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + public SysUser selectUserByUserName(String userName); + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + public SysUser selectUserById(Long userId); + + /** + * 通过手机号查询用户 + * + * @param phone 手机号 + * @return 用户对象信息 + */ + public SysUser selectUserByPhone(String phone); + + /** + * 通过邮箱查询用户 + * + * @param email 邮箱 + * @return 用户对象信息 + */ + public SysUser selectUserByEmail(String email); + + /** + * 新增用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int insertUser(SysUser user); + + /** + * 修改用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int updateUser(SysUser user); + + /** + * 修改用户头像 + * + * @param userName 用户名 + * @param avatar 头像地址 + * @return 结果 + */ + public int updateUserAvatar(@Param("userName") String userName, @Param("avatar") String avatar); + + /** + * 重置用户密码 + * + * @param userName 用户名 + * @param password 密码 + * @return 结果 + */ + public int resetUserPwd(@Param("userName") String userName, @Param("password") String password); + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + public int deleteUserById(Long userId); + + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + public int deleteUserByIds(Long[] userIds); + + /** + * 校验用户名称是否唯一 + * + * @param userName 用户名称 + * @return 结果 + */ + public SysUser checkUserNameUnique(String userName); + + /** + * 校验手机号码是否唯一 + * + * @param phonenumber 手机号码 + * @return 结果 + */ + public SysUser checkPhoneUnique(String phonenumber); + + /** + * 校验email是否唯一 + * + * @param email 用户邮箱 + * @return 结果 + */ + public SysUser checkEmailUnique(String email); +} diff --git a/boyue-system/src/main/java/com/boyue/system/mapper/SysUserPostMapper.java b/boyue-system/src/main/java/com/boyue/system/mapper/SysUserPostMapper.java new file mode 100644 index 0000000..d4f93bf --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/mapper/SysUserPostMapper.java @@ -0,0 +1,44 @@ +package com.boyue.system.mapper; + +import java.util.List; +import com.boyue.system.domain.SysUserPost; + +/** + * 用户与岗位关联表 数据层 + * + * @author boyue + */ +public interface SysUserPostMapper +{ + /** + * 通过用户ID删除用户和岗位关联 + * + * @param userId 用户ID + * @return 结果 + */ + public int deleteUserPostByUserId(Long userId); + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + public int countUserPostById(Long postId); + + /** + * 批量删除用户和岗位关联 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteUserPost(Long[] ids); + + /** + * 批量新增用户岗位信息 + * + * @param userPostList 用户岗位列表 + * @return 结果 + */ + public int batchUserPost(List userPostList); +} diff --git a/boyue-system/src/main/java/com/boyue/system/mapper/SysUserRoleMapper.java b/boyue-system/src/main/java/com/boyue/system/mapper/SysUserRoleMapper.java new file mode 100644 index 0000000..9686c41 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/mapper/SysUserRoleMapper.java @@ -0,0 +1,62 @@ +package com.boyue.system.mapper; + +import java.util.List; +import org.apache.ibatis.annotations.Param; +import com.boyue.system.domain.SysUserRole; + +/** + * 用户与角色关联表 数据层 + * + * @author boyue + */ +public interface SysUserRoleMapper +{ + /** + * 通过用户ID删除用户和角色关联 + * + * @param userId 用户ID + * @return 结果 + */ + public int deleteUserRoleByUserId(Long userId); + + /** + * 批量删除用户和角色关联 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteUserRole(Long[] ids); + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + public int countUserRoleByRoleId(Long roleId); + + /** + * 批量新增用户角色信息 + * + * @param userRoleList 用户角色列表 + * @return 结果 + */ + public int batchUserRole(List userRoleList); + + /** + * 删除用户和角色关联信息 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + public int deleteUserRoleInfo(SysUserRole userRole); + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要删除的用户数据ID + * @return 结果 + */ + public int deleteUserRoleInfos(@Param("roleId") Long roleId, @Param("userIds") Long[] userIds); +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/ISysConfigService.java b/boyue-system/src/main/java/com/boyue/system/service/ISysConfigService.java new file mode 100644 index 0000000..3135734 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/ISysConfigService.java @@ -0,0 +1,89 @@ +package com.boyue.system.service; + +import java.util.List; +import com.boyue.system.domain.SysConfig; + +/** + * 参数配置 服务层 + * + * @author boyue + */ +public interface ISysConfigService +{ + /** + * 查询参数配置信息 + * + * @param configId 参数配置ID + * @return 参数配置信息 + */ + public SysConfig selectConfigById(Long configId); + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数键名 + * @return 参数键值 + */ + public String selectConfigByKey(String configKey); + + /** + * 获取验证码开关 + * + * @return true开启,false关闭 + */ + public boolean selectCaptchaEnabled(); + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + public List selectConfigList(SysConfig config); + + /** + * 新增参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + public int insertConfig(SysConfig config); + + /** + * 修改参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + public int updateConfig(SysConfig config); + + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + */ + public void deleteConfigByIds(Long[] configIds); + + /** + * 加载参数缓存数据 + */ + public void loadingConfigCache(); + + /** + * 清空参数缓存数据 + */ + public void clearConfigCache(); + + /** + * 重置参数缓存数据 + */ + public void resetConfigCache(); + + /** + * 校验参数键名是否唯一 + * + * @param config 参数信息 + * @return 结果 + */ + public boolean checkConfigKeyUnique(SysConfig config); +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/ISysDeptService.java b/boyue-system/src/main/java/com/boyue/system/service/ISysDeptService.java new file mode 100644 index 0000000..7b94abf --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/ISysDeptService.java @@ -0,0 +1,124 @@ +package com.boyue.system.service; + +import java.util.List; +import com.boyue.common.core.domain.TreeSelect; +import com.boyue.common.core.domain.entity.SysDept; + +/** + * 部门管理 服务层 + * + * @author boyue + */ +public interface ISysDeptService +{ + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + public List selectDeptList(SysDept dept); + + /** + * 查询部门树结构信息 + * + * @param dept 部门信息 + * @return 部门树信息集合 + */ + public List selectDeptTreeList(SysDept dept); + + /** + * 构建前端所需要树结构 + * + * @param depts 部门列表 + * @return 树结构列表 + */ + public List buildDeptTree(List depts); + + /** + * 构建前端所需要下拉树结构 + * + * @param depts 部门列表 + * @return 下拉树结构列表 + */ + public List buildDeptTreeSelect(List depts); + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @return 选中部门列表 + */ + public List selectDeptListByRoleId(Long roleId); + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + public SysDept selectDeptById(Long deptId); + + /** + * 根据ID查询所有子部门(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + public int selectNormalChildrenDeptById(Long deptId); + + /** + * 是否存在部门子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + public boolean hasChildByDeptId(Long deptId); + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 true 存在 false 不存在 + */ + public boolean checkDeptExistUser(Long deptId); + + /** + * 校验部门名称是否唯一 + * + * @param dept 部门信息 + * @return 结果 + */ + public boolean checkDeptNameUnique(SysDept dept); + + /** + * 校验部门是否有数据权限 + * + * @param deptId 部门id + */ + public void checkDeptDataScope(Long deptId); + + /** + * 新增保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int insertDept(SysDept dept); + + /** + * 修改保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int updateDept(SysDept dept); + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + public int deleteDeptById(Long deptId); +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/ISysDictDataService.java b/boyue-system/src/main/java/com/boyue/system/service/ISysDictDataService.java new file mode 100644 index 0000000..54a553d --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/ISysDictDataService.java @@ -0,0 +1,60 @@ +package com.boyue.system.service; + +import java.util.List; +import com.boyue.common.core.domain.entity.SysDictData; + +/** + * 字典 业务层 + * + * @author boyue + */ +public interface ISysDictDataService +{ + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + public List selectDictDataList(SysDictData dictData); + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + public String selectDictLabel(String dictType, String dictValue); + + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + public SysDictData selectDictDataById(Long dictCode); + + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + */ + public void deleteDictDataByIds(Long[] dictCodes); + + /** + * 新增保存字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + public int insertDictData(SysDictData dictData); + + /** + * 修改保存字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + public int updateDictData(SysDictData dictData); +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/ISysDictTypeService.java b/boyue-system/src/main/java/com/boyue/system/service/ISysDictTypeService.java new file mode 100644 index 0000000..372e35d --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/ISysDictTypeService.java @@ -0,0 +1,98 @@ +package com.boyue.system.service; + +import java.util.List; +import com.boyue.common.core.domain.entity.SysDictData; +import com.boyue.common.core.domain.entity.SysDictType; + +/** + * 字典 业务层 + * + * @author boyue + */ +public interface ISysDictTypeService +{ + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + public List selectDictTypeList(SysDictType dictType); + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + public List selectDictTypeAll(); + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + public List selectDictDataByType(String dictType); + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + public SysDictType selectDictTypeById(Long dictId); + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + public SysDictType selectDictTypeByType(String dictType); + + /** + * 批量删除字典信息 + * + * @param dictIds 需要删除的字典ID + */ + public void deleteDictTypeByIds(Long[] dictIds); + + /** + * 加载字典缓存数据 + */ + public void loadingDictCache(); + + /** + * 清空字典缓存数据 + */ + public void clearDictCache(); + + /** + * 重置字典缓存数据 + */ + public void resetDictCache(); + + /** + * 新增保存字典类型信息 + * + * @param dictType 字典类型信息 + * @return 结果 + */ + public int insertDictType(SysDictType dictType); + + /** + * 修改保存字典类型信息 + * + * @param dictType 字典类型信息 + * @return 结果 + */ + public int updateDictType(SysDictType dictType); + + /** + * 校验字典类型称是否唯一 + * + * @param dictType 字典类型 + * @return 结果 + */ + public boolean checkDictTypeUnique(SysDictType dictType); +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/ISysLogininforService.java b/boyue-system/src/main/java/com/boyue/system/service/ISysLogininforService.java new file mode 100644 index 0000000..8460917 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/ISysLogininforService.java @@ -0,0 +1,40 @@ +package com.boyue.system.service; + +import java.util.List; +import com.boyue.system.domain.SysLogininfor; + +/** + * 系统访问日志情况信息 服务层 + * + * @author boyue + */ +public interface ISysLogininforService +{ + /** + * 新增系统登录日志 + * + * @param logininfor 访问日志对象 + */ + public void insertLogininfor(SysLogininfor logininfor); + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + public List selectLogininforList(SysLogininfor logininfor); + + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + public int deleteLogininforByIds(Long[] infoIds); + + /** + * 清空系统登录日志 + */ + public void cleanLogininfor(); +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/ISysMenuService.java b/boyue-system/src/main/java/com/boyue/system/service/ISysMenuService.java new file mode 100644 index 0000000..a093c13 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/ISysMenuService.java @@ -0,0 +1,144 @@ +package com.boyue.system.service; + +import java.util.List; +import java.util.Set; +import com.boyue.common.core.domain.TreeSelect; +import com.boyue.common.core.domain.entity.SysMenu; +import com.boyue.system.domain.vo.RouterVo; + +/** + * 菜单 业务层 + * + * @author boyue + */ +public interface ISysMenuService +{ + /** + * 根据用户查询系统菜单列表 + * + * @param userId 用户ID + * @return 菜单列表 + */ + public List selectMenuList(Long userId); + + /** + * 根据用户查询系统菜单列表 + * + * @param menu 菜单信息 + * @param userId 用户ID + * @return 菜单列表 + */ + public List selectMenuList(SysMenu menu, Long userId); + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + public Set selectMenuPermsByUserId(Long userId); + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + public Set selectMenuPermsByRoleId(Long roleId); + + /** + * 根据用户ID查询菜单树信息 + * + * @param userId 用户ID + * @return 菜单列表 + */ + public List selectMenuTreeByUserId(Long userId); + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + public List selectMenuListByRoleId(Long roleId); + + /** + * 构建前端路由所需要的菜单 + * + * @param menus 菜单列表 + * @return 路由列表 + */ + public List buildMenus(List menus); + + /** + * 构建前端所需要树结构 + * + * @param menus 菜单列表 + * @return 树结构列表 + */ + public List buildMenuTree(List menus); + + /** + * 构建前端所需要下拉树结构 + * + * @param menus 菜单列表 + * @return 下拉树结构列表 + */ + public List buildMenuTreeSelect(List menus); + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + public SysMenu selectMenuById(Long menuId); + + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 true 存在 false 不存在 + */ + public boolean hasChildByMenuId(Long menuId); + + /** + * 查询菜单是否存在角色 + * + * @param menuId 菜单ID + * @return 结果 true 存在 false 不存在 + */ + public boolean checkMenuExistRole(Long menuId); + + /** + * 新增保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int insertMenu(SysMenu menu); + + /** + * 修改保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int updateMenu(SysMenu menu); + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int deleteMenuById(Long menuId); + + /** + * 校验菜单名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + public boolean checkMenuNameUnique(SysMenu menu); +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/ISysNoticeService.java b/boyue-system/src/main/java/com/boyue/system/service/ISysNoticeService.java new file mode 100644 index 0000000..6a8abea --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/ISysNoticeService.java @@ -0,0 +1,60 @@ +package com.boyue.system.service; + +import java.util.List; +import com.boyue.system.domain.SysNotice; + +/** + * 公告 服务层 + * + * @author boyue + */ +public interface ISysNoticeService +{ + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + public SysNotice selectNoticeById(Long noticeId); + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + public List selectNoticeList(SysNotice notice); + + /** + * 新增公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int insertNotice(SysNotice notice); + + /** + * 修改公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int updateNotice(SysNotice notice); + + /** + * 删除公告信息 + * + * @param noticeId 公告ID + * @return 结果 + */ + public int deleteNoticeById(Long noticeId); + + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + public int deleteNoticeByIds(Long[] noticeIds); +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/ISysOperLogService.java b/boyue-system/src/main/java/com/boyue/system/service/ISysOperLogService.java new file mode 100644 index 0000000..0eb75ad --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/ISysOperLogService.java @@ -0,0 +1,70 @@ +package com.boyue.system.service; + +import java.util.List; +import java.util.Map; + +import com.boyue.system.domain.SysOperLog; + +/** + * 操作日志 服务层 + * + * @author boyue + */ +public interface ISysOperLogService +{ + /** + * 新增操作日志 + * + * @param operLog 操作日志对象 + */ + public void insertOperlog(SysOperLog operLog); + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + public List selectOperLogList(SysOperLog operLog); + + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + public int deleteOperLogByIds(Long[] operIds); + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + public SysOperLog selectOperLogById(Long operId); + + /** + * 清空操作日志 + */ + public void cleanOperLog(); + + /** + * 获取成功操作的统计信息 + */ + List> getSuccessOperationStats(SysOperLog operLog); + + /** + * 获取失败操作的统计信息 + */ + List> getFailureOperationStats(SysOperLog operLog); + + /** + * 获取按状态分类的操作统计信息 + */ + List> getStatusStats(SysOperLog operLog); + + /** + * 获取按模块和操作类型分类的操作统计信息 + */ + List> getModuleOperationStats(SysOperLog operLog); +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/ISysPostService.java b/boyue-system/src/main/java/com/boyue/system/service/ISysPostService.java new file mode 100644 index 0000000..746fb5d --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/ISysPostService.java @@ -0,0 +1,99 @@ +package com.boyue.system.service; + +import java.util.List; +import com.boyue.system.domain.SysPost; + +/** + * 岗位信息 服务层 + * + * @author boyue + */ +public interface ISysPostService +{ + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位列表 + */ + public List selectPostList(SysPost post); + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + public List selectPostAll(); + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + public SysPost selectPostById(Long postId); + + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + public List selectPostListByUserId(Long userId); + + /** + * 校验岗位名称 + * + * @param post 岗位信息 + * @return 结果 + */ + public boolean checkPostNameUnique(SysPost post); + + /** + * 校验岗位编码 + * + * @param post 岗位信息 + * @return 结果 + */ + public boolean checkPostCodeUnique(SysPost post); + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + public int countUserPostById(Long postId); + + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + public int deletePostById(Long postId); + + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 结果 + */ + public int deletePostByIds(Long[] postIds); + + /** + * 新增保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + public int insertPost(SysPost post); + + /** + * 修改保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + public int updatePost(SysPost post); +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/ISysRoleService.java b/boyue-system/src/main/java/com/boyue/system/service/ISysRoleService.java new file mode 100644 index 0000000..ea6b4dd --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/ISysRoleService.java @@ -0,0 +1,173 @@ +package com.boyue.system.service; + +import java.util.List; +import java.util.Set; +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.system.domain.SysUserRole; + +/** + * 角色业务层 + * + * @author boyue + */ +public interface ISysRoleService +{ + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + public List selectRoleList(SysRole role); + + /** + * 根据用户ID查询角色列表 + * + * @param userId 用户ID + * @return 角色列表 + */ + public List selectRolesByUserId(Long userId); + + /** + * 根据用户ID查询角色权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + public Set selectRolePermissionByUserId(Long userId); + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + public List selectRoleAll(); + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + public List selectRoleListByUserId(Long userId); + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + public SysRole selectRoleById(Long roleId); + + /** + * 校验角色名称是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + public boolean checkRoleNameUnique(SysRole role); + + /** + * 校验角色权限是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + public boolean checkRoleKeyUnique(SysRole role); + + /** + * 校验角色是否允许操作 + * + * @param role 角色信息 + */ + public void checkRoleAllowed(SysRole role); + + /** + * 校验角色是否有数据权限 + * + * @param roleId 角色id + */ + public void checkRoleDataScope(Long roleId); + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + public int countUserRoleByRoleId(Long roleId); + + /** + * 新增保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int insertRole(SysRole role); + + /** + * 修改保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int updateRole(SysRole role); + + /** + * 修改角色状态 + * + * @param role 角色信息 + * @return 结果 + */ + public int updateRoleStatus(SysRole role); + + /** + * 修改数据权限信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int authDataScope(SysRole role); + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + public int deleteRoleById(Long roleId); + + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + public int deleteRoleByIds(Long[] roleIds); + + /** + * 取消授权用户角色 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + public int deleteAuthUser(SysUserRole userRole); + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要取消授权的用户数据ID + * @return 结果 + */ + public int deleteAuthUsers(Long roleId, Long[] userIds); + + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要删除的用户数据ID + * @return 结果 + */ + public int insertAuthUsers(Long roleId, Long[] userIds); +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/ISysUserOnlineService.java b/boyue-system/src/main/java/com/boyue/system/service/ISysUserOnlineService.java new file mode 100644 index 0000000..9c765dc --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/ISysUserOnlineService.java @@ -0,0 +1,48 @@ +package com.boyue.system.service; + +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.system.domain.SysUserOnline; + +/** + * 在线用户 服务层 + * + * @author boyue + */ +public interface ISysUserOnlineService +{ + /** + * 通过登录地址查询信息 + * + * @param ipaddr 登录地址 + * @param user 用户信息 + * @return 在线用户信息 + */ + public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user); + + /** + * 通过用户名称查询信息 + * + * @param userName 用户名称 + * @param user 用户信息 + * @return 在线用户信息 + */ + public SysUserOnline selectOnlineByUserName(String userName, LoginUser user); + + /** + * 通过登录地址/用户名称查询信息 + * + * @param ipaddr 登录地址 + * @param userName 用户名称 + * @param user 用户信息 + * @return 在线用户信息 + */ + public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user); + + /** + * 设置在线用户信息 + * + * @param user 用户信息 + * @return 在线用户 + */ + public SysUserOnline loginUserToUserOnline(LoginUser user); +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/ISysUserService.java b/boyue-system/src/main/java/com/boyue/system/service/ISysUserService.java new file mode 100644 index 0000000..6fcf8ff --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/ISysUserService.java @@ -0,0 +1,222 @@ +package com.boyue.system.service; + +import java.util.List; + +import com.boyue.common.core.domain.entity.SysUser; + +/** + * 用户 业务层 + * + * @author boyue + */ +public interface ISysUserService { + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List selectUserList(SysUser user); + + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List selectAllocatedList(SysUser user); + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List selectUnallocatedList(SysUser user); + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + public SysUser selectUserByUserName(String userName); + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + public SysUser selectUserById(Long userId); + + /** + * 通过手机号查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + public SysUser selectUserByPhone(String phone); + + /** + * 通过邮箱查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + public SysUser selectUserByEmail(String email); + + /** + * 根据用户ID查询用户所属角色组 + * + * @param userName 用户名 + * @return 结果 + */ + public String selectUserRoleGroup(String userName); + + /** + * 根据用户ID查询用户所属岗位组 + * + * @param userName 用户名 + * @return 结果 + */ + public String selectUserPostGroup(String userName); + + /** + * 校验用户名称是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + public boolean checkUserNameUnique(SysUser user); + + /** + * 校验手机号码是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + public boolean checkPhoneUnique(SysUser user); + + /** + * 校验email是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + public boolean checkEmailUnique(SysUser user); + + /** + * 校验用户是否允许操作 + * + * @param user 用户信息 + */ + public void checkUserAllowed(SysUser user); + + /** + * 校验用户是否有数据权限 + * + * @param userId 用户id + */ + public void checkUserDataScope(Long userId); + + /** + * 新增用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int insertUser(SysUser user); + + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public boolean registerUser(SysUser user); + + /** + * 修改用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int updateUser(SysUser user); + + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + public void insertUserAuth(Long userId, Long[] roleIds); + + /** + * 修改用户状态 + * + * @param user 用户信息 + * @return 结果 + */ + public int updateUserStatus(SysUser user); + + /** + * 修改用户基本信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int updateUserProfile(SysUser user); + + /** + * 修改用户头像 + * + * @param userName 用户名 + * @param avatar 头像地址 + * @return 结果 + */ + public boolean updateUserAvatar(String userName, String avatar); + + /** + * 重置用户密码 + * + * @param user 用户信息 + * @return 结果 + */ + public int resetPwd(SysUser user); + + /** + * 重置用户密码 + * + * @param userName 用户名 + * @param password 密码 + * @return 结果 + */ + public int resetUserPwd(String userName, String password); + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + public int deleteUserById(Long userId); + + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + public int deleteUserByIds(Long[] userIds); + + /** + * 导入用户数据 + * + * @param userList 用户数据列表 + * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 + * @param operName 操作用户 + * @return 结果 + */ + public String importUser(List userList, Boolean isUpdateSupport, String operName); +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/impl/SysConfigServiceImpl.java b/boyue-system/src/main/java/com/boyue/system/service/impl/SysConfigServiceImpl.java new file mode 100644 index 0000000..43e5139 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/impl/SysConfigServiceImpl.java @@ -0,0 +1,226 @@ +package com.boyue.system.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.Cache; +import org.springframework.stereotype.Service; + +import com.boyue.common.annotation.DataSource; +import com.boyue.common.constant.CacheConstants; +import com.boyue.common.constant.UserConstants; +import com.boyue.common.core.text.Convert; +import com.boyue.common.enums.DataSourceType; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.CacheUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.system.domain.SysConfig; +import com.boyue.system.mapper.SysConfigMapper; +import com.boyue.system.service.ISysConfigService; + +import jakarta.annotation.PostConstruct; + +/** + * 参数配置 服务层实现 + * + * @author boyue + */ +@Service +public class SysConfigServiceImpl implements ISysConfigService +{ + @Autowired + private SysConfigMapper configMapper; + + /** + * 项目启动时,初始化参数到缓存 + */ + @PostConstruct + public void init() + { + loadingConfigCache(); + } + + /** + * 查询参数配置信息 + * + * @param configId 参数配置ID + * @return 参数配置信息 + */ + @Override + @DataSource(DataSourceType.MASTER) + public SysConfig selectConfigById(Long configId) + { + SysConfig config = new SysConfig(); + config.setConfigId(configId); + return configMapper.selectConfig(config); + } + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数key + * @return 参数键值 + */ + @Override + public String selectConfigByKey(String configKey) + { + String configValue = Convert.toStr(getCache().get(configKey, String.class)); + if (StringUtils.isNotEmpty(configValue)) + { + return configValue; + } + SysConfig config = new SysConfig(); + config.setConfigKey(configKey); + SysConfig retConfig = configMapper.selectConfig(config); + if (StringUtils.isNotNull(retConfig)) + { + CacheUtils.put(CacheConstants.SYS_CONFIG_KEY, configKey, retConfig.getConfigValue()); + return retConfig.getConfigValue(); + } + return StringUtils.EMPTY; + } + + /** + * 获取验证码开关 + * + * @return true开启,false关闭 + */ + @Override + public boolean selectCaptchaEnabled() + { + String captchaEnabled = selectConfigByKey("sys.account.captchaEnabled"); + return Convert.toBool(captchaEnabled,true); + } + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + @Override + public List selectConfigList(SysConfig config) + { + return configMapper.selectConfigList(config); + } + + /** + * 新增参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + @Override + public int insertConfig(SysConfig config) + { + int row = configMapper.insertConfig(config); + if (row > 0) + { + CacheUtils.put(CacheConstants.SYS_CONFIG_KEY, config.getConfigKey(), config.getConfigValue()); + } + return row; + } + + /** + * 修改参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + @Override + public int updateConfig(SysConfig config) + { + SysConfig temp = configMapper.selectConfigById(config.getConfigId()); + if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey())) + { + CacheUtils.removeIfPresent(CacheConstants.SYS_CONFIG_KEY, temp.getConfigKey()); + } + + int row = configMapper.updateConfig(config); + if (row > 0) + { + CacheUtils.put(CacheConstants.SYS_CONFIG_KEY, config.getConfigKey(), config.getConfigValue()); + } + return row; + } + + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + */ + @Override + public void deleteConfigByIds(Long[] configIds) + { + for (Long configId : configIds) + { + SysConfig config = selectConfigById(configId); + if (StringUtils.equals(UserConstants.YES, config.getConfigType())) + { + throw new ServiceException(String.format("内置参数【%1$s】不能删除 ", config.getConfigKey())); + } + configMapper.deleteConfigById(configId); + getCache().evict(config.getConfigKey()); + } + } + + /** + * 加载参数缓存数据 + */ + @Override + public void loadingConfigCache() + { + List configsList = configMapper.selectConfigList(new SysConfig()); + for (SysConfig config : configsList) + { + getCache().put(config.getConfigKey(), config.getConfigValue()); + } + } + + /** + * 清空参数缓存数据 + */ + @Override + public void clearConfigCache() + { + CacheUtils.getCache(CacheConstants.SYS_CONFIG_KEY).clear(); + } + + /** + * 重置参数缓存数据 + */ + @Override + public void resetConfigCache() + { + clearConfigCache(); + loadingConfigCache(); + } + + /** + * 校验参数键名是否唯一 + * + * @param config 参数配置信息 + * @return 结果 + */ + @Override + public boolean checkConfigKeyUnique(SysConfig config) + { + Long configId = StringUtils.isNull(config.getConfigId()) ? -1L : config.getConfigId(); + SysConfig info = configMapper.checkConfigKeyUnique(config.getConfigKey()); + if (StringUtils.isNotNull(info) && info.getConfigId().longValue() != configId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 获取config缓存 + * + * @return + */ + private Cache getCache() + { + return CacheUtils.getCache(CacheConstants.SYS_CONFIG_KEY); + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/impl/SysDeptServiceImpl.java b/boyue-system/src/main/java/com/boyue/system/service/impl/SysDeptServiceImpl.java new file mode 100644 index 0000000..00e4e65 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/impl/SysDeptServiceImpl.java @@ -0,0 +1,338 @@ +package com.boyue.system.service.impl; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.boyue.common.annotation.DataScope; +import com.boyue.common.constant.UserConstants; +import com.boyue.common.core.domain.TreeSelect; +import com.boyue.common.core.domain.entity.SysDept; +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.core.text.Convert; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.spring.SpringUtils; +import com.boyue.system.mapper.SysDeptMapper; +import com.boyue.system.mapper.SysRoleMapper; +import com.boyue.system.service.ISysDeptService; + +/** + * 部门管理 服务实现 + * + * @author boyue + */ +@Service +public class SysDeptServiceImpl implements ISysDeptService +{ + @Autowired + private SysDeptMapper deptMapper; + + @Autowired + private SysRoleMapper roleMapper; + + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + @Override + @DataScope(deptAlias = "d") + public List selectDeptList(SysDept dept) + { + return deptMapper.selectDeptList(dept); + } + + /** + * 查询部门树结构信息 + * + * @param dept 部门信息 + * @return 部门树信息集合 + */ + @Override + public List selectDeptTreeList(SysDept dept) + { + List depts = SpringUtils.getAopProxy(this).selectDeptList(dept); + return buildDeptTreeSelect(depts); + } + + /** + * 构建前端所需要树结构 + * + * @param depts 部门列表 + * @return 树结构列表 + */ + @Override + public List buildDeptTree(List depts) + { + List returnList = new ArrayList(); + List tempList = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList()); + for (SysDept dept : depts) + { + // 如果是顶级节点, 遍历该父节点的所有子节点 + if (!tempList.contains(dept.getParentId())) + { + recursionFn(depts, dept); + returnList.add(dept); + } + } + if (returnList.isEmpty()) + { + returnList = depts; + } + return returnList; + } + + /** + * 构建前端所需要下拉树结构 + * + * @param depts 部门列表 + * @return 下拉树结构列表 + */ + @Override + public List buildDeptTreeSelect(List depts) + { + List deptTrees = buildDeptTree(depts); + return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList()); + } + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @return 选中部门列表 + */ + @Override + public List selectDeptListByRoleId(Long roleId) + { + SysRole role = roleMapper.selectRoleById(roleId); + return deptMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly()); + } + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + @Override + public SysDept selectDeptById(Long deptId) + { + return deptMapper.selectDeptById(deptId); + } + + /** + * 根据ID查询所有子部门(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + @Override + public int selectNormalChildrenDeptById(Long deptId) + { + return deptMapper.selectNormalChildrenDeptById(deptId); + } + + /** + * 是否存在子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + @Override + public boolean hasChildByDeptId(Long deptId) + { + int result = deptMapper.hasChildByDeptId(deptId); + return result > 0; + } + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 true 存在 false 不存在 + */ + @Override + public boolean checkDeptExistUser(Long deptId) + { + int result = deptMapper.checkDeptExistUser(deptId); + return result > 0; + } + + /** + * 校验部门名称是否唯一 + * + * @param dept 部门信息 + * @return 结果 + */ + @Override + public boolean checkDeptNameUnique(SysDept dept) + { + Long deptId = StringUtils.isNull(dept.getDeptId()) ? -1L : dept.getDeptId(); + SysDept info = deptMapper.checkDeptNameUnique(dept.getDeptName(), dept.getParentId()); + if (StringUtils.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验部门是否有数据权限 + * + * @param deptId 部门id + */ + @Override + public void checkDeptDataScope(Long deptId) + { + if (!SysUser.isAdmin(SecurityUtils.getUserId())) + { + SysDept dept = new SysDept(); + dept.setDeptId(deptId); + List depts = SpringUtils.getAopProxy(this).selectDeptList(dept); + if (StringUtils.isEmpty(depts)) + { + throw new ServiceException("没有权限访问部门数据!"); + } + } + } + + /** + * 新增保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + @Override + public int insertDept(SysDept dept) + { + SysDept info = deptMapper.selectDeptById(dept.getParentId()); + // 如果父节点不为正常状态,则不允许新增子节点 + if (!UserConstants.DEPT_NORMAL.equals(info.getStatus())) + { + throw new ServiceException("部门停用,不允许新增"); + } + dept.setAncestors(info.getAncestors() + "," + dept.getParentId()); + return deptMapper.insertDept(dept); + } + + /** + * 修改保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + @Override + public int updateDept(SysDept dept) + { + SysDept newParentDept = deptMapper.selectDeptById(dept.getParentId()); + SysDept oldDept = deptMapper.selectDeptById(dept.getDeptId()); + if (StringUtils.isNotNull(newParentDept) && StringUtils.isNotNull(oldDept)) + { + String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId(); + String oldAncestors = oldDept.getAncestors(); + dept.setAncestors(newAncestors); + updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors); + } + int result = deptMapper.updateDept(dept); + if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors()) + && !StringUtils.equals("0", dept.getAncestors())) + { + // 如果该部门是启用状态,则启用该部门的所有上级部门 + updateParentDeptStatusNormal(dept); + } + return result; + } + + /** + * 修改该部门的父级部门状态 + * + * @param dept 当前部门 + */ + private void updateParentDeptStatusNormal(SysDept dept) + { + String ancestors = dept.getAncestors(); + Long[] deptIds = Convert.toLongArray(ancestors); + deptMapper.updateDeptStatusNormal(deptIds); + } + + /** + * 修改子元素关系 + * + * @param deptId 被修改的部门ID + * @param newAncestors 新的父ID集合 + * @param oldAncestors 旧的父ID集合 + */ + public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) + { + List children = deptMapper.selectChildrenDeptById(deptId); + for (SysDept child : children) + { + child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); + } + if (children.size() > 0) + { + deptMapper.updateDeptChildren(children); + } + } + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + @Override + public int deleteDeptById(Long deptId) + { + return deptMapper.deleteDeptById(deptId); + } + + /** + * 递归列表 + */ + private void recursionFn(List list, SysDept t) + { + // 得到子节点列表 + List childList = getChildList(list, t); + t.setChildren(childList); + for (SysDept tChild : childList) + { + if (hasChild(list, tChild)) + { + recursionFn(list, tChild); + } + } + } + + /** + * 得到子节点列表 + */ + private List getChildList(List list, SysDept t) + { + List tlist = new ArrayList(); + Iterator it = list.iterator(); + while (it.hasNext()) + { + SysDept n = (SysDept) it.next(); + if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue()) + { + tlist.add(n); + } + } + return tlist; + } + + /** + * 判断是否有子节点 + */ + private boolean hasChild(List list, SysDept t) + { + return getChildList(list, t).size() > 0; + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/impl/SysDictDataServiceImpl.java b/boyue-system/src/main/java/com/boyue/system/service/impl/SysDictDataServiceImpl.java new file mode 100644 index 0000000..e89cbb4 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/impl/SysDictDataServiceImpl.java @@ -0,0 +1,111 @@ +package com.boyue.system.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.boyue.common.core.domain.entity.SysDictData; +import com.boyue.common.utils.DictUtils; +import com.boyue.system.mapper.SysDictDataMapper; +import com.boyue.system.service.ISysDictDataService; + +/** + * 字典 业务层处理 + * + * @author boyue + */ +@Service +public class SysDictDataServiceImpl implements ISysDictDataService +{ + @Autowired + private SysDictDataMapper dictDataMapper; + + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + @Override + public List selectDictDataList(SysDictData dictData) + { + return dictDataMapper.selectDictDataList(dictData); + } + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + @Override + public String selectDictLabel(String dictType, String dictValue) + { + return dictDataMapper.selectDictLabel(dictType, dictValue); + } + + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + @Override + public SysDictData selectDictDataById(Long dictCode) + { + return dictDataMapper.selectDictDataById(dictCode); + } + + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + */ + @Override + public void deleteDictDataByIds(Long[] dictCodes) + { + for (Long dictCode : dictCodes) + { + SysDictData data = selectDictDataById(dictCode); + dictDataMapper.deleteDictDataById(dictCode); + List dictDatas = dictDataMapper.selectDictDataByType(data.getDictType()); + DictUtils.setDictCache(data.getDictType(), dictDatas); + } + } + + /** + * 新增保存字典数据信息 + * + * @param data 字典数据信息 + * @return 结果 + */ + @Override + public int insertDictData(SysDictData data) + { + int row = dictDataMapper.insertDictData(data); + if (row > 0) + { + List dictDatas = dictDataMapper.selectDictDataByType(data.getDictType()); + DictUtils.setDictCache(data.getDictType(), dictDatas); + } + return row; + } + + /** + * 修改保存字典数据信息 + * + * @param data 字典数据信息 + * @return 结果 + */ + @Override + public int updateDictData(SysDictData data) + { + int row = dictDataMapper.updateDictData(data); + if (row > 0) + { + List dictDatas = dictDataMapper.selectDictDataByType(data.getDictType()); + DictUtils.setDictCache(data.getDictType(), dictDatas); + } + return row; + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/impl/SysDictTypeServiceImpl.java b/boyue-system/src/main/java/com/boyue/system/service/impl/SysDictTypeServiceImpl.java new file mode 100644 index 0000000..732141d --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/impl/SysDictTypeServiceImpl.java @@ -0,0 +1,226 @@ +package com.boyue.system.service.impl; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.boyue.common.constant.UserConstants; +import com.boyue.common.core.domain.entity.SysDictData; +import com.boyue.common.core.domain.entity.SysDictType; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.DictUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.system.mapper.SysDictDataMapper; +import com.boyue.system.mapper.SysDictTypeMapper; +import com.boyue.system.service.ISysDictTypeService; + +import jakarta.annotation.PostConstruct; + +/** + * 字典 业务层处理 + * + * @author boyue + */ +@Service +public class SysDictTypeServiceImpl implements ISysDictTypeService +{ + @Autowired + private SysDictTypeMapper dictTypeMapper; + + @Autowired + private SysDictDataMapper dictDataMapper; + + /** + * 项目启动时,初始化字典到缓存 + */ + @PostConstruct + public void init() + { + loadingDictCache(); + } + + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + @Override + public List selectDictTypeList(SysDictType dictType) + { + return dictTypeMapper.selectDictTypeList(dictType); + } + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + @Override + public List selectDictTypeAll() + { + return dictTypeMapper.selectDictTypeAll(); + } + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + @Override + public List selectDictDataByType(String dictType) + { + List dictDatas = DictUtils.getDictCache(dictType); + if (StringUtils.isNotEmpty(dictDatas)) + { + return dictDatas; + } + dictDatas = dictDataMapper.selectDictDataByType(dictType); + if (StringUtils.isNotEmpty(dictDatas)) + { + DictUtils.setDictCache(dictType, dictDatas); + return dictDatas; + } + return null; + } + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + @Override + public SysDictType selectDictTypeById(Long dictId) + { + return dictTypeMapper.selectDictTypeById(dictId); + } + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + @Override + public SysDictType selectDictTypeByType(String dictType) + { + return dictTypeMapper.selectDictTypeByType(dictType); + } + + /** + * 批量删除字典类型信息 + * + * @param dictIds 需要删除的字典ID + */ + @Override + public void deleteDictTypeByIds(Long[] dictIds) + { + for (Long dictId : dictIds) + { + SysDictType dictType = selectDictTypeById(dictId); + if (dictDataMapper.countDictDataByType(dictType.getDictType()) > 0) + { + throw new ServiceException("%1$s已分配,不能删除".formatted(dictType.getDictName())); + } + dictTypeMapper.deleteDictTypeById(dictId); + DictUtils.removeDictCache(dictType.getDictType()); + } + } + + /** + * 加载字典缓存数据 + */ + @Override + public void loadingDictCache() + { + SysDictData dictData = new SysDictData(); + dictData.setStatus("0"); + Map> dictDataMap = dictDataMapper.selectDictDataList(dictData).stream().collect(Collectors.groupingBy(SysDictData::getDictType)); + for (Map.Entry> entry : dictDataMap.entrySet()) + { + DictUtils.setDictCache(entry.getKey(), entry.getValue().stream().sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList())); + } + } + + /** + * 清空字典缓存数据 + */ + @Override + public void clearDictCache() + { + DictUtils.clearDictCache(); + } + + /** + * 重置字典缓存数据 + */ + @Override + public void resetDictCache() + { + clearDictCache(); + loadingDictCache(); + } + + /** + * 新增保存字典类型信息 + * + * @param dict 字典类型信息 + * @return 结果 + */ + @Override + public int insertDictType(SysDictType dict) + { + int row = dictTypeMapper.insertDictType(dict); + if (row > 0) + { + DictUtils.removeDictCache(dict.getDictType()); + } + return row; + } + + /** + * 修改保存字典类型信息 + * + * @param dict 字典类型信息 + * @return 结果 + */ + @Override + @Transactional + public int updateDictType(SysDictType dict) + { + SysDictType oldDict = dictTypeMapper.selectDictTypeById(dict.getDictId()); + dictDataMapper.updateDictDataType(oldDict.getDictType(), dict.getDictType()); + int row = dictTypeMapper.updateDictType(dict); + if (row > 0) + { + List dictDatas = dictDataMapper.selectDictDataByType(dict.getDictType()); + DictUtils.setDictCache(dict.getDictType(), dictDatas); + } + return row; + } + + /** + * 校验字典类型称是否唯一 + * + * @param dict 字典类型 + * @return 结果 + */ + @Override + public boolean checkDictTypeUnique(SysDictType dict) + { + Long dictId = StringUtils.isNull(dict.getDictId()) ? -1L : dict.getDictId(); + SysDictType dictType = dictTypeMapper.checkDictTypeUnique(dict.getDictType()); + if (StringUtils.isNotNull(dictType) && dictType.getDictId().longValue() != dictId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/impl/SysLogininforServiceImpl.java b/boyue-system/src/main/java/com/boyue/system/service/impl/SysLogininforServiceImpl.java new file mode 100644 index 0000000..20f0be3 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/impl/SysLogininforServiceImpl.java @@ -0,0 +1,65 @@ +package com.boyue.system.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.boyue.system.domain.SysLogininfor; +import com.boyue.system.mapper.SysLogininforMapper; +import com.boyue.system.service.ISysLogininforService; + +/** + * 系统访问日志情况信息 服务层处理 + * + * @author boyue + */ +@Service +public class SysLogininforServiceImpl implements ISysLogininforService +{ + + @Autowired + private SysLogininforMapper logininforMapper; + + /** + * 新增系统登录日志 + * + * @param logininfor 访问日志对象 + */ + @Override + public void insertLogininfor(SysLogininfor logininfor) + { + logininforMapper.insertLogininfor(logininfor); + } + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + @Override + public List selectLogininforList(SysLogininfor logininfor) + { + return logininforMapper.selectLogininforList(logininfor); + } + + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + @Override + public int deleteLogininforByIds(Long[] infoIds) + { + return logininforMapper.deleteLogininforByIds(infoIds); + } + + /** + * 清空系统登录日志 + */ + @Override + public void cleanLogininfor() + { + logininforMapper.cleanLogininfor(); + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/impl/SysMenuServiceImpl.java b/boyue-system/src/main/java/com/boyue/system/service/impl/SysMenuServiceImpl.java new file mode 100644 index 0000000..55cd742 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/impl/SysMenuServiceImpl.java @@ -0,0 +1,484 @@ +package com.boyue.system.service.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.boyue.common.constant.Constants; +import com.boyue.common.constant.UserConstants; +import com.boyue.common.core.domain.TreeSelect; +import com.boyue.common.core.domain.entity.SysMenu; +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.system.domain.vo.MetaVo; +import com.boyue.system.domain.vo.RouterVo; +import com.boyue.system.mapper.SysMenuMapper; +import com.boyue.system.mapper.SysRoleMapper; +import com.boyue.system.mapper.SysRoleMenuMapper; +import com.boyue.system.service.ISysMenuService; + +/** + * 菜单 业务层处理 + * + * @author boyue + */ +@Service +public class SysMenuServiceImpl implements ISysMenuService { + public static final String PREMISSION_STRING = "perms[\"{0}\"]"; + + @Autowired + private SysMenuMapper menuMapper; + + @Autowired + private SysRoleMapper roleMapper; + + @Autowired + private SysRoleMenuMapper roleMenuMapper; + + /** + * 根据用户查询系统菜单列表 + * + * @param userId 用户ID + * @return 菜单列表 + */ + @Override + public List selectMenuList(Long userId) { + return selectMenuList(new SysMenu(), userId); + } + + /** + * 查询系统菜单列表 + * + * @param menu 菜单信息 + * @return 菜单列表 + */ + @Override + public List selectMenuList(SysMenu menu, Long userId) { + List menuList = null; + // 管理员显示所有菜单信息 + if (SysUser.isAdmin(userId)) { + menuList = menuMapper.selectMenuList(menu); + } else { + menu.getParams().put("userId", userId); + menuList = menuMapper.selectMenuListByUserId(menu); + } + return menuList; + } + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + @Override + public Set selectMenuPermsByUserId(Long userId) { + List perms = menuMapper.selectMenuPermsByUserId(userId); + Set permsSet = new HashSet<>(); + for (String perm : perms) { + if (StringUtils.isNotEmpty(perm)) { + permsSet.addAll(Arrays.asList(perm.trim().split(","))); + } + } + return permsSet; + } + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + @Override + public Set selectMenuPermsByRoleId(Long roleId) { + List perms = menuMapper.selectMenuPermsByRoleId(roleId); + Set permsSet = new HashSet<>(); + for (String perm : perms) { + if (StringUtils.isNotEmpty(perm)) { + permsSet.addAll(Arrays.asList(perm.trim().split(","))); + } + } + return permsSet; + } + + /** + * 根据用户ID查询菜单 + * + * @param userId 用户名称 + * @return 菜单列表 + */ + @Override + public List selectMenuTreeByUserId(Long userId) { + List menus = null; + if (SecurityUtils.isAdmin(userId)) { + menus = menuMapper.selectMenuTreeAll(); + } else { + menus = menuMapper.selectMenuTreeByUserId(userId); + } + return getChildPerms(menus, 0); + } + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + @Override + public List selectMenuListByRoleId(Long roleId) { + SysRole role = roleMapper.selectRoleById(roleId); + return menuMapper.selectMenuListByRoleId(roleId, role.isMenuCheckStrictly()); + } + + /** + * 构建前端路由所需要的菜单 + * + * @param menus 菜单列表 + * @return 路由列表 + */ + @Override + public List buildMenus(List menus) { + List routers = new LinkedList(); + for (SysMenu menu : menus) { + RouterVo router = new RouterVo(); + router.setHidden("1".equals(menu.getVisible())); + router.setName(getRouteName(menu)); + router.setPath(getRouterPath(menu)); + router.setComponent(getComponent(menu)); + router.setQuery(menu.getQuery()); + router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), + menu.getPath())); + List cMenus = menu.getChildren(); + if (StringUtils.isNotEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType())) { + router.setAlwaysShow(true); + router.setRedirect("noRedirect"); + router.setChildren(buildMenus(cMenus)); + } else if (isMenuFrame(menu)) { + router.setMeta(null); + List childrenList = new ArrayList(); + RouterVo children = new RouterVo(); + children.setPath(menu.getPath()); + children.setComponent(menu.getComponent()); + children.setName(getRouteName(menu.getRouteName(), menu.getPath())); + children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), + StringUtils.equals("1", menu.getIsCache()), menu.getPath())); + children.setQuery(menu.getQuery()); + childrenList.add(children); + router.setChildren(childrenList); + } else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) { + router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon())); + router.setPath("/"); + List childrenList = new ArrayList(); + RouterVo children = new RouterVo(); + String routerPath = innerLinkReplaceEach(menu.getPath()); + children.setPath(routerPath); + children.setComponent(UserConstants.INNER_LINK); + children.setName(getRouteName(menu.getRouteName(), routerPath)); + children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath())); + childrenList.add(children); + router.setChildren(childrenList); + } + routers.add(router); + } + return routers; + } + + /** + * 构建前端所需要树结构 + * + * @param menus 菜单列表 + * @return 树结构列表 + */ + @Override + public List buildMenuTree(List menus) { + List returnList = new ArrayList(); + List tempList = menus.stream().map(SysMenu::getMenuId).collect(Collectors.toList()); + for (Iterator iterator = menus.iterator(); iterator.hasNext();) { + SysMenu menu = (SysMenu) iterator.next(); + // 如果是顶级节点, 遍历该父节点的所有子节点 + if (!tempList.contains(menu.getParentId())) { + recursionFn(menus, menu); + returnList.add(menu); + } + } + if (returnList.isEmpty()) { + returnList = menus; + } + return returnList; + } + + /** + * 构建前端所需要下拉树结构 + * + * @param menus 菜单列表 + * @return 下拉树结构列表 + */ + @Override + public List buildMenuTreeSelect(List menus) { + List menuTrees = buildMenuTree(menus); + return menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList()); + } + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + @Override + public SysMenu selectMenuById(Long menuId) { + return menuMapper.selectMenuById(menuId); + } + + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public boolean hasChildByMenuId(Long menuId) { + int result = menuMapper.hasChildByMenuId(menuId); + return result > 0; + } + + /** + * 查询菜单使用数量 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public boolean checkMenuExistRole(Long menuId) { + int result = roleMenuMapper.checkMenuExistRole(menuId); + return result > 0; + } + + /** + * 新增保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + public int insertMenu(SysMenu menu) { + return menuMapper.insertMenu(menu); + } + + /** + * 修改保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + public int updateMenu(SysMenu menu) { + return menuMapper.updateMenu(menu); + } + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public int deleteMenuById(Long menuId) { + return menuMapper.deleteMenuById(menuId); + } + + /** + * 校验菜单名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + public boolean checkMenuNameUnique(SysMenu menu) { + Long menuId = StringUtils.isNull(menu.getMenuId()) ? -1L : menu.getMenuId(); + SysMenu info = menuMapper.checkMenuNameUnique(menu.getMenuName(), menu.getParentId()); + if (StringUtils.isNotNull(info) && info.getMenuId().longValue() != menuId.longValue()) { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 获取路由名称 + * + * @param menu 菜单信息 + * @return 路由名称 + */ + public String getRouteName(SysMenu menu) { + // 非外链并且是一级目录(类型为目录) + if (isMenuFrame(menu)) { + return StringUtils.EMPTY; + } + return getRouteName(menu.getRouteName(), menu.getPath()); + } + + /** + * 获取路由名称,如没有配置路由名称则取路由地址 + * + * @param routerName 路由名称 + * @param path 路由地址 + * @return 路由名称(驼峰格式) + */ + public String getRouteName(String name, String path) { + String routerName = StringUtils.isNotEmpty(name) ? name : path; + return StringUtils.capitalize(routerName); + } + + /** + * 获取路由地址 + * + * @param menu 菜单信息 + * @return 路由地址 + */ + public String getRouterPath(SysMenu menu) { + String routerPath = menu.getPath(); + // 内链打开外网方式 + if (menu.getParentId().intValue() != 0 && isInnerLink(menu)) { + routerPath = innerLinkReplaceEach(routerPath); + } + // 非外链并且是一级目录(类型为目录) + if (0 == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType()) + && UserConstants.NO_FRAME.equals(menu.getIsFrame())) { + routerPath = "/" + menu.getPath(); + } + // 非外链并且是一级目录(类型为菜单) + else if (isMenuFrame(menu)) { + routerPath = "/"; + } + return routerPath; + } + + /** + * 获取组件信息 + * + * @param menu 菜单信息 + * @return 组件信息 + */ + public String getComponent(SysMenu menu) { + String component = UserConstants.LAYOUT; + if (StringUtils.isNotEmpty(menu.getComponent()) && !isMenuFrame(menu)) { + component = menu.getComponent(); + } else if (StringUtils.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != 0 + && isInnerLink(menu)) { + component = UserConstants.INNER_LINK; + } else if (StringUtils.isEmpty(menu.getComponent()) && isParentView(menu)) { + component = UserConstants.PARENT_VIEW; + } + return component; + } + + /** + * 是否为菜单内部跳转 + * + * @param menu 菜单信息 + * @return 结果 + */ + public boolean isMenuFrame(SysMenu menu) { + return menu.getParentId().intValue() == 0 && UserConstants.TYPE_MENU.equals(menu.getMenuType()) + && menu.getIsFrame().equals(UserConstants.NO_FRAME); + } + + /** + * 是否为内链组件 + * + * @param menu 菜单信息 + * @return 结果 + */ + public boolean isInnerLink(SysMenu menu) { + return menu.getIsFrame().equals(UserConstants.NO_FRAME) && StringUtils.ishttp(menu.getPath()); + } + + /** + * 是否为parent_view组件 + * + * @param menu 菜单信息 + * @return 结果 + */ + public boolean isParentView(SysMenu menu) { + return menu.getParentId().intValue() != 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType()); + } + + /** + * 根据父节点的ID获取所有子节点 + * + * @param list 分类表 + * @param parentId 传入的父节点ID + * @return String + */ + public List getChildPerms(List list, int parentId) { + List returnList = new ArrayList(); + for (Iterator iterator = list.iterator(); iterator.hasNext();) { + SysMenu t = (SysMenu) iterator.next(); + // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点 + if (t.getParentId() == parentId) { + recursionFn(list, t); + returnList.add(t); + } + } + return returnList; + } + + /** + * 递归列表 + * + * @param list 分类表 + * @param t 子节点 + */ + private void recursionFn(List list, SysMenu t) { + // 得到子节点列表 + List childList = getChildList(list, t); + t.setChildren(childList); + for (SysMenu tChild : childList) { + if (hasChild(list, tChild)) { + recursionFn(list, tChild); + } + } + } + + /** + * 得到子节点列表 + */ + private List getChildList(List list, SysMenu t) { + List tlist = new ArrayList(); + Iterator it = list.iterator(); + while (it.hasNext()) { + SysMenu n = (SysMenu) it.next(); + if (n.getParentId().longValue() == t.getMenuId().longValue()) { + tlist.add(n); + } + } + return tlist; + } + + /** + * 判断是否有子节点 + */ + private boolean hasChild(List list, SysMenu t) { + return getChildList(list, t).size() > 0; + } + + /** + * 内链域名特殊字符替换 + * + * @return 替换后的内链域名 + */ + public String innerLinkReplaceEach(String path) { + return StringUtils.replaceEach(path, new String[] { Constants.HTTP, Constants.HTTPS, Constants.WWW, "." }, + new String[] { "", "", "", "/" }); + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/impl/SysNoticeServiceImpl.java b/boyue-system/src/main/java/com/boyue/system/service/impl/SysNoticeServiceImpl.java new file mode 100644 index 0000000..f45df0e --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/impl/SysNoticeServiceImpl.java @@ -0,0 +1,92 @@ +package com.boyue.system.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.boyue.system.domain.SysNotice; +import com.boyue.system.mapper.SysNoticeMapper; +import com.boyue.system.service.ISysNoticeService; + +/** + * 公告 服务层实现 + * + * @author boyue + */ +@Service +public class SysNoticeServiceImpl implements ISysNoticeService +{ + @Autowired + private SysNoticeMapper noticeMapper; + + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + @Override + public SysNotice selectNoticeById(Long noticeId) + { + return noticeMapper.selectNoticeById(noticeId); + } + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + @Override + public List selectNoticeList(SysNotice notice) + { + return noticeMapper.selectNoticeList(notice); + } + + /** + * 新增公告 + * + * @param notice 公告信息 + * @return 结果 + */ + @Override + public int insertNotice(SysNotice notice) + { + return noticeMapper.insertNotice(notice); + } + + /** + * 修改公告 + * + * @param notice 公告信息 + * @return 结果 + */ + @Override + public int updateNotice(SysNotice notice) + { + return noticeMapper.updateNotice(notice); + } + + /** + * 删除公告对象 + * + * @param noticeId 公告ID + * @return 结果 + */ + @Override + public int deleteNoticeById(Long noticeId) + { + return noticeMapper.deleteNoticeById(noticeId); + } + + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + @Override + public int deleteNoticeByIds(Long[] noticeIds) + { + return noticeMapper.deleteNoticeByIds(noticeIds); + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/impl/SysOperLogServiceImpl.java b/boyue-system/src/main/java/com/boyue/system/service/impl/SysOperLogServiceImpl.java new file mode 100644 index 0000000..f9a027f --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/impl/SysOperLogServiceImpl.java @@ -0,0 +1,99 @@ +package com.boyue.system.service.impl; + +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.boyue.system.domain.SysOperLog; +import com.boyue.system.mapper.SysOperLogMapper; +import com.boyue.system.service.ISysOperLogService; + +/** + * 操作日志 服务层处理 + * + * @author boyue + */ +@Service +public class SysOperLogServiceImpl implements ISysOperLogService +{ + @Autowired + private SysOperLogMapper operLogMapper; + + /** + * 新增操作日志 + * + * @param operLog 操作日志对象 + */ + @Override + public void insertOperlog(SysOperLog operLog) + { + operLogMapper.insertOperlog(operLog); + } + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + @Override + public List selectOperLogList(SysOperLog operLog) + { + return operLogMapper.selectOperLogList(operLog); + } + + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + @Override + public int deleteOperLogByIds(Long[] operIds) + { + return operLogMapper.deleteOperLogByIds(operIds); + } + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + @Override + public SysOperLog selectOperLogById(Long operId) + { + return operLogMapper.selectOperLogById(operId); + } + + /** + * 清空操作日志 + */ + @Override + public void cleanOperLog() + { + operLogMapper.cleanOperLog(); + } + + @Override + public List> getSuccessOperationStats(SysOperLog operLog) { + return operLogMapper.getSuccessOperationStats(operLog); + } + + @Override + public List> getFailureOperationStats(SysOperLog operLog) { + return operLogMapper.getFailureOperationStats(operLog); + } + + @Override + public List> getStatusStats(SysOperLog operLog) { + return operLogMapper.getStatusStats(operLog); + } + + @Override + public List> getModuleOperationStats(SysOperLog operLog) { + return operLogMapper.getModuleOperationStats(operLog); + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/impl/SysPostServiceImpl.java b/boyue-system/src/main/java/com/boyue/system/service/impl/SysPostServiceImpl.java new file mode 100644 index 0000000..170c99a --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/impl/SysPostServiceImpl.java @@ -0,0 +1,178 @@ +package com.boyue.system.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.boyue.common.constant.UserConstants; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.StringUtils; +import com.boyue.system.domain.SysPost; +import com.boyue.system.mapper.SysPostMapper; +import com.boyue.system.mapper.SysUserPostMapper; +import com.boyue.system.service.ISysPostService; + +/** + * 岗位信息 服务层处理 + * + * @author boyue + */ +@Service +public class SysPostServiceImpl implements ISysPostService +{ + @Autowired + private SysPostMapper postMapper; + + @Autowired + private SysUserPostMapper userPostMapper; + + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位信息集合 + */ + @Override + public List selectPostList(SysPost post) + { + return postMapper.selectPostList(post); + } + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + @Override + public List selectPostAll() + { + return postMapper.selectPostAll(); + } + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + @Override + public SysPost selectPostById(Long postId) + { + return postMapper.selectPostById(postId); + } + + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + @Override + public List selectPostListByUserId(Long userId) + { + return postMapper.selectPostListByUserId(userId); + } + + /** + * 校验岗位名称是否唯一 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public boolean checkPostNameUnique(SysPost post) + { + Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId(); + SysPost info = postMapper.checkPostNameUnique(post.getPostName()); + if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验岗位编码是否唯一 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public boolean checkPostCodeUnique(SysPost post) + { + Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId(); + SysPost info = postMapper.checkPostCodeUnique(post.getPostCode()); + if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + @Override + public int countUserPostById(Long postId) + { + return userPostMapper.countUserPostById(postId); + } + + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + @Override + public int deletePostById(Long postId) + { + return postMapper.deletePostById(postId); + } + + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 结果 + */ + @Override + public int deletePostByIds(Long[] postIds) + { + for (Long postId : postIds) + { + SysPost post = selectPostById(postId); + if (countUserPostById(postId) > 0) + { + throw new ServiceException("%1$s已分配,不能删除".formatted(post.getPostName())); + } + } + return postMapper.deletePostByIds(postIds); + } + + /** + * 新增保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public int insertPost(SysPost post) + { + return postMapper.insertPost(post); + } + + /** + * 修改保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public int updatePost(SysPost post) + { + return postMapper.updatePost(post); + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/impl/SysRoleServiceImpl.java b/boyue-system/src/main/java/com/boyue/system/service/impl/SysRoleServiceImpl.java new file mode 100644 index 0000000..a1adbc9 --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/impl/SysRoleServiceImpl.java @@ -0,0 +1,424 @@ +package com.boyue.system.service.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import com.boyue.common.annotation.DataScope; +import com.boyue.common.constant.UserConstants; +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.spring.SpringUtils; +import com.boyue.system.domain.SysRoleDept; +import com.boyue.system.domain.SysRoleMenu; +import com.boyue.system.domain.SysUserRole; +import com.boyue.system.mapper.SysRoleDeptMapper; +import com.boyue.system.mapper.SysRoleMapper; +import com.boyue.system.mapper.SysRoleMenuMapper; +import com.boyue.system.mapper.SysUserRoleMapper; +import com.boyue.system.service.ISysRoleService; + +/** + * 角色 业务层处理 + * + * @author boyue + */ +@Service +public class SysRoleServiceImpl implements ISysRoleService +{ + @Autowired + private SysRoleMapper roleMapper; + + @Autowired + private SysRoleMenuMapper roleMenuMapper; + + @Autowired + private SysUserRoleMapper userRoleMapper; + + @Autowired + private SysRoleDeptMapper roleDeptMapper; + + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + @Override + @DataScope(deptAlias = "d") + public List selectRoleList(SysRole role) + { + return roleMapper.selectRoleList(role); + } + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + @Override + public List selectRolesByUserId(Long userId) + { + List userRoles = roleMapper.selectRolePermissionByUserId(userId); + List roles = selectRoleAll(); + for (SysRole role : roles) + { + for (SysRole userRole : userRoles) + { + if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) + { + role.setFlag(true); + break; + } + } + } + return roles; + } + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + @Override + public Set selectRolePermissionByUserId(Long userId) + { + List perms = roleMapper.selectRolePermissionByUserId(userId); + Set permsSet = new HashSet<>(); + for (SysRole perm : perms) + { + if (StringUtils.isNotNull(perm)) + { + permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(","))); + } + } + return permsSet; + } + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + @Override + public List selectRoleAll() + { + return SpringUtils.getAopProxy(this).selectRoleList(new SysRole()); + } + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + @Override + public List selectRoleListByUserId(Long userId) + { + return roleMapper.selectRoleListByUserId(userId); + } + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + @Override + public SysRole selectRoleById(Long roleId) + { + return roleMapper.selectRoleById(roleId); + } + + /** + * 校验角色名称是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public boolean checkRoleNameUnique(SysRole role) + { + Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId(); + SysRole info = roleMapper.checkRoleNameUnique(role.getRoleName()); + if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验角色权限是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public boolean checkRoleKeyUnique(SysRole role) + { + Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId(); + SysRole info = roleMapper.checkRoleKeyUnique(role.getRoleKey()); + if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验角色是否允许操作 + * + * @param role 角色信息 + */ + @Override + public void checkRoleAllowed(SysRole role) + { + if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin()) + { + throw new ServiceException("不允许操作超级管理员角色"); + } + } + + /** + * 校验角色是否有数据权限 + * + * @param roleId 角色id + */ + @Override + public void checkRoleDataScope(Long roleId) + { + if (!SysUser.isAdmin(SecurityUtils.getUserId())) + { + SysRole role = new SysRole(); + role.setRoleId(roleId); + List roles = SpringUtils.getAopProxy(this).selectRoleList(role); + if (StringUtils.isEmpty(roles)) + { + throw new ServiceException("没有权限访问角色数据!"); + } + } + } + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + @Override + public int countUserRoleByRoleId(Long roleId) + { + return userRoleMapper.countUserRoleByRoleId(roleId); + } + + /** + * 新增保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + @Transactional + public int insertRole(SysRole role) + { + // 新增角色信息 + roleMapper.insertRole(role); + return insertRoleMenu(role); + } + + /** + * 修改保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + @Transactional + public int updateRole(SysRole role) + { + // 修改角色信息 + roleMapper.updateRole(role); + // 删除角色与菜单关联 + roleMenuMapper.deleteRoleMenuByRoleId(role.getRoleId()); + return insertRoleMenu(role); + } + + /** + * 修改角色状态 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public int updateRoleStatus(SysRole role) + { + return roleMapper.updateRole(role); + } + + /** + * 修改数据权限信息 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + @Transactional + public int authDataScope(SysRole role) + { + // 修改角色信息 + roleMapper.updateRole(role); + // 删除角色与部门关联 + roleDeptMapper.deleteRoleDeptByRoleId(role.getRoleId()); + // 新增角色和部门信息(数据权限) + return insertRoleDept(role); + } + + /** + * 新增角色菜单信息 + * + * @param role 角色对象 + */ + public int insertRoleMenu(SysRole role) + { + int rows = 1; + // 新增用户与角色管理 + List list = new ArrayList(); + for (Long menuId : role.getMenuIds()) + { + SysRoleMenu rm = new SysRoleMenu(); + rm.setRoleId(role.getRoleId()); + rm.setMenuId(menuId); + list.add(rm); + } + if (list.size() > 0) + { + rows = roleMenuMapper.batchRoleMenu(list); + } + return rows; + } + + /** + * 新增角色部门信息(数据权限) + * + * @param role 角色对象 + */ + public int insertRoleDept(SysRole role) + { + int rows = 1; + // 新增角色与部门(数据权限)管理 + List list = new ArrayList(); + for (Long deptId : role.getDeptIds()) + { + SysRoleDept rd = new SysRoleDept(); + rd.setRoleId(role.getRoleId()); + rd.setDeptId(deptId); + list.add(rd); + } + if (list.size() > 0) + { + rows = roleDeptMapper.batchRoleDept(list); + } + return rows; + } + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + @Override + @Transactional + public int deleteRoleById(Long roleId) + { + // 删除角色与菜单关联 + roleMenuMapper.deleteRoleMenuByRoleId(roleId); + // 删除角色与部门关联 + roleDeptMapper.deleteRoleDeptByRoleId(roleId); + return roleMapper.deleteRoleById(roleId); + } + + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + @Override + @Transactional + public int deleteRoleByIds(Long[] roleIds) + { + for (Long roleId : roleIds) + { + checkRoleAllowed(new SysRole(roleId)); + checkRoleDataScope(roleId); + SysRole role = selectRoleById(roleId); + if (countUserRoleByRoleId(roleId) > 0) + { + throw new ServiceException("%1$s已分配,不能删除".formatted(role.getRoleName())); + } + } + // 删除角色与菜单关联 + roleMenuMapper.deleteRoleMenu(roleIds); + // 删除角色与部门关联 + roleDeptMapper.deleteRoleDept(roleIds); + return roleMapper.deleteRoleByIds(roleIds); + } + + /** + * 取消授权用户角色 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + @Override + public int deleteAuthUser(SysUserRole userRole) + { + return userRoleMapper.deleteUserRoleInfo(userRole); + } + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要取消授权的用户数据ID + * @return 结果 + */ + @Override + public int deleteAuthUsers(Long roleId, Long[] userIds) + { + return userRoleMapper.deleteUserRoleInfos(roleId, userIds); + } + + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要授权的用户数据ID + * @return 结果 + */ + @Override + public int insertAuthUsers(Long roleId, Long[] userIds) + { + // 新增用户与角色管理 + List list = new ArrayList(); + for (Long userId : userIds) + { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + list.add(ur); + } + return userRoleMapper.batchUserRole(list); + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/impl/SysUserOnlineServiceImpl.java b/boyue-system/src/main/java/com/boyue/system/service/impl/SysUserOnlineServiceImpl.java new file mode 100644 index 0000000..2c7c22c --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/impl/SysUserOnlineServiceImpl.java @@ -0,0 +1,96 @@ +package com.boyue.system.service.impl; + +import org.springframework.stereotype.Service; +import com.boyue.common.core.domain.model.LoginUser; +import com.boyue.common.utils.StringUtils; +import com.boyue.system.domain.SysUserOnline; +import com.boyue.system.service.ISysUserOnlineService; + +/** + * 在线用户 服务层处理 + * + * @author boyue + */ +@Service +public class SysUserOnlineServiceImpl implements ISysUserOnlineService +{ + /** + * 通过登录地址查询信息 + * + * @param ipaddr 登录地址 + * @param user 用户信息 + * @return 在线用户信息 + */ + @Override + public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user) + { + if (StringUtils.equals(ipaddr, user.getIpaddr())) + { + return loginUserToUserOnline(user); + } + return null; + } + + /** + * 通过用户名称查询信息 + * + * @param userName 用户名称 + * @param user 用户信息 + * @return 在线用户信息 + */ + @Override + public SysUserOnline selectOnlineByUserName(String userName, LoginUser user) + { + if (StringUtils.equals(userName, user.getUsername())) + { + return loginUserToUserOnline(user); + } + return null; + } + + /** + * 通过登录地址/用户名称查询信息 + * + * @param ipaddr 登录地址 + * @param userName 用户名称 + * @param user 用户信息 + * @return 在线用户信息 + */ + @Override + public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user) + { + if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername())) + { + return loginUserToUserOnline(user); + } + return null; + } + + /** + * 设置在线用户信息 + * + * @param user 用户信息 + * @return 在线用户 + */ + @Override + public SysUserOnline loginUserToUserOnline(LoginUser user) + { + if (StringUtils.isNull(user) || StringUtils.isNull(user.getUser())) + { + return null; + } + SysUserOnline sysUserOnline = new SysUserOnline(); + sysUserOnline.setTokenId(user.getToken()); + sysUserOnline.setUserName(user.getUsername()); + sysUserOnline.setIpaddr(user.getIpaddr()); + sysUserOnline.setLoginLocation(user.getLoginLocation()); + sysUserOnline.setBrowser(user.getBrowser()); + sysUserOnline.setOs(user.getOs()); + sysUserOnline.setLoginTime(user.getLoginTime()); + if (StringUtils.isNotNull(user.getUser().getDept())) + { + sysUserOnline.setDeptName(user.getUser().getDept().getDeptName()); + } + return sysUserOnline; + } +} diff --git a/boyue-system/src/main/java/com/boyue/system/service/impl/SysUserServiceImpl.java b/boyue-system/src/main/java/com/boyue/system/service/impl/SysUserServiceImpl.java new file mode 100644 index 0000000..cf9e1db --- /dev/null +++ b/boyue-system/src/main/java/com/boyue/system/service/impl/SysUserServiceImpl.java @@ -0,0 +1,515 @@ +package com.boyue.system.service.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import com.boyue.common.annotation.DataScope; +import com.boyue.common.constant.UserConstants; +import com.boyue.common.core.domain.entity.SysRole; +import com.boyue.common.core.domain.entity.SysUser; +import com.boyue.common.exception.ServiceException; +import com.boyue.common.utils.SecurityUtils; +import com.boyue.common.utils.StringUtils; +import com.boyue.common.utils.bean.BeanValidators; +import com.boyue.common.utils.spring.SpringUtils; +import com.boyue.system.domain.SysPost; +import com.boyue.system.domain.SysUserPost; +import com.boyue.system.domain.SysUserRole; +import com.boyue.system.mapper.SysPostMapper; +import com.boyue.system.mapper.SysRoleMapper; +import com.boyue.system.mapper.SysUserMapper; +import com.boyue.system.mapper.SysUserPostMapper; +import com.boyue.system.mapper.SysUserRoleMapper; +import com.boyue.system.service.ISysConfigService; +import com.boyue.system.service.ISysUserService; + +import jakarta.validation.Validator; + +/** + * 用户 业务层处理 + * + * @author boyue + */ +@Service +public class SysUserServiceImpl implements ISysUserService { + private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class); + + @Autowired + private SysUserMapper userMapper; + + @Autowired + private SysRoleMapper roleMapper; + + @Autowired + private SysPostMapper postMapper; + + @Autowired + private SysUserRoleMapper userRoleMapper; + + @Autowired + private SysUserPostMapper userPostMapper; + + @Autowired + private ISysConfigService configService; + + @Autowired + protected Validator validator; + + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List selectUserList(SysUser user) { + return userMapper.selectUserList(user); + } + + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List selectAllocatedList(SysUser user) { + return userMapper.selectAllocatedList(user); + } + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List selectUnallocatedList(SysUser user) { + return userMapper.selectUnallocatedList(user); + } + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + @Override + public SysUser selectUserByUserName(String userName) { + return userMapper.selectUserByUserName(userName); + } + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + @Override + public SysUser selectUserById(Long userId) { + return userMapper.selectUserById(userId); + } + + /** + * 通过手机号查询用户 + * + * @param phone 用户ID + * @return 用户对象信息 + */ + @Override + public SysUser selectUserByPhone(String phone) { + return userMapper.selectUserByPhone(phone); + } + + /** + * 通过邮箱查询用户 + * + * @param email 用户名 + * @return 用户对象信息 + */ + @Override + public SysUser selectUserByEmail(String email){ + return userMapper.selectUserByEmail(email); + } + + /** + * 查询用户所属角色组 + * + * @param userName 用户名 + * @return 结果 + */ + @Override + public String selectUserRoleGroup(String userName) { + List list = roleMapper.selectRolesByUserName(userName); + if (CollectionUtils.isEmpty(list)) { + return StringUtils.EMPTY; + } + return list.stream().map(SysRole::getRoleName).collect(Collectors.joining(",")); + } + + /** + * 查询用户所属岗位组 + * + * @param userName 用户名 + * @return 结果 + */ + @Override + public String selectUserPostGroup(String userName) { + List list = postMapper.selectPostsByUserName(userName); + if (CollectionUtils.isEmpty(list)) { + return StringUtils.EMPTY; + } + return list.stream().map(SysPost::getPostName).collect(Collectors.joining(",")); + } + + /** + * 校验用户名称是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public boolean checkUserNameUnique(SysUser user) { + Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); + SysUser info = userMapper.checkUserNameUnique(user.getUserName()); + if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验手机号码是否唯一 + * + * @param user 用户信息 + * @return + */ + @Override + public boolean checkPhoneUnique(SysUser user) { + Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); + SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber()); + if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验email是否唯一 + * + * @param user 用户信息 + * @return + */ + @Override + public boolean checkEmailUnique(SysUser user) { + Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); + SysUser info = userMapper.checkEmailUnique(user.getEmail()); + if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验用户是否允许操作 + * + * @param user 用户信息 + */ + @Override + public void checkUserAllowed(SysUser user) { + if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin()) { + throw new ServiceException("不允许操作超级管理员用户"); + } + } + + /** + * 校验用户是否有数据权限 + * + * @param userId 用户id + */ + @Override + public void checkUserDataScope(Long userId) { + if (!SysUser.isAdmin(SecurityUtils.getUserId())) { + SysUser user = new SysUser(); + user.setUserId(userId); + List users = SpringUtils.getAopProxy(this).selectUserList(user); + if (StringUtils.isEmpty(users)) { + throw new ServiceException("没有权限访问用户数据!"); + } + } + } + + /** + * 新增保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @Transactional + public int insertUser(SysUser user) { + // 新增用户信息 + int rows = userMapper.insertUser(user); + // 新增用户岗位关联 + insertUserPost(user); + // 新增用户与角色管理 + insertUserRole(user); + return rows; + } + + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public boolean registerUser(SysUser user) { + return userMapper.insertUser(user) > 0; + } + + /** + * 修改保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @Transactional + public int updateUser(SysUser user) { + Long userId = user.getUserId(); + // 删除用户与角色关联 + userRoleMapper.deleteUserRoleByUserId(userId); + // 新增用户与角色管理 + insertUserRole(user); + // 删除用户与岗位关联 + userPostMapper.deleteUserPostByUserId(userId); + // 新增用户与岗位管理 + insertUserPost(user); + return userMapper.updateUser(user); + } + + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + @Override + @Transactional + public void insertUserAuth(Long userId, Long[] roleIds) { + userRoleMapper.deleteUserRoleByUserId(userId); + insertUserRole(userId, roleIds); + } + + /** + * 修改用户状态 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public int updateUserStatus(SysUser user) { + return userMapper.updateUser(user); + } + + /** + * 修改用户基本信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public int updateUserProfile(SysUser user) { + return userMapper.updateUser(user); + } + + /** + * 修改用户头像 + * + * @param userName 用户名 + * @param avatar 头像地址 + * @return 结果 + */ + @Override + public boolean updateUserAvatar(String userName, String avatar) { + return userMapper.updateUserAvatar(userName, avatar) > 0; + } + + /** + * 重置用户密码 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public int resetPwd(SysUser user) { + return userMapper.updateUser(user); + } + + /** + * 重置用户密码 + * + * @param userName 用户名 + * @param password 密码 + * @return 结果 + */ + @Override + public int resetUserPwd(String userName, String password) { + return userMapper.resetUserPwd(userName, password); + } + + /** + * 新增用户角色信息 + * + * @param user 用户对象 + */ + public void insertUserRole(SysUser user) { + this.insertUserRole(user.getUserId(), user.getRoleIds()); + } + + /** + * 新增用户岗位信息 + * + * @param user 用户对象 + */ + public void insertUserPost(SysUser user) { + Long[] posts = user.getPostIds(); + if (StringUtils.isNotEmpty(posts)) { + // 新增用户与岗位管理 + List list = new ArrayList(posts.length); + for (Long postId : posts) { + SysUserPost up = new SysUserPost(); + up.setUserId(user.getUserId()); + up.setPostId(postId); + list.add(up); + } + userPostMapper.batchUserPost(list); + } + } + + /** + * 新增用户角色信息 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + public void insertUserRole(Long userId, Long[] roleIds) { + if (StringUtils.isNotEmpty(roleIds)) { + // 新增用户与角色管理 + List list = new ArrayList(roleIds.length); + for (Long roleId : roleIds) { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + list.add(ur); + } + userRoleMapper.batchUserRole(list); + } + } + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + @Transactional + public int deleteUserById(Long userId) { + // 删除用户与角色关联 + userRoleMapper.deleteUserRoleByUserId(userId); + // 删除用户与岗位表 + userPostMapper.deleteUserPostByUserId(userId); + return userMapper.deleteUserById(userId); + } + + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + @Override + @Transactional + public int deleteUserByIds(Long[] userIds) { + for (Long userId : userIds) { + checkUserAllowed(new SysUser(userId)); + checkUserDataScope(userId); + } + // 删除用户与角色关联 + userRoleMapper.deleteUserRole(userIds); + // 删除用户与岗位关联 + userPostMapper.deleteUserPost(userIds); + return userMapper.deleteUserByIds(userIds); + } + + /** + * 导入用户数据 + * + * @param userList 用户数据列表 + * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 + * @param operName 操作用户 + * @return 结果 + */ + @Override + public String importUser(List userList, Boolean isUpdateSupport, String operName) { + if (StringUtils.isNull(userList) || userList.size() == 0) { + throw new ServiceException("导入用户数据不能为空!"); + } + int successNum = 0; + int failureNum = 0; + StringBuilder successMsg = new StringBuilder(); + StringBuilder failureMsg = new StringBuilder(); + String password = configService.selectConfigByKey("sys.user.initPassword"); + for (SysUser user : userList) { + try { + // 验证是否存在这个用户 + SysUser u = userMapper.selectUserByUserName(user.getUserName()); + if (StringUtils.isNull(u)) { + BeanValidators.validateWithException(validator, user); + user.setPassword(SecurityUtils.encryptPassword(password)); + user.setCreateBy(operName); + userMapper.insertUser(user); + successNum++; + successMsg.append("
" + successNum + "、账号 " + user.getUserName() + " 导入成功"); + } else if (isUpdateSupport) { + BeanValidators.validateWithException(validator, user); + checkUserAllowed(u); + checkUserDataScope(u.getUserId()); + user.setUserId(u.getUserId()); + user.setUpdateBy(operName); + userMapper.updateUser(user); + successNum++; + successMsg.append("
" + successNum + "、账号 " + user.getUserName() + " 更新成功"); + } else { + failureNum++; + failureMsg.append("
" + failureNum + "、账号 " + user.getUserName() + " 已存在"); + } + } catch (Exception e) { + failureNum++; + String msg = "
" + failureNum + "、账号 " + user.getUserName() + " 导入失败:"; + failureMsg.append(msg + e.getMessage()); + log.error(msg, e); + } + } + if (failureNum > 0) { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new ServiceException(failureMsg.toString()); + } else { + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } +} diff --git a/boyue-system/src/main/resources/mapper/system/SysConfigMapper.xml b/boyue-system/src/main/resources/mapper/system/SysConfigMapper.xml new file mode 100644 index 0000000..80300c3 --- /dev/null +++ b/boyue-system/src/main/resources/mapper/system/SysConfigMapper.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + select config_id, config_name, config_key, config_value, config_type, create_by, create_time, update_by, update_time, remark + from sys_config + + + + + + + and config_id = #{configId} + + + and config_key = #{configKey} + + + + + + + + + + + + + + insert into sys_config ( + config_name, + config_key, + config_value, + config_type, + create_by, + remark, + create_time + )values( + #{configName}, + #{configKey}, + #{configValue}, + #{configType}, + #{createBy}, + #{remark}, + sysdate() + ) + + + + update sys_config + + config_name = #{configName}, + config_key = #{configKey}, + config_value = #{configValue}, + config_type = #{configType}, + update_by = #{updateBy}, + remark = #{remark}, + update_time = sysdate() + + where config_id = #{configId} + + + + delete from sys_config where config_id = #{configId} + + + + delete from sys_config where config_id in + + #{configId} + + + + \ No newline at end of file diff --git a/boyue-system/src/main/resources/mapper/system/SysDeptMapper.xml b/boyue-system/src/main/resources/mapper/system/SysDeptMapper.xml new file mode 100644 index 0000000..c42daef --- /dev/null +++ b/boyue-system/src/main/resources/mapper/system/SysDeptMapper.xml @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time + from sys_dept d + + + + + + + + + + + + + + + + + + + + insert into sys_dept( + dept_id, + parent_id, + dept_name, + ancestors, + order_num, + leader, + phone, + email, + status, + create_by, + create_time + )values( + #{deptId}, + #{parentId}, + #{deptName}, + #{ancestors}, + #{orderNum}, + #{leader}, + #{phone}, + #{email}, + #{status}, + #{createBy}, + sysdate() + ) + + + + update sys_dept + + parent_id = #{parentId}, + dept_name = #{deptName}, + ancestors = #{ancestors}, + order_num = #{orderNum}, + leader = #{leader}, + phone = #{phone}, + email = #{email}, + status = #{status}, + update_by = #{updateBy}, + update_time = sysdate() + + where dept_id = #{deptId} + + + + update sys_dept set ancestors = + + when #{item.deptId} then #{item.ancestors} + + where dept_id in + + #{item.deptId} + + + + + update sys_dept set status = '0' where dept_id in + + #{deptId} + + + + + update sys_dept set del_flag = '2' where dept_id = #{deptId} + + + \ No newline at end of file diff --git a/boyue-system/src/main/resources/mapper/system/SysDictDataMapper.xml b/boyue-system/src/main/resources/mapper/system/SysDictDataMapper.xml new file mode 100644 index 0000000..989a5cf --- /dev/null +++ b/boyue-system/src/main/resources/mapper/system/SysDictDataMapper.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + select dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark + from sys_dict_data + + + + + + + + + + + + + + delete from sys_dict_data where dict_code = #{dictCode} + + + + delete from sys_dict_data where dict_code in + + #{dictCode} + + + + + update sys_dict_data + + dict_sort = #{dictSort}, + dict_label = #{dictLabel}, + dict_value = #{dictValue}, + dict_type = #{dictType}, + css_class = #{cssClass}, + list_class = #{listClass}, + is_default = #{isDefault}, + status = #{status}, + remark = #{remark}, + update_by = #{updateBy}, + update_time = sysdate() + + where dict_code = #{dictCode} + + + + update sys_dict_data set dict_type = #{newDictType} where dict_type = #{oldDictType} + + + + insert into sys_dict_data( + dict_sort, + dict_label, + dict_value, + dict_type, + css_class, + list_class, + is_default, + status, + remark, + create_by, + create_time + )values( + #{dictSort}, + #{dictLabel}, + #{dictValue}, + #{dictType}, + #{cssClass}, + #{listClass}, + #{isDefault}, + #{status}, + #{remark}, + #{createBy}, + sysdate() + ) + + + \ No newline at end of file diff --git a/boyue-system/src/main/resources/mapper/system/SysDictTypeMapper.xml b/boyue-system/src/main/resources/mapper/system/SysDictTypeMapper.xml new file mode 100644 index 0000000..a62b081 --- /dev/null +++ b/boyue-system/src/main/resources/mapper/system/SysDictTypeMapper.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + select dict_id, dict_name, dict_type, status, create_by, create_time, remark + from sys_dict_type + + + + + + + + + + + + + + delete from sys_dict_type where dict_id = #{dictId} + + + + delete from sys_dict_type where dict_id in + + #{dictId} + + + + + update sys_dict_type + + dict_name = #{dictName}, + dict_type = #{dictType}, + status = #{status}, + remark = #{remark}, + update_by = #{updateBy}, + update_time = sysdate() + + where dict_id = #{dictId} + + + + insert into sys_dict_type( + dict_name, + dict_type, + status, + remark, + create_by, + create_time + )values( + #{dictName}, + #{dictType}, + #{status}, + #{remark}, + #{createBy}, + sysdate() + ) + + + \ No newline at end of file diff --git a/boyue-system/src/main/resources/mapper/system/SysLogininforMapper.xml b/boyue-system/src/main/resources/mapper/system/SysLogininforMapper.xml new file mode 100644 index 0000000..c68531e --- /dev/null +++ b/boyue-system/src/main/resources/mapper/system/SysLogininforMapper.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + insert into sys_logininfor (user_name, status, ipaddr, login_location, browser, os, msg, login_time) + values (#{userName}, #{status}, #{ipaddr}, #{loginLocation}, #{browser}, #{os}, #{msg}, sysdate()) + + + + + + delete from sys_logininfor where info_id in + + #{infoId} + + + + + truncate table sys_logininfor + + + \ No newline at end of file diff --git a/boyue-system/src/main/resources/mapper/system/SysMenuMapper.xml b/boyue-system/src/main/resources/mapper/system/SysMenuMapper.xml new file mode 100644 index 0000000..0c27399 --- /dev/null +++ b/boyue-system/src/main/resources/mapper/system/SysMenuMapper.xml @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select menu_id, menu_name, parent_id, order_num, path, component, sys_menu.query, route_name, is_frame, is_cache, menu_type, visible, status, COALESCE(perms,'') as perms, icon, create_time + from sys_menu + + + + + + + + + + + + + + + + + + + + + + + + + + update sys_menu + + menu_name = #{menuName}, + parent_id = #{parentId}, + order_num = #{orderNum}, + path = #{path}, + component = #{component}, + query = #{query}, + route_name = #{routeName}, + is_frame = #{isFrame}, + is_cache = #{isCache}, + menu_type = #{menuType}, + visible = #{visible}, + status = #{status}, + perms = #{perms}, + icon = #{icon}, + remark = #{remark}, + update_by = #{updateBy}, + update_time = sysdate() + + where menu_id = #{menuId} + + + + insert into sys_menu( + menu_id, + parent_id, + menu_name, + order_num, + path, + component, + query, + route_name, + is_frame, + is_cache, + menu_type, + visible, + status, + perms, + icon, + remark, + create_by, + create_time + )values( + #{menuId}, + #{parentId}, + #{menuName}, + #{orderNum}, + #{path}, + #{component}, + #{query}, + #{routeName}, + #{isFrame}, + #{isCache}, + #{menuType}, + #{visible}, + #{status}, + #{perms}, + #{icon}, + #{remark}, + #{createBy}, + sysdate() + ) + + + + delete from sys_menu where menu_id = #{menuId} + + + \ No newline at end of file diff --git a/boyue-system/src/main/resources/mapper/system/SysNoticeMapper.xml b/boyue-system/src/main/resources/mapper/system/SysNoticeMapper.xml new file mode 100644 index 0000000..71e2d5e --- /dev/null +++ b/boyue-system/src/main/resources/mapper/system/SysNoticeMapper.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + select notice_id, notice_title, notice_type, cast(notice_content as char) as notice_content, status, create_by, create_time, update_by, update_time, remark + from sys_notice + + + + + + + + insert into sys_notice ( + notice_title, + notice_type, + notice_content, + status, + remark, + create_by, + create_time + )values( + #{noticeTitle}, + #{noticeType}, + #{noticeContent}, + #{status}, + #{remark}, + #{createBy}, + sysdate() + ) + + + + update sys_notice + + notice_title = #{noticeTitle}, + notice_type = #{noticeType}, + notice_content = #{noticeContent}, + status = #{status}, + update_by = #{updateBy}, + update_time = sysdate() + + where notice_id = #{noticeId} + + + + delete from sys_notice where notice_id = #{noticeId} + + + + delete from sys_notice where notice_id in + + #{noticeId} + + + + \ No newline at end of file diff --git a/boyue-system/src/main/resources/mapper/system/SysOperLogMapper.xml b/boyue-system/src/main/resources/mapper/system/SysOperLogMapper.xml new file mode 100644 index 0000000..0e70e36 --- /dev/null +++ b/boyue-system/src/main/resources/mapper/system/SysOperLogMapper.xml @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + select oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time, cost_time + from sys_oper_log + + + + insert into sys_oper_log(title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, cost_time, oper_time) + values (#{title}, #{businessType}, #{method}, #{requestMethod}, #{operatorType}, #{operName}, #{deptName}, #{operUrl}, #{operIp}, #{operLocation}, #{operParam}, #{jsonResult}, #{status}, #{errorMsg}, #{costTime}, sysdate()) + + + + + + delete from sys_oper_log where oper_id in + + #{operId} + + + + + + + truncate table sys_oper_log + + + + + + AND title like concat('%', #{title}, '%') + + + AND business_type = #{businessType} + + + AND request_method = #{requestMethod} + + + AND business_type in + + #{businessType} + + + + AND status = #{status} + + + AND oper_time >= #{params.beginTime} + + + AND oper_time <= #{params.endTime} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/boyue-system/src/main/resources/mapper/system/SysPostMapper.xml b/boyue-system/src/main/resources/mapper/system/SysPostMapper.xml new file mode 100644 index 0000000..a3b32f0 --- /dev/null +++ b/boyue-system/src/main/resources/mapper/system/SysPostMapper.xml @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + select post_id, post_code, post_name, post_sort, status, create_by, create_time, remark + from sys_post + + + + + + + + + + + + + + + + + + update sys_post + + post_code = #{postCode}, + post_name = #{postName}, + post_sort = #{postSort}, + status = #{status}, + remark = #{remark}, + update_by = #{updateBy}, + update_time = sysdate() + + where post_id = #{postId} + + + + insert into sys_post( + post_id, + post_code, + post_name, + post_sort, + status, + remark, + create_by, + create_time + )values( + #{postId}, + #{postCode}, + #{postName}, + #{postSort}, + #{status}, + #{remark}, + #{createBy}, + sysdate() + ) + + + + delete from sys_post where post_id = #{postId} + + + + delete from sys_post where post_id in + + #{postId} + + + + \ No newline at end of file diff --git a/boyue-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml b/boyue-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml new file mode 100644 index 0000000..114ddf8 --- /dev/null +++ b/boyue-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + delete from sys_role_dept where role_id=#{roleId} + + + + + + delete from sys_role_dept where role_id in + + #{roleId} + + + + + insert into sys_role_dept(role_id, dept_id) values + + (#{item.roleId},#{item.deptId}) + + + + \ No newline at end of file diff --git a/boyue-system/src/main/resources/mapper/system/SysRoleMapper.xml b/boyue-system/src/main/resources/mapper/system/SysRoleMapper.xml new file mode 100644 index 0000000..6d7f72f --- /dev/null +++ b/boyue-system/src/main/resources/mapper/system/SysRoleMapper.xml @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + select distinct r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.menu_check_strictly, r.dept_check_strictly, + r.status, r.del_flag, r.create_time, r.remark + from sys_role r + left join sys_user_role ur on ur.role_id = r.role_id + left join sys_user u on u.user_id = ur.user_id + left join sys_dept d on u.dept_id = d.dept_id + + + + + + + + + + + + + + + + + + + + insert into sys_role( + role_id, + role_name, + role_key, + role_sort, + data_scope, + menu_check_strictly, + dept_check_strictly, + status, + remark, + create_by, + create_time + )values( + #{roleId}, + #{roleName}, + #{roleKey}, + #{roleSort}, + #{dataScope}, + #{menuCheckStrictly}, + #{deptCheckStrictly}, + #{status}, + #{remark}, + #{createBy}, + sysdate() + ) + + + + update sys_role + + role_name = #{roleName}, + role_key = #{roleKey}, + role_sort = #{roleSort}, + data_scope = #{dataScope}, + menu_check_strictly = #{menuCheckStrictly}, + dept_check_strictly = #{deptCheckStrictly}, + status = #{status}, + remark = #{remark}, + update_by = #{updateBy}, + update_time = sysdate() + + where role_id = #{roleId} + + + + update sys_role set del_flag = '2' where role_id = #{roleId} + + + + update sys_role set del_flag = '2' where role_id in + + #{roleId} + + + + \ No newline at end of file diff --git a/boyue-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml b/boyue-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml new file mode 100644 index 0000000..0093f76 --- /dev/null +++ b/boyue-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + delete from sys_role_menu where role_id=#{roleId} + + + + delete from sys_role_menu where role_id in + + #{roleId} + + + + + insert into sys_role_menu(role_id, menu_id) values + + (#{item.roleId},#{item.menuId}) + + + + \ No newline at end of file diff --git a/boyue-system/src/main/resources/mapper/system/SysUserMapper.xml b/boyue-system/src/main/resources/mapper/system/SysUserMapper.xml new file mode 100644 index 0000000..8e618fa --- /dev/null +++ b/boyue-system/src/main/resources/mapper/system/SysUserMapper.xml @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, + d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status, + r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status + from sys_user u + left join sys_dept d on u.dept_id = d.dept_id + left join sys_user_role ur on u.user_id = ur.user_id + left join sys_role r on r.role_id = ur.role_id + + + + + + + + + + + + + + + + + + + + + + + + insert into sys_user( + user_id, + dept_id, + user_name, + nick_name, + email, + avatar, + phonenumber, + sex, + password, + status, + create_by, + remark, + create_time + )values( + #{userId}, + #{deptId}, + #{userName}, + #{nickName}, + #{email}, + #{avatar}, + #{phonenumber}, + #{sex}, + #{password}, + #{status}, + #{createBy}, + #{remark}, + sysdate() + ) + + + + update sys_user + + dept_id = #{deptId}, + user_name = #{userName}, + nick_name = #{nickName}, + email = #{email}, + phonenumber = #{phonenumber}, + sex = #{sex}, + avatar = #{avatar}, + password = #{password}, + status = #{status}, + login_ip = #{loginIp}, + login_date = #{loginDate}, + update_by = #{updateBy}, + remark = #{remark}, + update_time = sysdate() + + where user_id = #{userId} + + + + update sys_user set status = #{status} where user_id = #{userId} + + + + update sys_user set avatar = #{avatar} where user_name = #{userName} + + + + update sys_user set password = #{password} where user_name = #{userName} + + + + update sys_user set del_flag = '2' where user_id = #{userId} + + + + update sys_user set del_flag = '2' where user_id in + + #{userId} + + + + \ No newline at end of file diff --git a/boyue-system/src/main/resources/mapper/system/SysUserPostMapper.xml b/boyue-system/src/main/resources/mapper/system/SysUserPostMapper.xml new file mode 100644 index 0000000..0578872 --- /dev/null +++ b/boyue-system/src/main/resources/mapper/system/SysUserPostMapper.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + delete from sys_user_post where user_id=#{userId} + + + + + + delete from sys_user_post where user_id in + + #{userId} + + + + + insert into sys_user_post(user_id, post_id) values + + (#{item.userId},#{item.postId}) + + + + \ No newline at end of file diff --git a/boyue-system/src/main/resources/mapper/system/SysUserRoleMapper.xml b/boyue-system/src/main/resources/mapper/system/SysUserRoleMapper.xml new file mode 100644 index 0000000..d5e62b0 --- /dev/null +++ b/boyue-system/src/main/resources/mapper/system/SysUserRoleMapper.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + delete from sys_user_role where user_id=#{userId} + + + + + + delete from sys_user_role where user_id in + + #{userId} + + + + + insert into sys_user_role(user_id, role_id) values + + (#{item.userId},#{item.roleId}) + + + + + delete from sys_user_role where user_id=#{userId} and role_id=#{roleId} + + + + delete from sys_user_role where role_id=#{roleId} and user_id in + + #{userId} + + + \ No newline at end of file diff --git a/doc/image/code-edit.png b/doc/image/code-edit.png new file mode 100644 index 0000000..5fc972b Binary files /dev/null and b/doc/image/code-edit.png differ diff --git a/doc/image/code-show.png b/doc/image/code-show.png new file mode 100644 index 0000000..24378e8 Binary files /dev/null and b/doc/image/code-show.png differ diff --git a/doc/image/form-edit.png b/doc/image/form-edit.png new file mode 100644 index 0000000..4054d34 Binary files /dev/null and b/doc/image/form-edit.png differ diff --git a/doc/image/logo.png b/doc/image/logo.png new file mode 100644 index 0000000..dab35ca Binary files /dev/null and b/doc/image/logo.png differ diff --git a/doc/image/online-mb-code.png b/doc/image/online-mb-code.png new file mode 100644 index 0000000..45a4973 Binary files /dev/null and b/doc/image/online-mb-code.png differ diff --git a/doc/image/online-mb-edit.png b/doc/image/online-mb-edit.png new file mode 100644 index 0000000..6f3b378 Binary files /dev/null and b/doc/image/online-mb-edit.png differ diff --git a/doc/image/online-mb-list.png b/doc/image/online-mb-list.png new file mode 100644 index 0000000..0e1c032 Binary files /dev/null and b/doc/image/online-mb-list.png differ diff --git a/doc/代码生成.drawio b/doc/代码生成.drawio new file mode 100644 index 0000000..c892fbe --- /dev/null +++ b/doc/代码生成.drawio @@ -0,0 +1,311 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/关于多数据源与分布式事务.drawio b/doc/关于多数据源与分布式事务.drawio new file mode 100644 index 0000000..54ac704 --- /dev/null +++ b/doc/关于多数据源与分布式事务.drawio @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/微信登录.drawio b/doc/微信登录.drawio new file mode 100644 index 0000000..509b195 --- /dev/null +++ b/doc/微信登录.drawio @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/支付流程图.drawio b/doc/支付流程图.drawio new file mode 100644 index 0000000..184cb9f --- /dev/null +++ b/doc/支付流程图.drawio @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/支付系统订单状态图.drawio b/doc/支付系统订单状态图.drawio new file mode 100644 index 0000000..ce41fa8 --- /dev/null +++ b/doc/支付系统订单状态图.drawio @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/权限控制.md b/doc/权限控制.md new file mode 100644 index 0000000..cb0b187 --- /dev/null +++ b/doc/权限控制.md @@ -0,0 +1,68 @@ +### 与权限有关的注解 + +`@Anonymous`注解用于配置公开接口 + +`@PreAuthorize`注解用于配置接口要求用户拥有某些权限才可访问,它拥有如下方法 + +| 方法 | 参数 | 描述 | +| ----------- | ------ | ---------------------------------------------- | +| hasPermi | String | 验证用户是否具备某权限 | +| lacksPermi | String | 验证用户是否不具备某权限,与 hasPermi逻辑相反 | +| hasAnyPermi | String | 验证用户是否具有以下任意一个权限 | +| hasRole | String | 判断用户是否拥有某个角色 | +| lacksRole | String | 验证用户是否不具备某角色,与 isRole逻辑相反 | +| hasAnyRoles | String | 验证用户是否具有以下任意一个角色,多个逗号分隔 | + +```java +@PreAuthorize("@ss.hasPermi('system:user:list')") +@PreAuthorize("@ss.lacksPermi('system:user:list')") +@PreAuthorize("@ss.hasAnyPermi('system:user:add,system:user:edit')") +``` + +`@DataScope`注解用于配置接口数据权限 + +* `deptAlias`用于指定部门表的别名; +* `userAlias`用于指定用户表的别名; +* 实体需要继承BaseEntity类; +* `全部数据权限`、`自定数据权限`、`部门数据权限`、`部门及以下数据权限`、`仅本人数据权限`五种权限模式在后台角色管理界面配置数据权限 + +```java +// 部门数据权限注解 +@DataScope(deptAlias = "d") +// 部门及用户权限注解 +@DataScope(deptAlias = "d", userAlias = "u") +``` + +1. 使用注解 + +```java + +@DataScope(deptAlias = "d", userAlias = "u") +public List<...> select(...) +{ + return mapper.select(...); +} +``` + +2. 配置mybatis的xml + +```xml + +``` + +### 安全工具类 + +utils.com.boyue.common.SecurityUtils + +| 方法 | 参数 | 返回 | 描述 | +| ------------ | ------ | ---------- | ------------------------ | +| getUserId | 无 | Long | 获取当前用户ID | +| getDeptId | 无 | Long | 获取当前部门ID | +| getUsername | 无 | String | 获取当前用户账户 | +| getLoginUser | 无 | LonginUser | 获取当前登录用户代理 | +| hasPermi | String | boolean | 验证用户是否具备某权限 | +| hasRole | String | boolean | 验证用户是否拥有某个角色 | diff --git a/doc/模块依赖关系.drawio b/doc/模块依赖关系.drawio new file mode 100644 index 0000000..ee8771f --- /dev/null +++ b/doc/模块依赖关系.drawio @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/登录+JWT逻辑.drawio b/doc/登录+JWT逻辑.drawio new file mode 100644 index 0000000..9d05d20 --- /dev/null +++ b/doc/登录+JWT逻辑.drawio @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/若依环境使用手册.docx b/doc/若依环境使用手册.docx new file mode 100644 index 0000000..9e4daef Binary files /dev/null and b/doc/若依环境使用手册.docx differ diff --git a/doc/邮箱或短信验证码登录注册重置流程图.drawio b/doc/邮箱或短信验证码登录注册重置流程图.drawio new file mode 100644 index 0000000..7e623e9 --- /dev/null +++ b/doc/邮箱或短信验证码登录注册重置流程图.drawio @@ -0,0 +1,260 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/限流逻辑.drawio b/doc/限流逻辑.drawio new file mode 100644 index 0000000..7ad47d0 --- /dev/null +++ b/doc/限流逻辑.drawio @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..8b48ad0 --- /dev/null +++ b/pom.xml @@ -0,0 +1,368 @@ + + + 4.0.0 + + com.boyue + boyuehasfj-java + 3.8.9-G + + boyue + 管理系统 + + + 3.8.9-G + UTF-8 + UTF-8 + 21 + 3.1.1 + 3.5.0 + 1.2.24 + 1.1 + 1.21 + 3.0.0 + 2.3.3 + 2.1.0 + 2.0.53 + 2.18.0 + 6.6.6 + 2.19.0 + 4.4 + 5.4.1 + 4.5.14 + 2.4.1 + 0.12.6 + 4.5.0 + 3.0.4 + 3.5.16 + + 8.3.0 + 42.7.4 + 4.0.2 + 4.0.5 + 2.8.4 + + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + com.mysql + mysql-connector-j + ${mysql.version} + runtime + + + + + org.postgresql + postgresql + ${postgresql.version} + runtime + + + + + com.alibaba + druid-spring-boot-3-starter + ${druid.version} + + + + javax.transaction + jta + ${jta.version} + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + ${mybatis-spring-boot.version} + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + ${pagehelper.boot.version} + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + + + + + + + com.github.oshi + oshi-core + ${oshi.version} + + + + + commons-io + commons-io + ${commons.io.version} + + + + + org.apache.poi + poi-ooxml + ${poi.version} + + + + + org.apache.velocity + velocity-engine-core + ${velocity.version} + + + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + commons-logging + commons-logging + + + + + + + org.apache.commons + commons-collections4 + ${commons.collections.version} + + + + + com.alibaba.fastjson2 + fastjson2 + ${fastjson.version} + + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson.version} + + + + + io.jsonwebtoken + jjwt-api + ${jwt.version} + + + + io.jsonwebtoken + jjwt-impl + ${jwt.version} + + + + io.jsonwebtoken + jjwt-jackson + ${jwt.version} + + + + + jakarta.xml.bind + jakarta.xml.bind-api + ${jaxb-api.version} + + + com.sun.xml.bind + jaxb-impl + ${jaxb.version} + + + com.sun.xml.bind + jaxb-core + ${jaxb.version} + + + + + eu.bitwalker + UserAgentUtils + ${bitwalker.version} + + + + + pro.fessional + kaptcha + ${kaptcha.version} + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + ${springdoc.version} + + + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + ${knife4j.version} + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + + + + + + + com.boyue + boyue-framework + ${boyue.version} + + + + + com.boyue + boyue-system + ${boyue.version} + + + + + com.boyue + boyue-common + ${boyue.version} + + + + + com.boyue + boyue-auth-starter + ${boyue.version} + + + + + com.boyue + boyue-pay-starter + ${boyue.version} + + + + + com.boyue + boyue-plugins-starter + ${boyue.version} + + + + + com.boyue + boyue-file-starter + ${boyue.version} + + + + + com.boyue + boyue-middleware-starter + ${boyue.version} + + + + + com.boyue + boyue-models-starter + ${boyue.version} + + + + + + boyue-admin + boyue-framework + boyue-system + boyue-common + boyue-auth + boyue-pay + boyue-file + boyue-middleware + boyue-plugins + boyue-models + + pom + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + true + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + + + + + + + + public + aliyun nexus + https://maven.aliyun.com/repository/public + + true + + + + + + + + public + aliyun nexus + https://maven.aliyun.com/repository/public + + true + + + false + + + + + \ No newline at end of file diff --git a/sql/boyuehasfj.sql b/sql/boyuehasfj.sql new file mode 100644 index 0000000..d05606b --- /dev/null +++ b/sql/boyuehasfj.sql @@ -0,0 +1,2362 @@ +/* + Navicat Premium Dump SQL + + Source Server : 222.184.49.22测试 + Source Server Type : MySQL + Source Server Version : 80405 (8.4.5) + Source Host : 222.184.49.22:3307 + Source Schema : boyuehasfj + + Target Server Type : MySQL + Target Server Version : 80405 (8.4.5) + File Encoding : 65001 + + Date: 02/06/2025 21:22:28 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for ACT_APP_APPDEF +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_APP_APPDEF`; +CREATE TABLE `ACT_APP_APPDEF` ( + `ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `REV_` int NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `VERSION_` int NOT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `RESOURCE_NAME_` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `DESCRIPTION_` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + UNIQUE INDEX `ACT_IDX_APP_DEF_UNIQ`(`KEY_` ASC, `VERSION_` ASC, `TENANT_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_APP_DEF_DPLY`(`DEPLOYMENT_ID_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_APP_DEF_DPLY` FOREIGN KEY (`DEPLOYMENT_ID_`) REFERENCES `ACT_APP_DEPLOYMENT` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ACT_APP_APPDEF +-- ---------------------------- + +-- ---------------------------- +-- Table structure for ACT_APP_DEPLOYMENT +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_APP_DEPLOYMENT`; +CREATE TABLE `ACT_APP_DEPLOYMENT` ( + `ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `DEPLOY_TIME_` datetime(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ACT_APP_DEPLOYMENT +-- ---------------------------- + +-- ---------------------------- +-- Table structure for ACT_APP_DEPLOYMENT_RESOURCE +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_APP_DEPLOYMENT_RESOURCE`; +CREATE TABLE `ACT_APP_DEPLOYMENT_RESOURCE` ( + `ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `RESOURCE_BYTES_` longblob NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_APP_RSRC_DPL`(`DEPLOYMENT_ID_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_APP_RSRC_DPL` FOREIGN KEY (`DEPLOYMENT_ID_`) REFERENCES `ACT_APP_DEPLOYMENT` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ACT_APP_DEPLOYMENT_RESOURCE +-- ---------------------------- + +-- ---------------------------- +-- Table structure for ACT_EVT_LOG +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_EVT_LOG`; +CREATE TABLE `ACT_EVT_LOG` ( + `LOG_NR_` bigint NOT NULL AUTO_INCREMENT, + `TYPE_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TIME_STAMP_` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DATA_` longblob NULL, + `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `LOCK_TIME_` timestamp(3) NULL DEFAULT NULL, + `IS_PROCESSED_` tinyint NULL DEFAULT 0, + PRIMARY KEY (`LOG_NR_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ACT_EVT_LOG +-- ---------------------------- + +-- ---------------------------- +-- Table structure for ACT_PROCDEF_INFO +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_PROCDEF_INFO`; +CREATE TABLE `ACT_PROCDEF_INFO` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `INFO_JSON_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + UNIQUE INDEX `ACT_UNIQ_INFO_PROCDEF`(`PROC_DEF_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_INFO_PROCDEF`(`PROC_DEF_ID_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ACT_PROCDEF_INFO +-- ---------------------------- + +-- ---------------------------- +-- Table structure for ACT_RE_DEPLOYMENT +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RE_DEPLOYMENT`; +CREATE TABLE `ACT_RE_DEPLOYMENT` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + `DEPLOY_TIME_` timestamp(3) NULL DEFAULT NULL, + `DERIVED_FROM_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DERIVED_FROM_ROOT_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PARENT_DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ENGINE_VERSION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ACT_RE_DEPLOYMENT +-- ---------------------------- + +-- ---------------------------- +-- Table structure for ACT_RE_MODEL +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RE_MODEL`; +CREATE TABLE `ACT_RE_MODEL` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `LAST_UPDATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `VERSION_` int NULL DEFAULT NULL, + `META_INFO_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EDITOR_SOURCE_VALUE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EDITOR_SOURCE_EXTRA_VALUE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ACT_RE_MODEL +-- ---------------------------- + +-- ---------------------------- +-- Table structure for ACT_RE_PROCDEF +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RE_PROCDEF`; +CREATE TABLE `ACT_RE_PROCDEF` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `VERSION_` int NOT NULL, + `DEPLOYMENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `RESOURCE_NAME_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DGRM_RESOURCE_NAME_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DESCRIPTION_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HAS_START_FORM_KEY_` tinyint NULL DEFAULT NULL, + `HAS_GRAPHICAL_NOTATION_` tinyint NULL DEFAULT NULL, + `SUSPENSION_STATE_` int NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + `ENGINE_VERSION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DERIVED_FROM_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DERIVED_FROM_ROOT_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DERIVED_VERSION_` int NOT NULL DEFAULT 0, + PRIMARY KEY (`ID_`) USING BTREE, + UNIQUE INDEX `ACT_UNIQ_PROCDEF`(`KEY_` ASC, `VERSION_` ASC, `DERIVED_VERSION_` ASC, `TENANT_ID_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ACT_RE_PROCDEF +-- ---------------------------- + +-- ---------------------------- +-- Table structure for ACT_RU_ACTINST +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RU_ACTINST`; +CREATE TABLE `ACT_RU_ACTINST` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT 1, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `ACT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CALL_PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ACT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ACT_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `ASSIGNEE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `START_TIME_` datetime(3) NOT NULL, + `END_TIME_` datetime(3) NULL DEFAULT NULL, + `DURATION_` bigint NULL DEFAULT NULL, + `TRANSACTION_ORDER_` int NULL DEFAULT NULL, + `DELETE_REASON_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_RU_ACTI_START`(`START_TIME_` ASC) USING BTREE, + INDEX `ACT_IDX_RU_ACTI_END`(`END_TIME_` ASC) USING BTREE, + INDEX `ACT_IDX_RU_ACTI_PROC`(`PROC_INST_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_RU_ACTI_PROC_ACT`(`PROC_INST_ID_` ASC, `ACT_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_RU_ACTI_EXEC`(`EXECUTION_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_RU_ACTI_EXEC_ACT`(`EXECUTION_ID_` ASC, `ACT_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_RU_ACTI_TASK`(`TASK_ID_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ACT_RU_ACTINST +-- ---------------------------- + +-- ---------------------------- +-- Table structure for ACT_RU_EXECUTION +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RU_EXECUTION`; +CREATE TABLE `ACT_RU_EXECUTION` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `BUSINESS_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PARENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUPER_EXEC_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ROOT_PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ACT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `IS_ACTIVE_` tinyint NULL DEFAULT NULL, + `IS_CONCURRENT_` tinyint NULL DEFAULT NULL, + `IS_SCOPE_` tinyint NULL DEFAULT NULL, + `IS_EVENT_SCOPE_` tinyint NULL DEFAULT NULL, + `IS_MI_ROOT_` tinyint NULL DEFAULT NULL, + `SUSPENSION_STATE_` int NULL DEFAULT NULL, + `CACHED_ENT_STATE_` int NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `START_ACT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `START_TIME_` datetime(3) NULL DEFAULT NULL, + `START_USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `LOCK_TIME_` timestamp(3) NULL DEFAULT NULL, + `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `IS_COUNT_ENABLED_` tinyint NULL DEFAULT NULL, + `EVT_SUBSCR_COUNT_` int NULL DEFAULT NULL, + `TASK_COUNT_` int NULL DEFAULT NULL, + `JOB_COUNT_` int NULL DEFAULT NULL, + `TIMER_JOB_COUNT_` int NULL DEFAULT NULL, + `SUSP_JOB_COUNT_` int NULL DEFAULT NULL, + `DEADLETTER_JOB_COUNT_` int NULL DEFAULT NULL, + `EXTERNAL_WORKER_JOB_COUNT_` int NULL DEFAULT NULL, + `VAR_COUNT_` int NULL DEFAULT NULL, + `ID_LINK_COUNT_` int NULL DEFAULT NULL, + `CALLBACK_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CALLBACK_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `REFERENCE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `REFERENCE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROPAGATED_STAGE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `BUSINESS_STATUS_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_EXEC_BUSKEY`(`BUSINESS_KEY_` ASC) USING BTREE, + INDEX `ACT_IDC_EXEC_ROOT`(`ROOT_PROC_INST_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_EXEC_REF_ID_`(`REFERENCE_ID_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of ACT_RU_EXECUTION +-- ---------------------------- + +-- ---------------------------- +-- Table structure for form_data +-- ---------------------------- +DROP TABLE IF EXISTS `form_data`; +CREATE TABLE `form_data` ( + `data_id` bigint NOT NULL AUTO_INCREMENT COMMENT '数据ID', + `form_id` bigint NOT NULL COMMENT '关联的表单ID', + `form_version` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '表单版本(与模板表版本一致)', + `data_content` json NOT NULL COMMENT '表单数据内容(JSON格式)', + `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'draft' COMMENT '数据状态(draft, submitted, approved, rejected)', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + PRIMARY KEY (`data_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '表单数据表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of form_data +-- ---------------------------- + +-- ---------------------------- +-- Table structure for form_template +-- ---------------------------- +DROP TABLE IF EXISTS `form_template`; +CREATE TABLE `form_template` ( + `form_id` bigint NOT NULL AUTO_INCREMENT COMMENT '表单ID', + `form_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表单名称', + `form_schema` json NULL COMMENT '表单JSON Schema(vForm配置)', + `form_version` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '1.0.0' COMMENT '表单版本(语义化版本)', + `form_status` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '0' COMMENT '发布状态(0: 草稿, 1: 已发布, 2: 已停用)', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + PRIMARY KEY (`form_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '表单模板表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of form_template +-- ---------------------------- + +-- ---------------------------- +-- Table structure for gen_join_table +-- ---------------------------- +DROP TABLE IF EXISTS `gen_join_table`; +CREATE TABLE `gen_join_table` ( + `table_id` bigint NOT NULL COMMENT '表编号', + `left_table_id` bigint NOT NULL COMMENT '左表名称', + `right_table_id` bigint NOT NULL COMMENT '右表编号', + `left_table_alias` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '左表别名', + `right_table_alias` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '右表别名', + `left_table_fk` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '左表关联键', + `right_table_fk` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '右表关联键', + `join_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '关联类型', + `join_columns` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '关联字段', + `order_num` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '序号', + `new_table_id` bigint NOT NULL COMMENT '新表编号', + PRIMARY KEY (`table_id`, `right_table_id`, `left_table_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of gen_join_table +-- ---------------------------- + +-- ---------------------------- +-- Table structure for gen_table +-- ---------------------------- +DROP TABLE IF EXISTS `gen_table`; +CREATE TABLE `gen_table` ( + `table_id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `table_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表名称', + `table_alias` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表别名', + `table_comment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '表描述', + `have_sub_column` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '0' COMMENT '是否含有关联字段', + `sub_table_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联子表的表名', + `sub_table_fk_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '子表关联的外键名', + `class_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '实体类名称', + `tpl_category` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'crud' COMMENT '使用的模板(crud单表操作 tree树表操作)', + `tpl_web_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'element-plus' COMMENT '使用的模板类型', + `package_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '生成包路径', + `module_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '生成模块名', + `business_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '生成业务名', + `function_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '生成功能名', + `function_author` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '生成功能作者', + `gen_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '0' COMMENT '生成代码方式(0zip压缩包 1自定义路径)', + `gen_path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '/' COMMENT '生成路径(不填默认项目路径)', + `options` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '其它生成选项', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`table_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成业务表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of gen_table +-- ---------------------------- +INSERT INTO `gen_table` VALUES (1, 'html_pages', 'hp', '司法局法律规定、典型案例、表单下载表', '0', NULL, NULL, 'HtmlPages', 'crud', 'element-plus', 'com.boyue.hasfj', 'hasfj', 'hasfjpages', '司法局法律规定、典型案例、单下载', 'boyue', '0', '/', '{\"parentMenuId\":2087}', 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02', NULL); + +-- ---------------------------- +-- Table structure for gen_table_column +-- ---------------------------- +DROP TABLE IF EXISTS `gen_table_column`; +CREATE TABLE `gen_table_column` ( + `column_id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `table_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '归属表编号', + `column_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '列名称', + `column_comment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '列描述', + `column_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '列类型', + `java_type` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'JAVA类型', + `java_field` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'JAVA字段名', + `is_pk` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否主键(1是)', + `is_increment` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否自增(1是)', + `is_required` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否必填(1是)', + `is_insert` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否为插入字段(1是)', + `is_edit` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否编辑字段(1是)', + `is_list` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否列表字段(1是)', + `is_query` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否查询字段(1是)', + `query_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'EQ' COMMENT '查询方式(等于、不等于、大于、小于、范围)', + `html_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)', + `dict_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '字典类型', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `sub_column_table_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联表名称', + `sub_column_fk_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联字段名称', + `sub_column_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '映射字段名称', + `sub_column_java_field` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '映射字段JAVA字段名', + `sub_column_java_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '映射字段JAVA类型', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`column_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成业务表字段' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of gen_table_column +-- ---------------------------- +INSERT INTO `gen_table_column` VALUES (1, '1', 'id', '序号', 'int(11)', 'Long', 'id', '1', '0', '0', '0', NULL, '1', NULL, 'EQ', 'input', '', 1, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (2, '1', 'format_id', '访问id', 'varchar(6)', 'String', 'formatId', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 2, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (3, '1', 'title', '页面标题', 'varchar(200)', 'String', 'title', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 3, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (4, '1', 'content', 'HTML内容', 'text', 'String', 'content', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'editor', '', 4, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (5, '1', 'page_type', '页面类型:法律规定 law、典型案例 case、表单下载from', 'enum(\'law\',\'case\',\'form\')', 'String', 'pageType', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'select', '', 5, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (6, '1', 'page_url', '页面访问URL', 'varchar(255)', 'String', 'pageUrl', '0', '0', '1', '1', '1', '1', '0', 'EQ', 'input', '', 6, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (7, '1', 'create_time', '创建时间', 'datetime', 'LocalDate', 'createTime', '0', '0', '1', '1', NULL, '1', NULL, 'EQ', 'datetime', '', 7, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (8, '1', 'update_time', '更新时间', 'datetime', 'LocalDate', 'updateTime', '0', '0', '1', '1', '1', '1', NULL, 'EQ', 'datetime', '', 8, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (9, '1', 'status', '状态:1-启用,0-禁用', 'tinyint(4)', 'Integer', 'status', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'radio', '', 9, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (10, '1', 'sort_order', '排序序号,数值越小排序越靠前,用于自定义显示顺序', 'int(11)', 'Long', 'sortOrder', '0', '0', '1', '1', '1', '1', '0', 'EQ', 'input', '', 10, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (11, '1', 'view_count', '浏览次数,记录页面被访问的总次数', 'int(11)', 'Long', 'viewCount', '0', '0', '1', '1', '1', '1', '0', 'EQ', 'input', '', 11, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (12, '1', 'author', '作者/负责人,记录页面的创建者或负责维护的人员', 'varchar(50)', 'String', 'author', '0', '0', '0', '1', '1', '1', '0', 'EQ', 'input', '', 12, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (13, '1', 'keywords', 'SEO关键词,用于搜索引擎优化', 'varchar(200)', 'String', 'keywords', '0', '0', '0', '1', '1', '1', '0', 'EQ', 'input', '', 13, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (14, '1', 'description', 'SEO描述,用于搜索引擎结果展示的页面摘要', 'varchar(500)', 'String', 'description', '0', '0', '0', '1', '1', '1', '0', 'EQ', 'textarea', '', 14, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); + +-- ---------------------------- +-- Table structure for html_pages +-- ---------------------------- +DROP TABLE IF EXISTS `html_pages`; +CREATE TABLE `html_pages` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `format_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `page_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `page_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL, + `attachment_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `author` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `status` int NULL DEFAULT 1, + `sort_order` bigint NULL DEFAULT 100, + `view_count` bigint NULL DEFAULT 0, + `keywords` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `description` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `update_time` datetime NULL DEFAULT NULL, + `create_time` datetime NULL DEFAULT NULL, + `multi_attachments` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '多附件URLs,JSON格式存储多个附件URL及名称', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_html_pages_format_id`(`format_id` ASC) USING BTREE, + INDEX `idx_html_pages_page_type`(`page_type` ASC) USING BTREE, + INDEX `idx_html_pages_status`(`status` ASC) USING BTREE, + INDEX `idx_html_pages_sort_order`(`sort_order` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 451 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '页面内容' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of html_pages +-- ---------------------------- +INSERT INTO `html_pages` VALUES (1, '000001', 'law', '/show.html?Id=000001', '如何确定企业形式', '

《公司法》《个人独资企业法》《合伙企业法》

', '', '法律法规编辑部', 1, 1, 223, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-06-02 21:21:10', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (2, '000001', 'case', '/showcase.html?Id=000001', '如何确定企业形式', '

李某与王某成立“普通合伙企业”经营餐饮,后因亏损负债100万元,法院判令李某、王某承担无限连带责任。

', NULL, '案例分析组', 1, 2, 4, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:08:06', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (3, '000001', 'form', '/table.html?Id=000001', '如何确定企业形式', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', '', '表单管理员', 1, 3, 11, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-06-01 11:03:49', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (4, '000002', 'law', '/show.html?Id=000002', '有限责任公司和股份有限公司的区别是什么?', '

《证券法》第七十八条,发行人及法律、行政法规和国务院证券监督管理机构规定的其他信息披露义务人,应当及时依法履行信息披露义务。信息披露义务人披露的信息,应当真实、准确、完整,简明清晰,通俗易懂,不得有虚假记载、误导性陈述或者重大遗漏。

', NULL, '法律法规编辑部', 1, 4, 17, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:11:13', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (5, '000002', 'case', '/showcase.html?Id=000002', '有限责任公司和股份有限公司的区别是什么?', '

某科技创业团队初期仅3名股东,误以为股份公司“更规范易融资”,直接注册为股份公司。因股份公司需设股东大会、董事会、监事会,团队人数不足,决策效率低下;同时需定期披露年报、重大事项,合规成本高。天使投资机构因其结构复杂、股权转让受限(需股东大会批准)放弃投资,最终公司因资金链断裂解散清算。

', NULL, '案例分析组', 1, 5, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:11:33', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (6, '000002', 'form', '/table.html?Id=000002', '有限责任公司和股份有限公司的区别是什么?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 6, 1, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:09:11', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (7, '000003', 'law', '/show.html?Id=000003', '如何确定企业名称?', '

《企业名称登记管理规定》《企业名称登记管理规定实施办法》。

', NULL, '法律法规编辑部', 1, 7, 15, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:11:54', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (8, '000003', 'case', '/showcase.html?Id=000003', '如何确定企业名称?', '

甲公司注册名称为“上海特斯拉新能源科技有限公司”,未经特斯拉公司授权。法院认定其名称攀附知名品牌商誉,构成不正当竞争,判令更名并赔偿20万元。

', NULL, '案例分析组', 1, 8, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:12:12', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (9, '000003', 'form', '/table.html?Id=000003', '如何确定企业名称?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 9, 2, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:09:50', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (10, '000004', 'law', '/show.html?Id=000004', '法定代表人的要求有哪些?', '

《公司法》第十条,公司的法定代表人按照公司章程的规定,由代表公司执行公司事务的董事或者经理担任。担任法定代表人的董事或者经理辞任的,视为同时辞去法定代表人。法定代表人辞任的,公司应当在法定代表人辞任之日起三十日内确定新的法定代表人。第十一条:法定代表人以公司名义从事的民事活动,其法律后果由公司承受。公司章程或者股东会对法定代表人职权的限制,不得对抗善意相对人。法定代表人因执行职务造成他人损害的,由公司承担民事责任。公司承担民事责任后,依照法律或者公司章程的规定,可以向有过错的法定代表人追偿。

', NULL, '法律法规编辑部', 1, 10, 7, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:12:43', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (11, '000004', 'case', '/showcase.html?Id=000004', '法定代表人的要求有哪些?', '

某公司法定代表人李某因个人债务被列为失信被执行人,法院限制其高消费。公司向银行申请贷款时,因李某信用瑕疵遭拒,资金链断裂导致停产。市场监管部门责令更换法定代表人,但因股东争议拖延,最终公司破产清算。

', NULL, '案例分析组', 1, 11, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:13:17', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (12, '000004', 'form', '/table.html?Id=000004', '法定代表人的要求有哪些?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 12, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:13:35', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (13, '000005', 'law', '/show.html?Id=000005', '董事、监事、高级管理人员的资格限制有哪些?', '

《公司法》第一百七十八条,有下列情形之一的,不得担任公司的董事、监事、高级管理人员:(一)无民事行为能力或者限制民事行为能力;(二)因贪污、贿赂、侵占财产、挪用财产或者破坏社会主义市场经济秩序,被判处刑罚,或者因犯罪被剥夺政治权利,执行期满未逾五年,被宣告缓刑的,自缓刑考验期满之日起未逾二年;(三)担任破产清算的公司、企业的董事或者厂长、经理,对该公司、企业的破产负有个人责任的,自该公司、企业破产清算完结之日起未逾三年;(四)担任因违法被吊销营业执照、责令关闭的公司、企业的法定代表人,并负有个人责任的,自该公司、企业被吊销营业执照、责令关闭之日起未逾三年;(五)个人因所负数额较大债务到期未清偿被人民法院列为失信被执行人。

', NULL, '法律法规编辑部', 1, 13, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:14:05', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (14, '000005', 'case', '/showcase.html?Id=000005', '董事、监事、高级管理人员的资格限制有哪些?', '

某公司股东李某(公务员)通过亲属代持股权,后因公司债务纠纷被债权人揭发。法院认定代持协议无效,李某需退还全部股权收益,公司被处罚款10万元。

', NULL, '案例分析组', 1, 14, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:14:42', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (15, '000005', 'form', '/table.html?Id=000005', '董事、监事、高级管理人员的资格限制有哪些?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 15, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:14:52', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (16, '000006', 'law', '/show.html?Id=000006', '隐名股东有哪些常见法律风险?', '

最高人民法院关于适用《中华人民共和国公司法》若干问题的规定(三)第二十四条,有限责任公司的实际出资人与名义出资人订立合同,约定由实际出资人出资并享有投资权益,以名义出资人为名义股东,实际出资人与名义股东对该合同效力发生争议的,如无法律规定的无效情形,人民法院应当认定该合同有效。前款规定的实际出资人与名义股东因投资权益的归属发生争议,实际出资人以其实际履行了出资义务为由向名义股东主张权利的,人民法院应予支持。名义股东以公司股东名册记载、公司登记机关登记为由否认实际出资人权利的,人民法院不予支持。实际出资人未经公司其他股东半数以上同意,请求公司变更股东、签发出资证明书、记载于股东名册、记载于公司章程并办理公司登记机关登记的,人民法院不予支持。

', NULL, '法律法规编辑部', 1, 16, 1, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:15:42', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (17, '000006', 'case', '/showcase.html?Id=000006', '隐名股东有哪些常见法律风险?', '

隐名股东李某委托张某代持某公司10%股权,张某未经同意将股权转让给王某,王某不知情且支付合理价款。王某善意取得股权,李某仅能要求张某赔偿损失。

', NULL, '案例分析组', 1, 17, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:16:04', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (18, '000006', 'form', '/table.html?Id=000006', '隐名股东有哪些常见法律风险?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 18, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:16:19', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (19, '000007', 'law', '/show.html?Id=000007', '如何保持创始人在公司的控制权?', '

《公司法》第六十五条,股东会会议由股东按照出资比例行使表决权;但是,公司章程另有规定的除外。

', NULL, '法律法规编辑部', 1, 19, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:16:52', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (20, '000007', 'case', '/showcase.html?Id=000007', '如何保持创始人在公司的控制权?', '

某公司创始人通过“AB股”架构(1股10票投票权),即使持股比例仅15%,仍掌控董事会80%席位。公司上市后,其投票权超80%,确保战略决策权。

', NULL, '案例分析组', 1, 20, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:17:15', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (21, '000007', 'form', '/table.html?Id=000007', '如何保持创始人在公司的控制权?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 21, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:17:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (22, '000008', 'law', '/show.html?Id=000008', '如何防止出现公司僵局?', '

《公司法》第二百三十一条,公司经营管理发生严重困难,继续存续会使股东利益受到重大损失,通过其他途径不能解决的,持有公司百分之十以上表决权的股东,可以请求人民法院解散公司。

最高人民法院关于适用《中华人民共和国公司法》若干问题的规定(二)第一条,单独或者合计持有公司全部股东表决权百分之十以上的股东,以下列事由之一提起解散公司诉讼,并符合公司法第一百八十二条规定的,人民法院应予受理:(一)公司持续两年以上无法召开股东会或者股东大会,公司经营管理发生严重困难的;(二)股东表决时无法达到法定或者公司章程规定的比例,持续两年以上不能做出有效的股东会或者股东大会决议,公司经营管理发生严重困难的;(三)公司董事长期冲突,且无法通过股东会或者股东大会解决,公司经营管理发生严重困难的;


', NULL, '法律法规编辑部', 1, 22, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:18:00', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (23, '000008', 'case', '/showcase.html?Id=000008', '如何防止出现公司僵局?', '

某零售企业两位股东各持50%股权,因经营理念严重冲突,股东会无法通过重大决策(如拓展新店、引入投资),公司现金流枯竭,员工离职,被法院裁定解散。

', NULL, '案例分析组', 1, 23, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:18:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (24, '000008', 'form', '/table.html?Id=000008', '如何防止出现公司僵局?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 24, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:18:40', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (25, '000009', 'law', '/show.html?Id=000009', '如何合理确定注册资本?', '

《公司法》第四条,有限责任公司的股东以其认缴的出资额为限对公司承担责任;股份有限公司的股东以其认购的股份为限对公司承担责任。

', NULL, '法律法规编辑部', 1, 25, 1, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:19:12', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (26, '000009', 'case', '/showcase.html?Id=000009', '如何合理确定注册资本?', '

某公司注册资本8000万元(认缴期30年),实际运营资金仅200万元。后因合同纠纷负债500万元,法院认定股东恶意设置超长认缴期,判令股东立即补缴。


', NULL, '案例分析组', 1, 26, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:19:32', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (27, '000009', 'form', '/table.html?Id=000009', '如何合理确定注册资本?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 27, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:19:44', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (28, '000010', 'law', '/show.html?Id=000010', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 28, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (29, '000010', 'case', '/showcase.html?Id=000010', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 29, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (30, '000010', 'form', '/table.html?Id=000010', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 30, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (31, '000011', 'law', '/show.html?Id=000011', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 31, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (32, '000011', 'case', '/showcase.html?Id=000011', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 32, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (33, '000011', 'form', '/table.html?Id=000011', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 33, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (34, '000012', 'law', '/show.html?Id=000012', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 34, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (35, '000012', 'case', '/showcase.html?Id=000012', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 35, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (36, '000012', 'form', '/table.html?Id=000012', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 36, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (37, '000013', 'law', '/show.html?Id=000013', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 37, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (38, '000013', 'case', '/showcase.html?Id=000013', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 38, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (39, '000013', 'form', '/table.html?Id=000013', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 39, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (40, '000014', 'law', '/show.html?Id=000014', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 40, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (41, '000014', 'case', '/showcase.html?Id=000014', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 41, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (42, '000014', 'form', '/table.html?Id=000014', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 42, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (43, '000015', 'law', '/show.html?Id=000015', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 43, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (44, '000015', 'case', '/showcase.html?Id=000015', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 44, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (45, '000015', 'form', '/table.html?Id=000015', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 45, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (46, '000016', 'law', '/show.html?Id=000016', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 46, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (47, '000016', 'case', '/showcase.html?Id=000016', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 47, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (48, '000016', 'form', '/table.html?Id=000016', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 48, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (49, '000017', 'law', '/show.html?Id=000017', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 49, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (50, '000017', 'case', '/showcase.html?Id=000017', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 50, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (51, '000017', 'form', '/table.html?Id=000017', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 51, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (52, '000018', 'law', '/show.html?Id=000018', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 52, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (53, '000018', 'case', '/showcase.html?Id=000018', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 53, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (54, '000018', 'form', '/table.html?Id=000018', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 54, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (55, '000019', 'law', '/show.html?Id=000019', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 55, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (56, '000019', 'case', '/showcase.html?Id=000019', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 56, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (57, '000019', 'form', '/table.html?Id=000019', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 57, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (58, '000020', 'law', '/show.html?Id=000020', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 58, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (59, '000020', 'case', '/showcase.html?Id=000020', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 59, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (60, '000020', 'form', '/table.html?Id=000020', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 60, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (61, '000021', 'law', '/show.html?Id=000021', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 61, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (62, '000021', 'case', '/showcase.html?Id=000021', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 62, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (63, '000021', 'form', '/table.html?Id=000021', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 63, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (64, '000022', 'law', '/show.html?Id=000022', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 64, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (65, '000022', 'case', '/showcase.html?Id=000022', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 65, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (66, '000022', 'form', '/table.html?Id=000022', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 66, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (67, '000023', 'law', '/show.html?Id=000023', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 67, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (68, '000023', 'case', '/showcase.html?Id=000023', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 68, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (69, '000023', 'form', '/table.html?Id=000023', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 69, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (70, '000024', 'law', '/show.html?Id=000024', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 70, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (71, '000024', 'case', '/showcase.html?Id=000024', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 71, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (72, '000024', 'form', '/table.html?Id=000024', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 72, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (73, '000025', 'law', '/show.html?Id=000025', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 73, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (74, '000025', 'case', '/showcase.html?Id=000025', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 74, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (75, '000025', 'form', '/table.html?Id=000025', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 75, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (76, '000026', 'law', '/show.html?Id=000026', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 76, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (77, '000026', 'case', '/showcase.html?Id=000026', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 77, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (78, '000026', 'form', '/table.html?Id=000026', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 78, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (79, '000027', 'law', '/show.html?Id=000027', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 79, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (80, '000027', 'case', '/showcase.html?Id=000027', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 80, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (81, '000027', 'form', '/table.html?Id=000027', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 81, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (82, '000028', 'law', '/show.html?Id=000028', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 82, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (83, '000028', 'case', '/showcase.html?Id=000028', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 83, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (84, '000028', 'form', '/table.html?Id=000028', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 84, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (85, '000029', 'law', '/show.html?Id=000029', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 85, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (86, '000029', 'case', '/showcase.html?Id=000029', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 86, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (87, '000029', 'form', '/table.html?Id=000029', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 87, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (88, '000030', 'law', '/show.html?Id=000030', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 88, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (89, '000030', 'case', '/showcase.html?Id=000030', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 89, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (90, '000030', 'form', '/table.html?Id=000030', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 90, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (91, '000031', 'law', '/show.html?Id=000031', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 91, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (92, '000031', 'case', '/showcase.html?Id=000031', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 92, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (93, '000031', 'form', '/table.html?Id=000031', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 93, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (94, '000032', 'law', '/show.html?Id=000032', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 94, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (95, '000032', 'case', '/showcase.html?Id=000032', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 95, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (96, '000032', 'form', '/table.html?Id=000032', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 96, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (97, '000033', 'law', '/show.html?Id=000033', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 97, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (98, '000033', 'case', '/showcase.html?Id=000033', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 98, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (99, '000033', 'form', '/table.html?Id=000033', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 99, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (100, '000034', 'law', '/show.html?Id=000034', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 100, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (101, '000034', 'case', '/showcase.html?Id=000034', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 101, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (102, '000034', 'form', '/table.html?Id=000034', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 102, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (103, '000035', 'law', '/show.html?Id=000035', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 103, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (104, '000035', 'case', '/showcase.html?Id=000035', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 104, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (105, '000035', 'form', '/table.html?Id=000035', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 105, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (106, '000036', 'law', '/show.html?Id=000036', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 106, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (107, '000036', 'case', '/showcase.html?Id=000036', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 107, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (108, '000036', 'form', '/table.html?Id=000036', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 108, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (109, '000037', 'law', '/show.html?Id=000037', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 109, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (110, '000037', 'case', '/showcase.html?Id=000037', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 110, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (111, '000037', 'form', '/table.html?Id=000037', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 111, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (112, '000038', 'law', '/show.html?Id=000038', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 112, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (113, '000038', 'case', '/showcase.html?Id=000038', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 113, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (114, '000038', 'form', '/table.html?Id=000038', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 114, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (115, '000039', 'law', '/show.html?Id=000039', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 115, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (116, '000039', 'case', '/showcase.html?Id=000039', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 116, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (117, '000039', 'form', '/table.html?Id=000039', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 117, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (118, '000040', 'law', '/show.html?Id=000040', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 118, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (119, '000040', 'case', '/showcase.html?Id=000040', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 119, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (120, '000040', 'form', '/table.html?Id=000040', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 120, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (121, '000041', 'law', '/show.html?Id=000041', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 121, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (122, '000041', 'case', '/showcase.html?Id=000041', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 122, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (123, '000041', 'form', '/table.html?Id=000041', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 123, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (124, '000042', 'law', '/show.html?Id=000042', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 124, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (125, '000042', 'case', '/showcase.html?Id=000042', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 125, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (126, '000042', 'form', '/table.html?Id=000042', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 126, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (127, '000043', 'law', '/show.html?Id=000043', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 127, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (128, '000043', 'case', '/showcase.html?Id=000043', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 128, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (129, '000043', 'form', '/table.html?Id=000043', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 129, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (130, '000044', 'law', '/show.html?Id=000044', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 130, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (131, '000044', 'case', '/showcase.html?Id=000044', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 131, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (132, '000044', 'form', '/table.html?Id=000044', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 132, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (133, '000045', 'law', '/show.html?Id=000045', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 133, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (134, '000045', 'case', '/showcase.html?Id=000045', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 134, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (135, '000045', 'form', '/table.html?Id=000045', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 135, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (136, '000046', 'law', '/show.html?Id=000046', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 136, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (137, '000046', 'case', '/showcase.html?Id=000046', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 137, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (138, '000046', 'form', '/table.html?Id=000046', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 138, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (139, '000047', 'law', '/show.html?Id=000047', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 139, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (140, '000047', 'case', '/showcase.html?Id=000047', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 140, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (141, '000047', 'form', '/table.html?Id=000047', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 141, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (142, '000048', 'law', '/show.html?Id=000048', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 142, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (143, '000048', 'case', '/showcase.html?Id=000048', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 143, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (144, '000048', 'form', '/table.html?Id=000048', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 144, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (145, '000049', 'law', '/show.html?Id=000049', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 145, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (146, '000049', 'case', '/showcase.html?Id=000049', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 146, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (147, '000049', 'form', '/table.html?Id=000049', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 147, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (148, '000050', 'law', '/show.html?Id=000050', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 148, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (149, '000050', 'case', '/showcase.html?Id=000050', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 149, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (150, '000050', 'form', '/table.html?Id=000050', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 150, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (151, '000051', 'law', '/show.html?Id=000051', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 151, 1, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:11:40', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (152, '000051', 'case', '/showcase.html?Id=000051', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 152, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (153, '000051', 'form', '/table.html?Id=000051', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 153, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (154, '000052', 'law', '/show.html?Id=000052', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 154, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (155, '000052', 'case', '/showcase.html?Id=000052', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 155, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (156, '000052', 'form', '/table.html?Id=000052', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 156, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (157, '000053', 'law', '/show.html?Id=000053', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 157, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (158, '000053', 'case', '/showcase.html?Id=000053', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 158, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (159, '000053', 'form', '/table.html?Id=000053', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 159, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (160, '000054', 'law', '/show.html?Id=000054', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 160, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (161, '000054', 'case', '/showcase.html?Id=000054', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 161, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (162, '000054', 'form', '/table.html?Id=000054', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 162, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (163, '000055', 'law', '/show.html?Id=000055', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 163, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (164, '000055', 'case', '/showcase.html?Id=000055', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 164, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (165, '000055', 'form', '/table.html?Id=000055', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 165, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (166, '000056', 'law', '/show.html?Id=000056', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 166, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (167, '000056', 'case', '/showcase.html?Id=000056', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 167, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (168, '000056', 'form', '/table.html?Id=000056', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 168, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (169, '000057', 'law', '/show.html?Id=000057', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 169, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (170, '000057', 'case', '/showcase.html?Id=000057', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 170, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (171, '000057', 'form', '/table.html?Id=000057', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 171, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (172, '000058', 'law', '/show.html?Id=000058', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 172, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (173, '000058', 'case', '/showcase.html?Id=000058', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 173, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (174, '000058', 'form', '/table.html?Id=000058', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 174, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (175, '000059', 'law', '/show.html?Id=000059', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 175, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (176, '000059', 'case', '/showcase.html?Id=000059', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 176, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (177, '000059', 'form', '/table.html?Id=000059', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 177, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (178, '000060', 'law', '/show.html?Id=000060', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 178, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (179, '000060', 'case', '/showcase.html?Id=000060', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 179, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (180, '000060', 'form', '/table.html?Id=000060', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 180, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (181, '000061', 'law', '/show.html?Id=000061', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 181, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (182, '000061', 'case', '/showcase.html?Id=000061', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 182, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (183, '000061', 'form', '/table.html?Id=000061', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 183, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (184, '000062', 'law', '/show.html?Id=000062', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 184, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (185, '000062', 'case', '/showcase.html?Id=000062', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 185, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (186, '000062', 'form', '/table.html?Id=000062', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 186, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (187, '000063', 'law', '/show.html?Id=000063', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 187, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (188, '000063', 'case', '/showcase.html?Id=000063', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 188, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (189, '000063', 'form', '/table.html?Id=000063', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 189, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (190, '000064', 'law', '/show.html?Id=000064', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 190, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (191, '000064', 'case', '/showcase.html?Id=000064', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 191, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (192, '000064', 'form', '/table.html?Id=000064', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 192, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (193, '000065', 'law', '/show.html?Id=000065', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 193, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (194, '000065', 'case', '/showcase.html?Id=000065', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 194, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (195, '000065', 'form', '/table.html?Id=000065', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 195, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (196, '000066', 'law', '/show.html?Id=000066', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 196, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (197, '000066', 'case', '/showcase.html?Id=000066', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 197, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (198, '000066', 'form', '/table.html?Id=000066', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 198, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (199, '000067', 'law', '/show.html?Id=000067', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 199, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (200, '000067', 'case', '/showcase.html?Id=000067', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 200, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (201, '000067', 'form', '/table.html?Id=000067', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 201, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (202, '000068', 'law', '/show.html?Id=000068', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 202, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (203, '000068', 'case', '/showcase.html?Id=000068', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 203, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (204, '000068', 'form', '/table.html?Id=000068', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 204, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (205, '000069', 'law', '/show.html?Id=000069', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 205, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (206, '000069', 'case', '/showcase.html?Id=000069', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 206, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (207, '000069', 'form', '/table.html?Id=000069', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 207, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (208, '000070', 'law', '/show.html?Id=000070', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 208, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (209, '000070', 'case', '/showcase.html?Id=000070', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 209, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (210, '000070', 'form', '/table.html?Id=000070', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 210, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (211, '000071', 'law', '/show.html?Id=000071', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 211, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (212, '000071', 'case', '/showcase.html?Id=000071', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 212, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (213, '000071', 'form', '/table.html?Id=000071', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 213, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (214, '000072', 'law', '/show.html?Id=000072', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 214, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (215, '000072', 'case', '/showcase.html?Id=000072', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 215, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (216, '000072', 'form', '/table.html?Id=000072', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 216, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (217, '000073', 'law', '/show.html?Id=000073', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 217, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (218, '000073', 'case', '/showcase.html?Id=000073', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 218, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (219, '000073', 'form', '/table.html?Id=000073', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 219, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (220, '000074', 'law', '/show.html?Id=000074', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 220, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (221, '000074', 'case', '/showcase.html?Id=000074', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 221, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (222, '000074', 'form', '/table.html?Id=000074', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 222, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (223, '000075', 'law', '/show.html?Id=000075', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 223, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (224, '000075', 'case', '/showcase.html?Id=000075', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 224, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (225, '000075', 'form', '/table.html?Id=000075', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 225, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (226, '000076', 'law', '/show.html?Id=000076', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 226, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (227, '000076', 'case', '/showcase.html?Id=000076', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 227, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (228, '000076', 'form', '/table.html?Id=000076', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 228, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (229, '000077', 'law', '/show.html?Id=000077', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 229, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (230, '000077', 'case', '/showcase.html?Id=000077', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 230, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (231, '000077', 'form', '/table.html?Id=000077', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 231, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (232, '000078', 'law', '/show.html?Id=000078', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 232, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (233, '000078', 'case', '/showcase.html?Id=000078', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 233, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (234, '000078', 'form', '/table.html?Id=000078', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 234, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (235, '000079', 'law', '/show.html?Id=000079', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 235, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (236, '000079', 'case', '/showcase.html?Id=000079', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 236, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (237, '000079', 'form', '/table.html?Id=000079', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 237, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (238, '000080', 'law', '/show.html?Id=000080', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 238, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (239, '000080', 'case', '/showcase.html?Id=000080', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 239, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (240, '000080', 'form', '/table.html?Id=000080', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 240, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (241, '000081', 'law', '/show.html?Id=000081', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 241, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (242, '000081', 'case', '/showcase.html?Id=000081', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 242, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (243, '000081', 'form', '/table.html?Id=000081', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 243, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (244, '000082', 'law', '/show.html?Id=000082', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 244, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (245, '000082', 'case', '/showcase.html?Id=000082', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 245, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (246, '000082', 'form', '/table.html?Id=000082', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 246, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (247, '000083', 'law', '/show.html?Id=000083', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 247, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (248, '000083', 'case', '/showcase.html?Id=000083', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 248, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (249, '000083', 'form', '/table.html?Id=000083', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 249, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (250, '000084', 'law', '/show.html?Id=000084', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 250, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (251, '000084', 'case', '/showcase.html?Id=000084', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 251, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (252, '000084', 'form', '/table.html?Id=000084', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 252, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (253, '000085', 'law', '/show.html?Id=000085', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 253, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (254, '000085', 'case', '/showcase.html?Id=000085', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 254, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (255, '000085', 'form', '/table.html?Id=000085', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 255, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (256, '000086', 'law', '/show.html?Id=000086', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 256, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (257, '000086', 'case', '/showcase.html?Id=000086', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 257, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (258, '000086', 'form', '/table.html?Id=000086', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 258, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (259, '000087', 'law', '/show.html?Id=000087', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 259, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (260, '000087', 'case', '/showcase.html?Id=000087', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 260, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (261, '000087', 'form', '/table.html?Id=000087', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 261, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (262, '000088', 'law', '/show.html?Id=000088', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 262, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (263, '000088', 'case', '/showcase.html?Id=000088', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 263, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (264, '000088', 'form', '/table.html?Id=000088', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 264, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (265, '000089', 'law', '/show.html?Id=000089', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 265, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (266, '000089', 'case', '/showcase.html?Id=000089', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 266, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (267, '000089', 'form', '/table.html?Id=000089', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 267, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (268, '000090', 'law', '/show.html?Id=000090', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 268, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (269, '000090', 'case', '/showcase.html?Id=000090', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 269, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (270, '000090', 'form', '/table.html?Id=000090', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 270, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (271, '000091', 'law', '/show.html?Id=000091', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 271, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (272, '000091', 'case', '/showcase.html?Id=000091', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 272, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (273, '000091', 'form', '/table.html?Id=000091', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 273, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (274, '000092', 'law', '/show.html?Id=000092', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 274, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (275, '000092', 'case', '/showcase.html?Id=000092', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 275, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (276, '000092', 'form', '/table.html?Id=000092', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 276, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (277, '000093', 'law', '/show.html?Id=000093', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 277, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (278, '000093', 'case', '/showcase.html?Id=000093', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 278, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (279, '000093', 'form', '/table.html?Id=000093', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 279, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (280, '000094', 'law', '/show.html?Id=000094', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 280, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (281, '000094', 'case', '/showcase.html?Id=000094', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 281, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (282, '000094', 'form', '/table.html?Id=000094', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 282, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (283, '000095', 'law', '/show.html?Id=000095', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 283, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (284, '000095', 'case', '/showcase.html?Id=000095', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 284, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (285, '000095', 'form', '/table.html?Id=000095', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 285, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (286, '000096', 'law', '/show.html?Id=000096', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 286, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (287, '000096', 'case', '/showcase.html?Id=000096', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 287, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (288, '000096', 'form', '/table.html?Id=000096', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 288, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (289, '000097', 'law', '/show.html?Id=000097', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 289, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (290, '000097', 'case', '/showcase.html?Id=000097', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 290, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (291, '000097', 'form', '/table.html?Id=000097', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 291, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (292, '000098', 'law', '/show.html?Id=000098', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 292, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (293, '000098', 'case', '/showcase.html?Id=000098', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 293, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (294, '000098', 'form', '/table.html?Id=000098', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 294, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (295, '000099', 'law', '/show.html?Id=000099', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 295, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (296, '000099', 'case', '/showcase.html?Id=000099', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 296, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (297, '000099', 'form', '/table.html?Id=000099', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 297, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (298, '000100', 'law', '/show.html?Id=000100', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 298, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (299, '000100', 'case', '/showcase.html?Id=000100', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 299, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (300, '000100', 'form', '/table.html?Id=000100', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 300, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (301, '000101', 'law', '/show.html?Id=000101', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 301, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (302, '000101', 'case', '/showcase.html?Id=000101', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 302, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (303, '000101', 'form', '/table.html?Id=000101', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 303, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (304, '000102', 'law', '/show.html?Id=000102', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 304, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (305, '000102', 'case', '/showcase.html?Id=000102', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 305, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (306, '000102', 'form', '/table.html?Id=000102', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 306, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (307, '000103', 'law', '/show.html?Id=000103', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 307, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (308, '000103', 'case', '/showcase.html?Id=000103', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 308, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (309, '000103', 'form', '/table.html?Id=000103', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 309, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (310, '000104', 'law', '/show.html?Id=000104', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 310, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (311, '000104', 'case', '/showcase.html?Id=000104', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 311, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (312, '000104', 'form', '/table.html?Id=000104', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 312, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (313, '000105', 'law', '/show.html?Id=000105', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 313, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (314, '000105', 'case', '/showcase.html?Id=000105', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 314, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (315, '000105', 'form', '/table.html?Id=000105', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 315, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (316, '000106', 'law', '/show.html?Id=000106', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 316, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (317, '000106', 'case', '/showcase.html?Id=000106', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 317, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (318, '000106', 'form', '/table.html?Id=000106', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 318, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (319, '000107', 'law', '/show.html?Id=000107', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 319, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (320, '000107', 'case', '/showcase.html?Id=000107', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 320, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (321, '000107', 'form', '/table.html?Id=000107', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 321, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (322, '000108', 'law', '/show.html?Id=000108', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 322, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (323, '000108', 'case', '/showcase.html?Id=000108', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 323, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (324, '000108', 'form', '/table.html?Id=000108', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 324, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (325, '000109', 'law', '/show.html?Id=000109', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 325, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (326, '000109', 'case', '/showcase.html?Id=000109', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 326, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (327, '000109', 'form', '/table.html?Id=000109', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 327, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (328, '000110', 'law', '/show.html?Id=000110', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 328, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (329, '000110', 'case', '/showcase.html?Id=000110', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 329, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (330, '000110', 'form', '/table.html?Id=000110', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 330, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (331, '000111', 'law', '/show.html?Id=000111', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 331, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (332, '000111', 'case', '/showcase.html?Id=000111', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 332, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (333, '000111', 'form', '/table.html?Id=000111', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 333, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (334, '000112', 'law', '/show.html?Id=000112', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 334, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (335, '000112', 'case', '/showcase.html?Id=000112', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 335, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (336, '000112', 'form', '/table.html?Id=000112', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 336, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (337, '000113', 'law', '/show.html?Id=000113', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 337, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (338, '000113', 'case', '/showcase.html?Id=000113', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 338, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (339, '000113', 'form', '/table.html?Id=000113', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 339, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (340, '000114', 'law', '/show.html?Id=000114', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 340, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (341, '000114', 'case', '/showcase.html?Id=000114', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 341, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (342, '000114', 'form', '/table.html?Id=000114', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 342, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (343, '000115', 'law', '/show.html?Id=000115', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 343, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (344, '000115', 'case', '/showcase.html?Id=000115', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 344, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (345, '000115', 'form', '/table.html?Id=000115', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 345, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (346, '000116', 'law', '/show.html?Id=000116', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 346, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (347, '000116', 'case', '/showcase.html?Id=000116', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 347, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (348, '000116', 'form', '/table.html?Id=000116', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 348, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (349, '000117', 'law', '/show.html?Id=000117', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 349, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (350, '000117', 'case', '/showcase.html?Id=000117', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 350, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (351, '000117', 'form', '/table.html?Id=000117', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 351, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (352, '000118', 'law', '/show.html?Id=000118', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 352, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (353, '000118', 'case', '/showcase.html?Id=000118', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 353, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (354, '000118', 'form', '/table.html?Id=000118', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 354, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (355, '000119', 'law', '/show.html?Id=000119', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 355, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (356, '000119', 'case', '/showcase.html?Id=000119', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 356, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (357, '000119', 'form', '/table.html?Id=000119', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 357, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (358, '000120', 'law', '/show.html?Id=000120', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 358, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (359, '000120', 'case', '/showcase.html?Id=000120', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 359, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (360, '000120', 'form', '/table.html?Id=000120', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 360, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (361, '000121', 'law', '/show.html?Id=000121', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 361, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (362, '000121', 'case', '/showcase.html?Id=000121', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 362, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (363, '000121', 'form', '/table.html?Id=000121', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 363, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (364, '000122', 'law', '/show.html?Id=000122', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 364, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (365, '000122', 'case', '/showcase.html?Id=000122', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 365, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (366, '000122', 'form', '/table.html?Id=000122', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 366, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (367, '000123', 'law', '/show.html?Id=000123', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 367, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (368, '000123', 'case', '/showcase.html?Id=000123', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 368, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (369, '000123', 'form', '/table.html?Id=000123', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 369, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (370, '000124', 'law', '/show.html?Id=000124', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 370, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (371, '000124', 'case', '/showcase.html?Id=000124', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 371, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (372, '000124', 'form', '/table.html?Id=000124', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 372, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (373, '000125', 'law', '/show.html?Id=000125', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 373, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (374, '000125', 'case', '/showcase.html?Id=000125', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 374, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (375, '000125', 'form', '/table.html?Id=000125', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 375, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (376, '000126', 'law', '/show.html?Id=000126', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 376, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (377, '000126', 'case', '/showcase.html?Id=000126', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 377, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (378, '000126', 'form', '/table.html?Id=000126', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 378, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (379, '000127', 'law', '/show.html?Id=000127', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 379, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (380, '000127', 'case', '/showcase.html?Id=000127', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 380, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (381, '000127', 'form', '/table.html?Id=000127', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 381, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (382, '000128', 'law', '/show.html?Id=000128', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 382, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (383, '000128', 'case', '/showcase.html?Id=000128', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 383, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (384, '000128', 'form', '/table.html?Id=000128', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 384, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (385, '000129', 'law', '/show.html?Id=000129', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 385, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (386, '000129', 'case', '/showcase.html?Id=000129', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 386, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (387, '000129', 'form', '/table.html?Id=000129', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 387, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (388, '000130', 'law', '/show.html?Id=000130', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 388, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (389, '000130', 'case', '/showcase.html?Id=000130', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 389, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (390, '000130', 'form', '/table.html?Id=000130', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 390, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (391, '000131', 'law', '/show.html?Id=000131', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 391, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (392, '000131', 'case', '/showcase.html?Id=000131', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 392, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (393, '000131', 'form', '/table.html?Id=000131', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 393, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (394, '000132', 'law', '/show.html?Id=000132', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 394, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (395, '000132', 'case', '/showcase.html?Id=000132', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 395, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (396, '000132', 'form', '/table.html?Id=000132', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 396, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (397, '000133', 'law', '/show.html?Id=000133', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 397, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (398, '000133', 'case', '/showcase.html?Id=000133', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 398, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (399, '000133', 'form', '/table.html?Id=000133', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 399, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (400, '000134', 'law', '/show.html?Id=000134', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 400, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (401, '000134', 'case', '/showcase.html?Id=000134', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 401, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (402, '000134', 'form', '/table.html?Id=000134', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 402, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (403, '000135', 'law', '/show.html?Id=000135', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 403, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (404, '000135', 'case', '/showcase.html?Id=000135', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 404, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (405, '000135', 'form', '/table.html?Id=000135', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 405, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (406, '000136', 'law', '/show.html?Id=000136', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 406, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (407, '000136', 'case', '/showcase.html?Id=000136', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 407, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (408, '000136', 'form', '/table.html?Id=000136', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 408, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (409, '000137', 'law', '/show.html?Id=000137', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 409, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (410, '000137', 'case', '/showcase.html?Id=000137', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 410, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (411, '000137', 'form', '/table.html?Id=000137', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 411, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (412, '000138', 'law', '/show.html?Id=000138', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 412, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (413, '000138', 'case', '/showcase.html?Id=000138', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 413, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (414, '000138', 'form', '/table.html?Id=000138', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 414, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (415, '000139', 'law', '/show.html?Id=000139', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 415, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (416, '000139', 'case', '/showcase.html?Id=000139', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 416, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (417, '000139', 'form', '/table.html?Id=000139', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 417, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (418, '000140', 'law', '/show.html?Id=000140', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 418, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (419, '000140', 'case', '/showcase.html?Id=000140', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 419, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (420, '000140', 'form', '/table.html?Id=000140', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 420, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (421, '000141', 'law', '/show.html?Id=000141', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 421, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (422, '000141', 'case', '/showcase.html?Id=000141', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 422, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (423, '000141', 'form', '/table.html?Id=000141', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 423, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (424, '000142', 'law', '/show.html?Id=000142', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 424, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (425, '000142', 'case', '/showcase.html?Id=000142', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 425, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (426, '000142', 'form', '/table.html?Id=000142', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 426, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (427, '000143', 'law', '/show.html?Id=000143', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 427, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (428, '000143', 'case', '/showcase.html?Id=000143', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 428, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (429, '000143', 'form', '/table.html?Id=000143', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 429, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (430, '000144', 'law', '/show.html?Id=000144', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 430, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (431, '000144', 'case', '/showcase.html?Id=000144', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 431, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (432, '000144', 'form', '/table.html?Id=000144', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 432, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (433, '000145', 'law', '/show.html?Id=000145', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 433, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (434, '000145', 'case', '/showcase.html?Id=000145', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 434, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (435, '000145', 'form', '/table.html?Id=000145', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 435, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (436, '000146', 'law', '/show.html?Id=000146', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 436, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (437, '000146', 'case', '/showcase.html?Id=000146', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 437, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (438, '000146', 'form', '/table.html?Id=000146', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 438, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (439, '000147', 'law', '/show.html?Id=000147', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 439, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (440, '000147', 'case', '/showcase.html?Id=000147', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 440, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (441, '000147', 'form', '/table.html?Id=000147', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 441, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (442, '000148', 'law', '/show.html?Id=000148', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 442, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (443, '000148', 'case', '/showcase.html?Id=000148', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 443, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (444, '000148', 'form', '/table.html?Id=000148', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 444, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (445, '000149', 'law', '/show.html?Id=000149', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 445, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (446, '000149', 'case', '/showcase.html?Id=000149', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 446, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (447, '000149', 'form', '/table.html?Id=000149', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 447, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (448, '000150', 'law', '/show.html?Id=000150', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 448, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (449, '000150', 'case', '/showcase.html?Id=000150', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 449, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (450, '000150', 'form', '/table.html?Id=000150', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 450, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); + +-- ---------------------------- +-- Table structure for message_system +-- ---------------------------- +DROP TABLE IF EXISTS `message_system`; +CREATE TABLE `message_system` ( + `message_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `message_title` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '标题', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `send_mode` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发送方式(0平台 1手机号 2 邮箱)', + `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '号码', + `message_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '消息内容', + `message_recipient` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '接收人', + `message_status` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '消息状态(0未读 1已读)', + `message_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '消息类型', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`message_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of message_system +-- ---------------------------- + +-- ---------------------------- +-- Table structure for message_template +-- ---------------------------- +DROP TABLE IF EXISTS `message_template`; +CREATE TABLE `message_template` ( + `template_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `template_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '模版名称', + `template_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '模版CODE', + `template_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '模版类型', + `template_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '模版内容', + `template_variable` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '变量属性', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`template_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '模版表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of message_template +-- ---------------------------- + +-- ---------------------------- +-- Table structure for message_variable +-- ---------------------------- +DROP TABLE IF EXISTS `message_variable`; +CREATE TABLE `message_variable` ( + `variable_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `variable_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '变量名称', + `variable_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '变量类型', + `variable_content` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '变量内容', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`variable_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '变量表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of message_variable +-- ---------------------------- + +-- ---------------------------- +-- Table structure for oauth_user +-- ---------------------------- +DROP TABLE IF EXISTS `oauth_user`; +CREATE TABLE `oauth_user` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', + `uuid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '第三方系统的唯一ID,详细解释请参考:名词解释', + `user_id` bigint NOT NULL COMMENT '用户ID', + `source` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '第三方用户来源,可选值:GITHUB、GITEE、QQ,更多请参考:AuthDefaultSource.java(opens new window)', + `access_token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户的授权令牌', + `expire_in` int NULL DEFAULT NULL COMMENT '第三方用户的授权令牌的有效期,部分平台可能没有', + `refresh_token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '刷新令牌,部分平台可能没有', + `open_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '第三方用户的 open id,部分平台可能没有', + `uid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '第三方用户的 ID,部分平台可能没有', + `access_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '个别平台的授权信息,部分平台可能没有', + `union_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '第三方用户的 union id,部分平台可能没有', + `scope` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '第三方用户授予的权限,部分平台可能没有', + `token_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '个别平台的授权信息,部分平台可能没有', + `id_token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'id token,部分平台可能没有', + `mac_algorithm` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '小米平台用户的附带属性,部分平台可能没有', + `mac_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '小米平台用户的附带属性,部分平台可能没有', + `code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户的授权code,部分平台可能没有', + `oauth_token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'Twitter平台用户的附带属性,部分平台可能没有', + `oauth_token_secret` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'Twitter平台用户的附带属性,部分平台可能没有', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '第三方登录' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of oauth_user +-- ---------------------------- + +-- ---------------------------- +-- Table structure for online_mb +-- ---------------------------- +DROP TABLE IF EXISTS `online_mb`; +CREATE TABLE `online_mb` ( + `mb_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `tag` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '标签名', + `tag_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '标签id', + `parameter_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '参数类型', + `result_map` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '结果类型', + `sql_text` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'sql语句', + `path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '请求路径', + `method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '请求方式', + `result_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '响应类型', + `actuator` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '执行器', + `user_id` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否需要userId', + `dept_id` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否需要deptId', + `permission_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '许可类型', + `permission_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '许可值', + `del_flag` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)', + PRIMARY KEY (`mb_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '在线接口' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of online_mb +-- ---------------------------- + +-- ---------------------------- +-- Table structure for pay_invoice +-- ---------------------------- +DROP TABLE IF EXISTS `pay_invoice`; +CREATE TABLE `pay_invoice` ( + `invoice_id` bigint NOT NULL AUTO_INCREMENT COMMENT '发票id', + `order_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '订单号', + `invoice_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发票类型', + `invoice_header` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发票抬头', + `invoice_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '纳税人识别号', + `invoice_phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '收票人手机号', + `invoice_email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '收票人邮箱', + `invoice_remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发票备注', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`invoice_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '发票' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of pay_invoice +-- ---------------------------- + +-- ---------------------------- +-- Table structure for pay_order +-- ---------------------------- +DROP TABLE IF EXISTS `pay_order`; +CREATE TABLE `pay_order` ( + `order_id` bigint NOT NULL AUTO_INCREMENT COMMENT '订单id', + `order_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '订单号', + `third_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '第三方订单号', + `order_status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '订单状态', + `total_amount` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '订单总金额', + `actual_amount` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '实际支付金额', + `order_content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '订单内容', + `order_message` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '负载信息', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`order_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '订单' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of pay_order +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_blob_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_blob_triggers`; +CREATE TABLE `qrtz_blob_triggers` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键', + `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键', + `blob_data` blob NULL COMMENT '存放持久化Trigger对象', + PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, + CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Blob类型的触发器表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_blob_triggers +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_calendars +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_calendars`; +CREATE TABLE `qrtz_calendars` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `calendar_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '日历名称', + `calendar` blob NOT NULL COMMENT '存放持久化calendar对象', + PRIMARY KEY (`sched_name`, `calendar_name`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '日历信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_calendars +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_cron_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_cron_triggers`; +CREATE TABLE `qrtz_cron_triggers` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键', + `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键', + `cron_expression` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'cron表达式', + `time_zone_id` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '时区', + PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, + CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Cron类型的触发器表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_cron_triggers +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_fired_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_fired_triggers`; +CREATE TABLE `qrtz_fired_triggers` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `entry_id` varchar(95) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度器实例id', + `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键', + `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键', + `instance_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度器实例名', + `fired_time` bigint NOT NULL COMMENT '触发的时间', + `sched_time` bigint NOT NULL COMMENT '定时器制定的时间', + `priority` int NOT NULL COMMENT '优先级', + `state` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '状态', + `job_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '任务名称', + `job_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '任务组名', + `is_nonconcurrent` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否并发', + `requests_recovery` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否接受恢复执行', + PRIMARY KEY (`sched_name`, `entry_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '已触发的触发器表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_fired_triggers +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_job_details +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_job_details`; +CREATE TABLE `qrtz_job_details` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `job_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '任务名称', + `job_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '任务组名', + `description` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '相关介绍', + `job_class_name` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '执行任务类名称', + `is_durable` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '是否持久化', + `is_nonconcurrent` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '是否并发', + `is_update_data` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '是否更新数据', + `requests_recovery` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '是否接受恢复执行', + `job_data` blob NULL COMMENT '存放持久化job对象', + PRIMARY KEY (`sched_name`, `job_name`, `job_group`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '任务详细信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_job_details +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_locks +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_locks`; +CREATE TABLE `qrtz_locks` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `lock_name` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '悲观锁名称', + PRIMARY KEY (`sched_name`, `lock_name`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '存储的悲观锁信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_locks +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_paused_trigger_grps +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`; +CREATE TABLE `qrtz_paused_trigger_grps` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键', + PRIMARY KEY (`sched_name`, `trigger_group`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '暂停的触发器表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_paused_trigger_grps +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_scheduler_state +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_scheduler_state`; +CREATE TABLE `qrtz_scheduler_state` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `instance_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '实例名称', + `last_checkin_time` bigint NOT NULL COMMENT '上次检查时间', + `checkin_interval` bigint NOT NULL COMMENT '检查间隔时间', + PRIMARY KEY (`sched_name`, `instance_name`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '调度器状态表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_scheduler_state +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_simple_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_simple_triggers`; +CREATE TABLE `qrtz_simple_triggers` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键', + `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键', + `repeat_count` bigint NOT NULL COMMENT '重复的次数统计', + `repeat_interval` bigint NOT NULL COMMENT '重复的间隔时间', + `times_triggered` bigint NOT NULL COMMENT '已经触发的次数', + PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, + CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '简单触发器的信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_simple_triggers +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_simprop_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_simprop_triggers`; +CREATE TABLE `qrtz_simprop_triggers` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键', + `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键', + `str_prop_1` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'String类型的trigger的第一个参数', + `str_prop_2` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'String类型的trigger的第二个参数', + `str_prop_3` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'String类型的trigger的第三个参数', + `int_prop_1` int NULL DEFAULT NULL COMMENT 'int类型的trigger的第一个参数', + `int_prop_2` int NULL DEFAULT NULL COMMENT 'int类型的trigger的第二个参数', + `long_prop_1` bigint NULL DEFAULT NULL COMMENT 'long类型的trigger的第一个参数', + `long_prop_2` bigint NULL DEFAULT NULL COMMENT 'long类型的trigger的第二个参数', + `dec_prop_1` decimal(13, 4) NULL DEFAULT NULL COMMENT 'decimal类型的trigger的第一个参数', + `dec_prop_2` decimal(13, 4) NULL DEFAULT NULL COMMENT 'decimal类型的trigger的第二个参数', + `bool_prop_1` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'Boolean类型的trigger的第一个参数', + `bool_prop_2` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'Boolean类型的trigger的第二个参数', + PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, + CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '同步机制的行锁表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_simprop_triggers +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_triggers`; +CREATE TABLE `qrtz_triggers` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '触发器的名字', + `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '触发器所属组的名字', + `job_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_job_details表job_name的外键', + `job_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_job_details表job_group的外键', + `description` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '相关介绍', + `next_fire_time` bigint NULL DEFAULT NULL COMMENT '上一次触发时间(毫秒)', + `prev_fire_time` bigint NULL DEFAULT NULL COMMENT '下一次触发时间(默认为-1表示不触发)', + `priority` int NULL DEFAULT NULL COMMENT '优先级', + `trigger_state` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '触发器状态', + `trigger_type` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '触发器的类型', + `start_time` bigint NOT NULL COMMENT '开始时间', + `end_time` bigint NULL DEFAULT NULL COMMENT '结束时间', + `calendar_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '日程表名称', + `misfire_instr` smallint NULL DEFAULT NULL COMMENT '补偿执行的策略', + `job_data` blob NULL COMMENT '存放持久化job对象', + PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, + INDEX `sched_name`(`sched_name` ASC, `job_name` ASC, `job_group` ASC) USING BTREE, + CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `job_name`, `job_group`) REFERENCES `qrtz_job_details` (`sched_name`, `job_name`, `job_group`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '触发器详细信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_triggers +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_config +-- ---------------------------- +DROP TABLE IF EXISTS `sys_config`; +CREATE TABLE `sys_config` ( + `config_id` int NOT NULL AUTO_INCREMENT COMMENT '参数主键', + `config_name` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '参数名称', + `config_key` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '参数键名', + `config_value` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '参数键值', + `config_type` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT 'N' COMMENT '系统内置(Y是 N否)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`config_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 106 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '参数配置表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_config +-- ---------------------------- +INSERT INTO `sys_config` VALUES (1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-green', 'Y', 'admin', '2023-04-13 20:46:20', 'admin', '2023-04-22 00:45:19', '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow'); +INSERT INTO `sys_config` VALUES (2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', '2023-04-13 20:46:20', '', NULL, '初始化密码 123456'); +INSERT INTO `sys_config` VALUES (3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-light', 'Y', 'admin', '2023-04-13 20:46:20', 'admin', '2023-04-22 00:45:25', '深色主题theme-dark,浅色主题theme-light'); +INSERT INTO `sys_config` VALUES (4, '账号自助-验证码开关', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', '2023-04-13 20:46:20', '', NULL, '是否开启验证码功能(true开启,false关闭)'); +INSERT INTO `sys_config` VALUES (5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'true', 'Y', 'admin', '2023-04-13 20:46:20', 'admin', '2023-04-22 00:41:41', '是否开启注册用户功能(true开启,false关闭)'); +INSERT INTO `sys_config` VALUES (100, '主题颜色', 'sys.index.theme', '#11A983', 'Y', 'admin', '2023-04-22 00:57:18', 'admin', '2023-04-22 00:58:23', NULL); +INSERT INTO `sys_config` VALUES (101, '开启TopNav', 'sys.index.topNav', 'false', 'Y', 'admin', '2023-04-22 00:58:59', '', NULL, NULL); +INSERT INTO `sys_config` VALUES (102, '开启Tags-Views', 'sys.index.tagsView', 'true', 'Y', 'admin', '2023-04-22 00:59:40', '', NULL, NULL); +INSERT INTO `sys_config` VALUES (103, '显示Logo', 'sys.index.sidebarLogo', 'true', 'Y', 'admin', '2023-04-22 01:00:20', '', NULL, NULL); +INSERT INTO `sys_config` VALUES (104, '固定Header', 'sys.index.fixedHeader', 'true', 'Y', 'admin', '2023-04-22 01:00:53', '', NULL, NULL); +INSERT INTO `sys_config` VALUES (105, '动态标题', 'sys.index.dynamicTitle', 'true', 'Y', 'admin', '2023-04-22 01:01:26', 'admin', '2023-04-22 01:01:41', NULL); + +-- ---------------------------- +-- Table structure for sys_deploy_form +-- ---------------------------- +DROP TABLE IF EXISTS `sys_deploy_form`; +CREATE TABLE `sys_deploy_form` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `form_id` bigint NULL DEFAULT NULL COMMENT '表单主键', + `deploy_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '流程实例主键', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 9623 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '流程实例关联表单' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_deploy_form +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_dept +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dept`; +CREATE TABLE `sys_dept` ( + `dept_id` bigint NOT NULL AUTO_INCREMENT COMMENT '部门id', + `parent_id` bigint NULL DEFAULT 0 COMMENT '父部门id', + `ancestors` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '祖级列表', + `dept_name` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '部门名称', + `order_num` int NULL DEFAULT 0 COMMENT '显示顺序', + `leader` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '负责人', + `phone` varchar(11) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系电话', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '邮箱', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '部门状态(0正常 1停用)', + `del_flag` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`dept_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 201 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '部门表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_dept +-- ---------------------------- +INSERT INTO `sys_dept` VALUES (100, 0, '0', '博越科技', 0, '博越', '15888888888', 'boyue@qq.com', '0', '0', 'admin', '2025-05-26 17:20:06', 'admin', '2025-05-29 08:42:28'); +INSERT INTO `sys_dept` VALUES (101, 100, '0,100', '淮安市', 1, '博越', '15888888888', 'boyue@qq.com', '0', '0', 'admin', '2025-05-26 17:20:06', 'admin', '2025-05-29 08:42:59'); +INSERT INTO `sys_dept` VALUES (102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2025-05-26 17:20:06', '', NULL); +INSERT INTO `sys_dept` VALUES (103, 101, '0,100,101', '管理', 2, '管理', '15888888888', 'sfj@qq.com', '0', '0', 'admin', '2025-05-26 17:20:06', 'admin', '2025-05-29 08:44:34'); +INSERT INTO `sys_dept` VALUES (104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2025-05-26 17:20:06', '', NULL); +INSERT INTO `sys_dept` VALUES (105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2025-05-26 17:20:06', '', NULL); +INSERT INTO `sys_dept` VALUES (106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2025-05-26 17:20:06', '', NULL); +INSERT INTO `sys_dept` VALUES (107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2025-05-26 17:20:06', '', NULL); +INSERT INTO `sys_dept` VALUES (108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2025-05-26 17:20:06', '', NULL); +INSERT INTO `sys_dept` VALUES (109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2025-05-26 17:20:06', '', NULL); +INSERT INTO `sys_dept` VALUES (200, 101, '0,100,101', '司法局', 3, NULL, NULL, NULL, '0', '0', 'admin', '2025-05-29 08:44:51', '', NULL); + +-- ---------------------------- +-- Table structure for sys_dict_data +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dict_data`; +CREATE TABLE `sys_dict_data` ( + `dict_code` bigint NOT NULL AUTO_INCREMENT COMMENT '字典编码', + `dict_sort` int NULL DEFAULT 0 COMMENT '字典排序', + `dict_label` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '字典标签', + `dict_value` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '字典键值', + `dict_type` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '字典类型', + `css_class` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '样式属性(其他样式扩展)', + `list_class` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '表格回显样式', + `is_default` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT 'N' COMMENT '是否默认(Y是 N否)', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '状态(0正常 1停用)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`dict_code`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 160 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '字典数据表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_dict_data +-- ---------------------------- +INSERT INTO `sys_dict_data` VALUES (1, 1, '男', '0', 'sys_user_sex', '', '', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '性别男'); +INSERT INTO `sys_dict_data` VALUES (2, 2, '女', '1', 'sys_user_sex', '', '', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '性别女'); +INSERT INTO `sys_dict_data` VALUES (3, 3, '未知', '2', 'sys_user_sex', '', '', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '性别未知'); +INSERT INTO `sys_dict_data` VALUES (4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '显示菜单'); +INSERT INTO `sys_dict_data` VALUES (5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '隐藏菜单'); +INSERT INTO `sys_dict_data` VALUES (6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '正常状态'); +INSERT INTO `sys_dict_data` VALUES (7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '停用状态'); +INSERT INTO `sys_dict_data` VALUES (8, 1, '正常', '0', 'sys_job_status', '', 'primary', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '正常状态'); +INSERT INTO `sys_dict_data` VALUES (9, 2, '暂停', '1', 'sys_job_status', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '停用状态'); +INSERT INTO `sys_dict_data` VALUES (10, 1, '默认', 'DEFAULT', 'sys_job_group', '', '', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '默认分组'); +INSERT INTO `sys_dict_data` VALUES (11, 2, '系统', 'SYSTEM', 'sys_job_group', '', '', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '系统分组'); +INSERT INTO `sys_dict_data` VALUES (12, 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '系统默认是'); +INSERT INTO `sys_dict_data` VALUES (13, 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '系统默认否'); +INSERT INTO `sys_dict_data` VALUES (14, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '通知'); +INSERT INTO `sys_dict_data` VALUES (15, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '公告'); +INSERT INTO `sys_dict_data` VALUES (16, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '正常状态'); +INSERT INTO `sys_dict_data` VALUES (17, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '关闭状态'); +INSERT INTO `sys_dict_data` VALUES (18, 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '其他操作'); +INSERT INTO `sys_dict_data` VALUES (19, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '新增操作'); +INSERT INTO `sys_dict_data` VALUES (20, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '修改操作'); +INSERT INTO `sys_dict_data` VALUES (21, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '删除操作'); +INSERT INTO `sys_dict_data` VALUES (22, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '授权操作'); +INSERT INTO `sys_dict_data` VALUES (23, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '导出操作'); +INSERT INTO `sys_dict_data` VALUES (24, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '导入操作'); +INSERT INTO `sys_dict_data` VALUES (25, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '强退操作'); +INSERT INTO `sys_dict_data` VALUES (26, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '生成操作'); +INSERT INTO `sys_dict_data` VALUES (27, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '清空操作'); +INSERT INTO `sys_dict_data` VALUES (28, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '正常状态'); +INSERT INTO `sys_dict_data` VALUES (29, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '停用状态'); +INSERT INTO `sys_dict_data` VALUES (100, 0, 'POST', 'POST', 'online_api_method', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:23:23', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (101, 0, 'GET', 'GET', 'online_api_method', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:23:30', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (102, 0, 'PUT', 'PUT', 'online_api_method', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:23:37', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (103, 0, 'DELETE', 'DELETE', 'online_api_method', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:23:49', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (104, 0, 'select', 'select', 'online_api_tag', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:24:06', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (105, 0, 'update', 'update', 'online_api_tag', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:24:12', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (106, 0, 'insert', 'insert', 'online_api_tag', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:24:18', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (107, 0, 'delete', 'delete', 'online_api_tag', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:24:26', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (108, 0, 'selectList', 'selectList', 'online_api_actuator', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:25:00', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (109, 0, 'insert', 'insert', 'online_api_actuator', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:25:05', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (110, 0, 'selectOne', 'selectOne', 'online_api_actuator', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:25:11', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (111, 0, 'update', 'update', 'online_api_actuator', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:25:16', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (112, 0, 'delete', 'delete', 'online_api_actuator', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:25:21', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (142, 0, '未读', '0', 'message_status', NULL, 'primary', 'N', '0', 'xl', '2024-12-21 15:13:02', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (143, 1, '已读', '1', 'message_status', NULL, 'success', 'N', '0', 'xl', '2024-12-21 15:13:15', 'xl', '2024-12-21 15:13:22', NULL); +INSERT INTO `sys_dict_data` VALUES (144, 0, '平台', '0', 'send_mode', NULL, 'primary', 'N', '0', 'xl', '2024-12-25 09:40:01', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (145, 1, '短信', '1', 'send_mode', NULL, 'success', 'N', '0', 'xl', '2024-12-25 09:40:16', 'xl', '2025-01-01 10:12:07', NULL); +INSERT INTO `sys_dict_data` VALUES (146, 2, '邮件', '2', 'send_mode', NULL, 'warning', 'N', '0', 'xl', '2024-12-25 09:40:28', 'xl', '2025-01-01 10:12:14', NULL); +INSERT INTO `sys_dict_data` VALUES (147, 0, '验证码', '0', 'template_type', NULL, 'primary', 'N', '0', 'xl', '2025-01-03 09:22:52', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (148, 0, '通知', '0', 'message_type', NULL, 'primary', 'N', '0', 'xl', '2025-01-03 15:12:29', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (149, 0, '提示', '1', 'message_type', NULL, 'success', 'N', '0', 'xl', '2025-01-03 15:12:41', 'xl', '2025-01-03 15:12:45', NULL); +INSERT INTO `sys_dict_data` VALUES (150, 1, '推广', '1', 'template_type', NULL, 'success', 'N', '0', 'xl', '2025-01-03 15:13:15', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (151, 0, '系统指定', 'fixed', 'exp_data_type', NULL, 'default', 'N', '0', 'admin', '2024-03-12 09:04:46', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (152, 0, '动态选择', 'dynamic', 'exp_data_type', NULL, 'default', 'N', '0', 'admin', '2024-03-12 09:05:02', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (153, 0, '任务监听', '1', 'sys_listener_type', NULL, 'default', 'N', '0', 'admin', '2022-12-25 11:47:26', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (154, 2, '执行监听', '2', 'sys_listener_type', NULL, 'default', 'N', '0', 'admin', '2022-12-25 11:47:37', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (155, 0, 'JAVA类', 'classListener', 'sys_listener_value_type', NULL, 'default', 'N', '0', 'admin', '2022-12-25 11:48:55', 'admin', '2024-09-05 21:38:02', NULL); +INSERT INTO `sys_dict_data` VALUES (156, 0, '表达式', 'expressionListener', 'sys_listener_value_type', NULL, 'default', 'N', '0', 'admin', '2022-12-25 11:49:05', 'admin', '2024-09-05 21:38:10', NULL); +INSERT INTO `sys_dict_data` VALUES (157, 0, '代理表达式', 'delegateExpressionListener', 'sys_listener_value_type', NULL, 'default', 'N', '0', 'admin', '2022-12-25 11:49:16', 'admin', '2024-09-05 21:38:16', NULL); +INSERT INTO `sys_dict_data` VALUES (158, 0, '请假', 'leave', 'sys_process_category', NULL, 'default', 'N', '0', 'admin', '2024-03-12 09:08:42', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (159, 0, '报销', 'expense', 'sys_process_category', NULL, 'default', 'N', '0', 'admin', '2024-03-12 09:09:02', '', NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_dict_type +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dict_type`; +CREATE TABLE `sys_dict_type` ( + `dict_id` bigint NOT NULL AUTO_INCREMENT COMMENT '字典主键', + `dict_name` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '字典名称', + `dict_type` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '字典类型', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '状态(0正常 1停用)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`dict_id`) USING BTREE, + UNIQUE INDEX `dict_type`(`dict_type` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 109 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '字典类型表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_dict_type +-- ---------------------------- +INSERT INTO `sys_dict_type` VALUES (1, '用户性别', 'sys_user_sex', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '用户性别列表'); +INSERT INTO `sys_dict_type` VALUES (2, '菜单状态', 'sys_show_hide', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '菜单状态列表'); +INSERT INTO `sys_dict_type` VALUES (3, '系统开关', 'sys_normal_disable', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '系统开关列表'); +INSERT INTO `sys_dict_type` VALUES (4, '任务状态', 'sys_job_status', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '任务状态列表'); +INSERT INTO `sys_dict_type` VALUES (5, '任务分组', 'sys_job_group', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '任务分组列表'); +INSERT INTO `sys_dict_type` VALUES (6, '系统是否', 'sys_yes_no', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '系统是否列表'); +INSERT INTO `sys_dict_type` VALUES (7, '通知类型', 'sys_notice_type', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '通知类型列表'); +INSERT INTO `sys_dict_type` VALUES (8, '通知状态', 'sys_notice_status', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '通知状态列表'); +INSERT INTO `sys_dict_type` VALUES (9, '操作类型', 'sys_oper_type', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '操作类型列表'); +INSERT INTO `sys_dict_type` VALUES (10, '系统状态', 'sys_common_status', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '登录状态列表'); +INSERT INTO `sys_dict_type` VALUES (100, '请求方式', 'online_api_method', '0', 'admin', '2024-02-21 18:22:03', 'admin', '2024-02-21 18:22:13', NULL); +INSERT INTO `sys_dict_type` VALUES (101, '标签名', 'online_api_tag', '0', 'admin', '2024-02-21 18:22:29', '', NULL, NULL); +INSERT INTO `sys_dict_type` VALUES (102, '响应类型', 'online_api_result', '0', 'admin', '2024-02-21 18:22:46', '', NULL, NULL); +INSERT INTO `sys_dict_type` VALUES (103, '执行器', 'online_api_actuator', '0', 'admin', '2024-02-21 18:23:03', '', NULL, NULL); +INSERT INTO `sys_dict_type` VALUES (104, '表达式类型', 'exp_data_type', '0', 'admin', '2024-03-12 09:03:02', '', NULL, NULL); +INSERT INTO `sys_dict_type` VALUES (105, '监听类型', 'sys_listener_type', '0', 'admin', '2022-12-18 22:03:07', '', NULL, NULL); +INSERT INTO `sys_dict_type` VALUES (106, '监听值类型', 'sys_listener_value_type', '0', 'admin', '2022-12-18 22:03:39', '', NULL, NULL); +INSERT INTO `sys_dict_type` VALUES (107, '监听属性', 'sys_listener_event_type', '0', 'admin', '2022-12-18 22:04:29', '', NULL, NULL); +INSERT INTO `sys_dict_type` VALUES (108, '流程分类', 'sys_process_category', '0', 'admin', '2024-03-12 09:08:18', '', NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_expression +-- ---------------------------- +DROP TABLE IF EXISTS `sys_expression`; +CREATE TABLE `sys_expression` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '表单主键', + `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '表达式名称', + `expression` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '表达式内容', + `data_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '表达式类型', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人员', + `update_by` bigint NULL DEFAULT NULL COMMENT '更新人员', + `status` tinyint NULL DEFAULT 0 COMMENT '状态', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 69 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '流程表达式' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_expression +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_file_info +-- ---------------------------- +DROP TABLE IF EXISTS `sys_file_info`; +CREATE TABLE `sys_file_info` ( + `file_id` bigint NOT NULL AUTO_INCREMENT COMMENT '文件主键', + `file_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '原始文件名', + `file_path` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '统一逻辑路径(/开头)', + `storage_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '存储类型(local/minio/oss)', + `file_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '文件类型/后缀', + `file_size` bigint NULL DEFAULT NULL COMMENT '文件大小(字节)', + `md5` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '文件MD5', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + PRIMARY KEY (`file_id`) USING BTREE, + UNIQUE INDEX `uk_md5`(`md5` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_file_info +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_job +-- ---------------------------- +DROP TABLE IF EXISTS `sys_job`; +CREATE TABLE `sys_job` ( + `job_id` bigint NOT NULL AUTO_INCREMENT COMMENT '任务ID', + `job_name` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '任务名称', + `job_group` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'DEFAULT' COMMENT '任务组名', + `invoke_target` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '调用目标字符串', + `cron_expression` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT 'cron执行表达式', + `misfire_policy` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '3' COMMENT '计划执行错误策略(1立即执行 2执行一次 3放弃执行)', + `concurrent` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '1' COMMENT '是否并发执行(0允许 1禁止)', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '状态(0正常 1暂停)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '备注信息', + PRIMARY KEY (`job_id`, `job_name`, `job_group`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 100 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '定时任务调度表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_job +-- ---------------------------- +INSERT INTO `sys_job` VALUES (1, '系统默认(无参)', 'DEFAULT', 'ryTask.ryNoParams', '0/10 * * * * ?', '3', '1', '1', 'admin', '2025-05-26 17:20:07', '', NULL, ''); +INSERT INTO `sys_job` VALUES (2, '系统默认(有参)', 'DEFAULT', 'ryTask.ryParams(\'ry\')', '0/15 * * * * ?', '3', '1', '1', 'admin', '2025-05-26 17:20:07', '', NULL, ''); +INSERT INTO `sys_job` VALUES (3, '系统默认(多参)', 'DEFAULT', 'ryTask.ryMultipleParams(\'ry\', true, 2000L, 316.50D, 100)', '0/20 * * * * ?', '3', '1', '1', 'admin', '2025-05-26 17:20:07', '', NULL, ''); + +-- ---------------------------- +-- Table structure for sys_job_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_job_log`; +CREATE TABLE `sys_job_log` ( + `job_log_id` bigint NOT NULL AUTO_INCREMENT COMMENT '任务日志ID', + `job_name` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '任务名称', + `job_group` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '任务组名', + `invoke_target` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '调用目标字符串', + `job_message` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '日志信息', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '执行状态(0正常 1失败)', + `exception_info` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '异常信息', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`job_log_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '定时任务调度日志表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_job_log +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_listener +-- ---------------------------- +DROP TABLE IF EXISTS `sys_listener`; +CREATE TABLE `sys_listener` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '表单主键', + `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '名称', + `type` char(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '监听类型', + `event_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '事件类型', + `value_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '值类型', + `value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '执行内容', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人员', + `update_by` bigint NULL DEFAULT NULL COMMENT '更新人员', + `status` tinyint NULL DEFAULT 0 COMMENT '状态', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '流程监听' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_listener +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_logininfor +-- ---------------------------- +DROP TABLE IF EXISTS `sys_logininfor`; +CREATE TABLE `sys_logininfor` ( + `info_id` bigint NOT NULL AUTO_INCREMENT COMMENT '访问ID', + `user_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '用户账号', + `ipaddr` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '登录IP地址', + `login_location` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '登录地点', + `browser` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '浏览器类型', + `os` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '操作系统', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '登录状态(0成功 1失败)', + `msg` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '提示消息', + `login_time` datetime NULL DEFAULT NULL COMMENT '访问时间', + PRIMARY KEY (`info_id`) USING BTREE, + INDEX `idx_sys_logininfor_s`(`status` ASC) USING BTREE, + INDEX `idx_sys_logininfor_lt`(`login_time` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 133 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '系统访问记录' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_logininfor +-- ---------------------------- +INSERT INTO `sys_logininfor` VALUES (100, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-26 18:37:16'); +INSERT INTO `sys_logininfor` VALUES (101, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '1', '验证码错误', '2025-05-28 18:36:01'); +INSERT INTO `sys_logininfor` VALUES (102, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-28 18:36:05'); +INSERT INTO `sys_logininfor` VALUES (103, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '退出成功', '2025-05-28 19:33:38'); +INSERT INTO `sys_logininfor` VALUES (104, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-28 19:33:47'); +INSERT INTO `sys_logininfor` VALUES (105, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-28 20:46:43'); +INSERT INTO `sys_logininfor` VALUES (106, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-28 21:18:44'); +INSERT INTO `sys_logininfor` VALUES (107, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 06:59:57'); +INSERT INTO `sys_logininfor` VALUES (108, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 08:41:00'); +INSERT INTO `sys_logininfor` VALUES (109, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '退出成功', '2025-05-29 10:46:05'); +INSERT INTO `sys_logininfor` VALUES (110, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 10:46:17'); +INSERT INTO `sys_logininfor` VALUES (111, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 12:33:00'); +INSERT INTO `sys_logininfor` VALUES (112, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '退出成功', '2025-05-29 12:33:12'); +INSERT INTO `sys_logininfor` VALUES (113, 'hasfj', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 12:33:26'); +INSERT INTO `sys_logininfor` VALUES (114, 'hasfj', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '退出成功', '2025-05-29 12:33:50'); +INSERT INTO `sys_logininfor` VALUES (115, 'admin', '49.74.40.190', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 13:28:43'); +INSERT INTO `sys_logininfor` VALUES (116, 'admin', '49.74.40.190', 'XX XX', 'Chrome 13', 'Windows 10', '0', '退出成功', '2025-05-29 13:28:52'); +INSERT INTO `sys_logininfor` VALUES (117, 'admin', '49.74.40.190', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 14:55:02'); +INSERT INTO `sys_logininfor` VALUES (118, 'hasfj', '49.74.40.190', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 14:56:29'); +INSERT INTO `sys_logininfor` VALUES (119, 'hasfj', '114.238.34.181', 'XX XX', 'Safari', 'Mac OS X', '0', '登录成功', '2025-05-29 14:57:15'); +INSERT INTO `sys_logininfor` VALUES (120, 'admin', '49.82.111.128', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-30 13:39:02'); +INSERT INTO `sys_logininfor` VALUES (121, 'admin', '49.82.111.128', 'XX XX', 'Chrome 13', 'Windows 10', '0', '退出成功', '2025-05-30 13:49:58'); +INSERT INTO `sys_logininfor` VALUES (122, 'admin', '49.82.111.128', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-30 13:50:12'); +INSERT INTO `sys_logininfor` VALUES (123, 'admin', '180.125.41.129', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-31 08:54:48'); +INSERT INTO `sys_logininfor` VALUES (124, 'admin', '49.87.176.188', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-31 12:12:39'); +INSERT INTO `sys_logininfor` VALUES (125, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-31 14:44:08'); +INSERT INTO `sys_logininfor` VALUES (126, 'admin', '180.125.41.129', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-31 15:04:25'); +INSERT INTO `sys_logininfor` VALUES (127, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-31 19:26:24'); +INSERT INTO `sys_logininfor` VALUES (128, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-06-01 10:15:29'); +INSERT INTO `sys_logininfor` VALUES (129, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-06-01 11:03:00'); +INSERT INTO `sys_logininfor` VALUES (130, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-06-02 13:51:42'); +INSERT INTO `sys_logininfor` VALUES (131, 'admin', '218.2.75.254', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-06-02 19:18:18'); +INSERT INTO `sys_logininfor` VALUES (132, 'admin', '218.2.75.254', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-06-02 19:33:32'); + +-- ---------------------------- +-- Table structure for sys_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_menu`; +CREATE TABLE `sys_menu` ( + `menu_id` bigint NOT NULL AUTO_INCREMENT COMMENT '菜单ID', + `menu_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '菜单名称', + `parent_id` bigint NULL DEFAULT 0 COMMENT '父菜单ID', + `order_num` int NULL DEFAULT 0 COMMENT '显示顺序', + `path` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '路由地址', + `component` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '组件路径', + `query` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '路由参数', + `route_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '路由名称', + `is_frame` int NULL DEFAULT 1 COMMENT '是否为外链(0是 1否)', + `is_cache` int NULL DEFAULT 0 COMMENT '是否缓存(0缓存 1不缓存)', + `menu_type` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '菜单类型(M目录 C菜单 F按钮)', + `visible` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '菜单状态(0显示 1隐藏)', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '菜单状态(0正常 1停用)', + `perms` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '权限标识', + `icon` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '#' COMMENT '菜单图标', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '备注', + PRIMARY KEY (`menu_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2105 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '菜单权限表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_menu +-- ---------------------------- +INSERT INTO `sys_menu` VALUES (1, '系统管理', 0, 1, 'system', NULL, '', '', 1, 0, 'M', '0', '0', '', 'system', 'admin', '2025-05-26 17:20:06', '', NULL, '系统管理目录'); +INSERT INTO `sys_menu` VALUES (2, '系统监控', 0, 2, 'monitor', NULL, '', '', 1, 0, 'M', '0', '0', '', 'monitor', 'admin', '2025-05-26 17:20:06', '', NULL, '系统监控目录'); +INSERT INTO `sys_menu` VALUES (3, '系统工具', 0, 3, 'tool', NULL, '', '', 1, 0, 'M', '0', '0', '', 'tool', 'admin', '2025-05-26 17:20:06', '', NULL, '系统工具目录'); +INSERT INTO `sys_menu` VALUES (100, '用户管理', 1, 1, 'user', 'system/user/index', '', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', '2025-05-26 17:20:06', '', NULL, '用户管理菜单'); +INSERT INTO `sys_menu` VALUES (101, '角色管理', 1, 2, 'role', 'system/role/index', '', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', '2025-05-26 17:20:06', '', NULL, '角色管理菜单'); +INSERT INTO `sys_menu` VALUES (102, '菜单管理', 1, 3, 'menu', 'system/menu/index', '', '', 1, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', 'admin', '2025-05-26 17:20:06', '', NULL, '菜单管理菜单'); +INSERT INTO `sys_menu` VALUES (103, '部门管理', 1, 4, 'dept', 'system/dept/index', '', '', 1, 0, 'C', '0', '0', 'system:dept:list', 'tree', 'admin', '2025-05-26 17:20:06', '', NULL, '部门管理菜单'); +INSERT INTO `sys_menu` VALUES (104, '岗位管理', 1, 5, 'post', 'system/post/index', '', '', 1, 0, 'C', '0', '0', 'system:post:list', 'post', 'admin', '2025-05-26 17:20:06', '', NULL, '岗位管理菜单'); +INSERT INTO `sys_menu` VALUES (105, '字典管理', 1, 6, 'dict', 'system/dict/index', '', '', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 'admin', '2025-05-26 17:20:06', '', NULL, '字典管理菜单'); +INSERT INTO `sys_menu` VALUES (106, '参数设置', 1, 7, 'config', 'system/config/index', '', '', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 'admin', '2025-05-26 17:20:06', '', NULL, '参数设置菜单'); +INSERT INTO `sys_menu` VALUES (107, '通知公告', 1, 8, 'notice', 'system/notice/index', '', '', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 'admin', '2025-05-26 17:20:06', '', NULL, '通知公告菜单'); +INSERT INTO `sys_menu` VALUES (108, '日志管理', 1, 9, 'log', '', '', '', 1, 0, 'M', '0', '0', '', 'log', 'admin', '2025-05-26 17:20:06', '', NULL, '日志管理菜单'); +INSERT INTO `sys_menu` VALUES (109, '在线用户', 2, 1, 'online', 'monitor/online/index', '', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 'admin', '2025-05-26 17:20:06', '', NULL, '在线用户菜单'); +INSERT INTO `sys_menu` VALUES (110, '定时任务', 2, 2, 'job', 'monitor/job/index', '', '', 1, 0, 'C', '0', '0', 'monitor:job:list', 'job', 'admin', '2025-05-26 17:20:06', '', NULL, '定时任务菜单'); +INSERT INTO `sys_menu` VALUES (111, '数据监控', 2, 3, 'druid', 'monitor/druid/index', '', '', 1, 0, 'C', '0', '0', 'monitor:druid:list', 'druid', 'admin', '2025-05-26 17:20:06', '', NULL, '数据监控菜单'); +INSERT INTO `sys_menu` VALUES (112, '服务监控', 2, 4, 'server', 'monitor/server/index', '', '', 1, 0, 'C', '0', '0', 'monitor:server:list', 'server', 'admin', '2025-05-26 17:20:06', '', NULL, '服务监控菜单'); +INSERT INTO `sys_menu` VALUES (113, '缓存监控', 2, 5, 'cache', 'monitor/cache/index', '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 'admin', '2025-05-26 17:20:06', '', NULL, '缓存监控菜单'); +INSERT INTO `sys_menu` VALUES (114, '缓存列表', 2, 6, 'cacheList', 'monitor/cache/list', '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis-list', 'admin', '2025-05-26 17:20:06', '', NULL, '缓存列表菜单'); +INSERT INTO `sys_menu` VALUES (115, '表单构建', 3, 1, 'build', 'tool/build/index', '', '', 1, 0, 'C', '0', '0', 'tool:build:list', 'build', 'admin', '2025-05-26 17:20:06', '', NULL, '表单构建菜单'); +INSERT INTO `sys_menu` VALUES (116, '代码生成', 3, 2, 'gen', 'tool/gen/index', '', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 'admin', '2025-05-26 18:42:26', '', NULL, '代码生成菜单'); +INSERT INTO `sys_menu` VALUES (117, '系统接口', 3, 3, 'swagger', 'tool/swagger/index', '', '', 1, 0, 'C', '0', '0', 'tool:swagger:list', 'swagger', 'admin', '2025-05-26 17:20:06', '', NULL, '系统接口菜单'); +INSERT INTO `sys_menu` VALUES (500, '操作日志', 108, 1, 'operlog', 'monitor/operlog/index', '', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 'admin', '2025-05-26 17:20:06', '', NULL, '操作日志菜单'); +INSERT INTO `sys_menu` VALUES (501, '登录日志', 108, 2, 'logininfor', 'monitor/logininfor/index', '', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 'admin', '2025-05-26 17:20:06', '', NULL, '登录日志菜单'); +INSERT INTO `sys_menu` VALUES (1000, '用户查询', 100, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1001, '用户新增', 100, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1002, '用户修改', 100, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1003, '用户删除', 100, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1004, '用户导出', 100, 5, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1005, '用户导入', 100, 6, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:import', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1006, '重置密码', 100, 7, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1007, '角色查询', 101, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1008, '角色新增', 101, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1009, '角色修改', 101, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1010, '角色删除', 101, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1011, '角色导出', 101, 5, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1012, '菜单查询', 102, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1013, '菜单新增', 102, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1014, '菜单修改', 102, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1015, '菜单删除', 102, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1016, '部门查询', 103, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1017, '部门新增', 103, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1018, '部门修改', 103, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1019, '部门删除', 103, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1020, '岗位查询', 104, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1021, '岗位新增', 104, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1022, '岗位修改', 104, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1023, '岗位删除', 104, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1024, '岗位导出', 104, 5, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1025, '字典查询', 105, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1026, '字典新增', 105, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1027, '字典修改', 105, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1028, '字典删除', 105, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1029, '字典导出', 105, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1030, '参数查询', 106, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1031, '参数新增', 106, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1032, '参数修改', 106, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1033, '参数删除', 106, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1034, '参数导出', 106, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1035, '公告查询', 107, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1036, '公告新增', 107, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1037, '公告修改', 107, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1038, '公告删除', 107, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1039, '操作查询', 500, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1040, '操作删除', 500, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1041, '日志导出', 500, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1042, '登录查询', 501, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1043, '登录删除', 501, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1044, '日志导出', 501, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1045, '账户解锁', 501, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1046, '在线查询', 109, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1047, '批量强退', 109, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1048, '单条强退', 109, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1049, '任务查询', 110, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1050, '任务新增', 110, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1051, '任务修改', 110, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1052, '任务删除', 110, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1053, '状态修改', 110, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:changeStatus', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1054, '任务导出', 110, 6, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1055, '生成查询', 116, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 'admin', '2025-05-26 18:42:26', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1056, '生成修改', 116, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 'admin', '2025-05-26 18:42:26', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1057, '生成删除', 116, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 'admin', '2025-05-26 18:42:26', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1058, '导入代码', 116, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 'admin', '2025-05-26 18:42:26', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1059, '预览代码', 116, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', '2025-05-26 18:42:26', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1060, '生成代码', 116, 6, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', '2025-05-26 18:42:26', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2000, '支付管理', 0, 4, 'pay', NULL, NULL, '', 1, 0, 'M', '1', '1', '', 'money', 'admin', '2024-02-15 22:40:23', 'admin', '2025-05-28 18:37:31', ''); +INSERT INTO `sys_menu` VALUES (2001, '订单', 2000, 1, 'order', 'pay/order/index', NULL, '', 1, 0, 'C', '0', '0', 'pay:order:list', '#', 'admin', '2025-05-26 18:42:52', '', NULL, '订单菜单'); +INSERT INTO `sys_menu` VALUES (2002, '订单查询', 2001, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:order:query', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2003, '订单新增', 2001, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:order:add', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2004, '订单修改', 2001, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:order:edit', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2005, '订单删除', 2001, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:order:remove', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2006, '订单导出', 2001, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:order:export', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2007, '发票', 2000, 1, 'invoice', 'pay/invoice/index', NULL, '', 1, 0, 'C', '0', '0', 'pay:invoice:list', '#', 'admin', '2025-05-26 18:42:52', '', NULL, '发票菜单'); +INSERT INTO `sys_menu` VALUES (2008, '发票查询', 2007, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:invoice:query', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2009, '发票新增', 2007, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:invoice:add', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2010, '发票修改', 2007, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:invoice:edit', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2011, '发票删除', 2007, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:invoice:remove', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2012, '发票导出', 2007, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:invoice:export', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2013, 'Online', 0, 5, 'onlinedev', NULL, NULL, '', 1, 0, 'M', '1', '1', '', 'international', 'admin', '2024-03-07 19:38:34', 'admin', '2025-05-28 18:37:18', ''); +INSERT INTO `sys_menu` VALUES (2014, 'mybatis在线接口', 2013, 1, 'mb', 'online/mb/index', NULL, '', 1, 0, 'C', '0', '0', 'online:mb:list', 'code', 'admin', '2025-05-26 18:42:57', '', NULL, 'mybatis在线接口菜单'); +INSERT INTO `sys_menu` VALUES (2015, '数据库', 2013, 1, 'db', 'online/db/index', NULL, '', 1, 0, 'C', '0', '0', 'admin', 'table', 'admin', '2024-03-07 19:48:24', 'admin', '2024-03-07 19:54:46', ''); +INSERT INTO `sys_menu` VALUES (2016, 'mybatis在线接口查询', 2015, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'online:mb:query', '#', 'admin', '2025-05-26 18:42:57', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2017, 'mybatis在线接口新增', 2015, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'online:mb:add', '#', 'admin', '2025-05-26 18:42:57', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2018, 'mybatis在线接口修改', 2015, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'online:mb:edit', '#', 'admin', '2025-05-26 18:42:57', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2019, 'mybatis在线接口删除', 2015, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'online:mb:remove', '#', 'admin', '2025-05-26 18:42:57', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2020, 'mybatis在线接口导出', 2015, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'online:mb:export', '#', 'admin', '2025-05-26 18:42:57', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2021, '消息系统', 0, 6, 'modelMessage', NULL, NULL, '', 1, 0, 'M', '1', '1', '', 'message', 'admin', '2024-12-31 11:57:29', 'admin', '2025-05-28 18:37:14', ''); +INSERT INTO `sys_menu` VALUES (2022, '消息管理', 2021, 0, 'messageSystem', 'modelMessage/messageSystem/index', NULL, '', 1, 0, 'C', '0', '0', 'modelMessage:messageSystem:list', '#', 'admin', '2024-12-21 15:00:31', 'admin', '2024-12-31 15:04:49', '消息管理菜单'); +INSERT INTO `sys_menu` VALUES (2023, '消息管理查询', 2022, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:messageSystem:query', '#', 'admin', '2024-12-21 15:00:31', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2024, '消息管理新增', 2022, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:messageSystem:add', '#', 'admin', '2024-12-21 15:00:31', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2025, '消息管理修改', 2022, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:messageSystem:edit', '#', 'admin', '2024-12-21 15:00:31', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2026, '消息管理删除', 2022, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:messageSystem:remove', '#', 'admin', '2024-12-21 15:00:31', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2027, '消息管理导出', 2022, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:messageSystem:export', '#', 'admin', '2024-12-21 15:00:31', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2028, '模版管理', 2021, 1, 'template', 'modelMessage/template/index', NULL, '', 1, 0, 'C', '0', '0', 'modelMessage:template:list', '#', 'admin', '2024-12-31 14:59:52', '', NULL, '模版管理菜单'); +INSERT INTO `sys_menu` VALUES (2029, '模版管理查询', 2028, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:template:query', '#', 'admin', '2024-12-31 14:59:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2030, '模版管理新增', 2028, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:template:add', '#', 'admin', '2024-12-31 14:59:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2031, '模版管理修改', 2028, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:template:edit', '#', 'admin', '2024-12-31 14:59:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2032, '模版管理删除', 2028, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:template:remove', '#', 'admin', '2024-12-31 14:59:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2033, '模版管理导出', 2028, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:template:export', '#', 'admin', '2024-12-31 14:59:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2034, '变量管理', 2021, 2, 'variable', 'modelMessage/variable/index', NULL, '', 1, 0, 'C', '0', '0', 'modelMessage:variable:list', '#', 'admin', '2024-12-31 15:01:50', 'admin', '2024-12-31 15:04:56', '变量管理菜单'); +INSERT INTO `sys_menu` VALUES (2035, '变量管理查询', 2034, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:variable:query', '#', 'admin', '2024-12-31 15:01:50', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2036, '变量管理新增', 2034, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:variable:add', '#', 'admin', '2024-12-31 15:01:50', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2037, '变量管理修改', 2034, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:variable:edit', '#', 'admin', '2024-12-31 15:01:50', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2038, '变量管理删除', 2034, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:variable:remove', '#', 'admin', '2024-12-31 15:01:50', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2039, '变量管理导出', 2034, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:variable:export', '#', 'admin', '2024-12-31 15:01:50', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2040, '表单管理', 0, 4, 'formManagement', NULL, NULL, '', 1, 0, 'M', '1', '1', '', 'form', 'admin', '2024-02-15 22:40:23', 'admin', '2025-05-28 18:37:27', ''); +INSERT INTO `sys_menu` VALUES (2041, '表单模板', 2040, 1, 'formtemplate', 'form/template/index', NULL, '', 1, 0, 'C', '0', '0', 'form:template:list', '#', 'admin', '2025-05-26 18:43:09', '', NULL, '表单模板菜单'); +INSERT INTO `sys_menu` VALUES (2042, '表单模板查询', 2041, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:template:query', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2043, '表单模板新增', 2041, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:template:add', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2044, '表单模板修改', 2041, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:template:edit', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2045, '表单模板删除', 2041, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:template:remove', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2046, '表单模板导出', 2041, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:template:export', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2047, '表单数据', 2040, 1, 'formdata', 'form/data/index', NULL, '', 1, 0, 'C', '0', '0', 'form:data:list', '#', 'admin', '2025-05-26 18:43:09', '', NULL, '表单数据菜单'); +INSERT INTO `sys_menu` VALUES (2048, '表单数据查询', 2047, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:data:query', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2049, '表单数据新增', 2047, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:data:add', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2050, '表单数据修改', 2047, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:data:edit', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2051, '表单数据删除', 2047, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:data:remove', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2052, '表单数据导出', 2047, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:data:export', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2053, '流程管理', 0, 6, 'flowable', NULL, NULL, NULL, 1, 0, 'M', '1', '1', '', 'cascader', 'tony', '2021-03-25 11:35:09', 'admin', '2025-05-28 18:37:09', ''); +INSERT INTO `sys_menu` VALUES (2054, '流程定义', 2053, 2, 'definition', 'flowable/definition/index', NULL, NULL, 1, 0, 'C', '0', '0', '', 'job', 'tony', '2021-03-25 13:53:55', 'admin', '2022-12-29 17:40:39', ''); +INSERT INTO `sys_menu` VALUES (2055, '任务管理', 0, 7, 'task', NULL, NULL, NULL, 1, 0, 'M', '1', '1', '', 'dict', 'tony', '2021-03-26 10:53:10', 'admin', '2025-05-28 18:37:05', ''); +INSERT INTO `sys_menu` VALUES (2056, '待办任务', 2055, 2, 'todo', 'flowable/task/todo/index', NULL, NULL, 1, 1, 'C', '0', '0', '', 'cascader', 'admin', '2021-03-26 10:55:52', 'admin', '2021-03-30 09:26:36', ''); +INSERT INTO `sys_menu` VALUES (2057, '已办任务', 2055, 3, 'finished', 'flowable/task/finished/index', NULL, NULL, 1, 1, 'C', '0', '0', '', 'time-range', 'admin', '2021-03-26 10:57:54', 'admin', '2021-03-30 09:26:50', ''); +INSERT INTO `sys_menu` VALUES (2058, '已发任务', 2055, 1, 'process', 'flowable/task/myProcess/index', NULL, NULL, 1, 1, 'C', '0', '0', '', 'guide', 'admin', '2021-03-30 09:26:23', 'admin', '2022-12-12 09:58:07', ''); +INSERT INTO `sys_menu` VALUES (2059, '新增', 2058, 1, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'system:deployment:add', '#', 'admin', '2021-07-07 14:25:22', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2060, '编辑', 2058, 2, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'system:deployment:edit', '#', 'admin', '2021-07-07 14:25:47', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2061, '删除', 2058, 3, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'system:deployment:remove', '#', 'admin', '2021-07-07 14:26:02', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2062, '流程表达式', 2053, 3, 'expression', 'flowable/expression/index', NULL, NULL, 1, 1, 'C', '0', '0', 'system:expression:list', 'list', 'admin', '2022-12-12 17:12:19', 'admin', '2022-12-12 17:13:44', '流程达式菜单'); +INSERT INTO `sys_menu` VALUES (2063, '流程达式查询', 2062, 1, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:expression:query', '#', 'admin', '2022-12-12 17:12:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2064, '流程达式新增', 2062, 2, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:expression:add', '#', 'admin', '2022-12-12 17:12:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2065, '流程达式修改', 2062, 3, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:expression:edit', '#', 'admin', '2022-12-12 17:12:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2066, '流程达式删除', 2062, 4, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:expression:remove', '#', 'admin', '2022-12-12 17:12:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2067, '流程达式导出', 2062, 5, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:expression:export', '#', 'admin', '2022-12-12 17:12:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2068, '流程监听', 2053, 4, 'listener', 'flowable/listener/index', NULL, NULL, 1, 0, 'C', '0', '0', 'system:listener:list', 'monitor', 'admin', '2022-12-25 11:44:16', 'admin', '2022-12-29 08:59:21', '流程监听菜单'); +INSERT INTO `sys_menu` VALUES (2069, '流程监听查询', 2068, 1, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:listener:query', '#', 'admin', '2022-12-25 11:44:16', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2070, '流程监听新增', 2068, 2, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:listener:add', '#', 'admin', '2022-12-25 11:44:16', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2071, '流程监听修改', 2068, 3, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:listener:edit', '#', 'admin', '2022-12-25 11:44:16', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2072, '流程监听删除', 2068, 4, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:listener:remove', '#', 'admin', '2022-12-25 11:44:16', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2073, '流程监听导出', 2068, 5, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:listener:export', '#', 'admin', '2022-12-25 11:44:16', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2074, '文件管理', 0, 4, 'file', NULL, NULL, '', 1, 0, 'M', '1', '1', '', 'excel', 'admin', '2024-02-15 22:40:23', 'admin', '2025-05-28 18:37:23', ''); +INSERT INTO `sys_menu` VALUES (2075, '文件信息', 2074, 1, 'info', 'file/info/index', NULL, '', 1, 0, 'C', '0', '0', 'file:info:list', 'excel', 'admin', '2025-05-26 18:43:20', '', NULL, '文件信息菜单'); +INSERT INTO `sys_menu` VALUES (2076, '文件信息查询', 2075, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'file:info:query', '#', 'admin', '2025-05-26 18:43:20', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2077, '文件信息新增', 2075, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'file:info:add', '#', 'admin', '2025-05-26 18:43:20', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2078, '文件信息修改', 2075, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'file:info:edit', '#', 'admin', '2025-05-26 18:43:20', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2079, '文件信息删除', 2075, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'file:info:remove', '#', 'admin', '2025-05-26 18:43:20', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2080, '文件信息导出', 2075, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'file:info:export', '#', 'admin', '2025-05-26 18:43:20', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2081, '第三方认证', 1, 1, 'oauth', 'system/oauth/index', NULL, '', 1, 0, 'C', '0', '0', 'system:oauth:list', 'checkbox', 'admin', '2025-05-26 18:43:24', '', NULL, '第三方认证菜单'); +INSERT INTO `sys_menu` VALUES (2082, '第三方认证查询', 2081, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'system:oauth:query', '#', 'admin', '2025-05-26 18:43:24', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2083, '第三方认证新增', 2081, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'system:oauth:add', '#', 'admin', '2025-05-26 18:43:24', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2084, '第三方认证修改', 2081, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'system:oauth:edit', '#', 'admin', '2025-05-26 18:43:24', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2085, '第三方认证删除', 2081, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'system:oauth:remove', '#', 'admin', '2025-05-26 18:43:24', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2086, '第三方认证导出', 2081, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'system:oauth:export', '#', 'admin', '2025-05-26 18:43:24', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2097, '淮安市司法局网站', 0, 40, 'hasfj', NULL, NULL, '', 1, 0, 'M', '0', '0', '', 'peoples', 'admin', '2025-05-28 21:46:52', '', NULL, '淮安市司法局网站管理'); +INSERT INTO `sys_menu` VALUES (2099, '页面内容管理', 2097, 1, 'hasfjpages', 'hasfj/hasfjpages/index', NULL, '', 1, 0, 'C', '0', '0', 'hasfj:hasfjpages:list', 'documentation', 'admin', '2025-05-28 21:48:22', '', NULL, '司法局法律规定、典型案例、单下载菜单'); +INSERT INTO `sys_menu` VALUES (2100, '页面内容查询', 2099, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'hasfj:hasfjpages:query', '#', 'admin', '2025-05-28 21:48:22', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2101, '页面内容新增', 2099, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'hasfj:hasfjpages:add', '#', 'admin', '2025-05-28 21:48:22', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2102, '页面内容修改', 2099, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'hasfj:hasfjpages:edit', '#', 'admin', '2025-05-28 21:48:22', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2103, '页面内容删除', 2099, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'hasfj:hasfjpages:remove', '#', 'admin', '2025-05-28 21:48:22', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2104, '页面内容导出', 2099, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'hasfj:hasfjpages:export', '#', 'admin', '2025-05-28 21:48:22', '', NULL, ''); + +-- ---------------------------- +-- Table structure for sys_notice +-- ---------------------------- +DROP TABLE IF EXISTS `sys_notice`; +CREATE TABLE `sys_notice` ( + `notice_id` int NOT NULL AUTO_INCREMENT COMMENT '公告ID', + `notice_title` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '公告标题', + `notice_type` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '公告类型(1通知 2公告)', + `notice_content` longblob NULL COMMENT '公告内容', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '公告状态(0正常 1关闭)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`notice_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '通知公告表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_notice +-- ---------------------------- +INSERT INTO `sys_notice` VALUES (1, '温馨提醒:2018-07-01 若依新版本发布啦', '2', 0xE696B0E78988E69CACE58685E5AEB9, '0', 'admin', '2025-05-26 17:20:07', '', NULL, '管理员'); +INSERT INTO `sys_notice` VALUES (2, '维护通知:2018-07-01 若依系统凌晨维护', '1', 0xE7BBB4E68AA4E58685E5AEB9, '0', 'admin', '2025-05-26 17:20:07', '', NULL, '管理员'); + +-- ---------------------------- +-- Table structure for sys_oper_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_oper_log`; +CREATE TABLE `sys_oper_log` ( + `oper_id` bigint NOT NULL AUTO_INCREMENT COMMENT '日志主键', + `title` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '模块标题', + `business_type` int NULL DEFAULT 0 COMMENT '业务类型(0其它 1新增 2修改 3删除)', + `method` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '方法名称', + `request_method` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '请求方式', + `operator_type` int NULL DEFAULT 0 COMMENT '操作类别(0其它 1后台用户 2手机端用户)', + `oper_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '操作人员', + `dept_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '部门名称', + `oper_url` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '请求URL', + `oper_ip` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '主机地址', + `oper_location` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '操作地点', + `oper_param` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '请求参数', + `json_result` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '返回参数', + `status` int NULL DEFAULT 0 COMMENT '操作状态(0正常 1异常)', + `error_msg` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '错误消息', + `oper_time` datetime NULL DEFAULT NULL COMMENT '操作时间', + `cost_time` bigint NULL DEFAULT 0 COMMENT '消耗时间', + PRIMARY KEY (`oper_id`) USING BTREE, + INDEX `idx_sys_oper_log_bt`(`business_type` ASC) USING BTREE, + INDEX `idx_sys_oper_log_s`(`status` ASC) USING BTREE, + INDEX `idx_sys_oper_log_ot`(`oper_time` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 231 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '操作日志记录' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_oper_log +-- ---------------------------- +INSERT INTO `sys_oper_log` VALUES (100, '用户头像', 2, 'com.boyue.web.controller.system.SysProfileController.avatar()', 'POST', 1, 'admin', '研发部门', '/system/user/profile/avatar', '127.0.0.1', '内网IP', '', '{\"msg\":\"操作成功\",\"imgUrl\":\"http://localhost:8080/profile/files/master/avatar/admin/1/20250526183841-avatar.png\",\"code\":200}', 0, NULL, '2025-05-26 18:38:41', 103); +INSERT INTO `sys_oper_log` VALUES (101, '菜单管理', 3, 'com.boyue.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/menu/4', '127.0.0.1', '内网IP', '4', '{\"msg\":\"菜单已分配,不允许删除\",\"code\":601}', 0, NULL, '2025-05-28 18:36:42', 16); +INSERT INTO `sys_oper_log` VALUES (102, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2025-05-26 17:20:06\",\"icon\":\"guide\",\"isCache\":\"0\",\"isFrame\":\"0\",\"menuId\":4,\"menuName\":\"若依官网\",\"menuType\":\"M\",\"orderNum\":4,\"params\":{},\"parentId\":0,\"path\":\"http://boyue.vip\",\"perms\":\"\",\"query\":\"\",\"routeName\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:36:51', 31); +INSERT INTO `sys_oper_log` VALUES (103, '菜单管理', 3, 'com.boyue.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/menu/4', '127.0.0.1', '内网IP', '4', '{\"msg\":\"菜单已分配,不允许删除\",\"code\":601}', 0, NULL, '2025-05-28 18:36:54', 6); +INSERT INTO `sys_oper_log` VALUES (104, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2021-03-26 10:53:10\",\"icon\":\"dict\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2055,\"menuName\":\"任务管理\",\"menuType\":\"M\",\"orderNum\":7,\"params\":{},\"parentId\":0,\"path\":\"task\",\"perms\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:37:05', 62); +INSERT INTO `sys_oper_log` VALUES (105, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2021-03-25 11:35:09\",\"icon\":\"cascader\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2053,\"menuName\":\"流程管理\",\"menuType\":\"M\",\"orderNum\":6,\"params\":{},\"parentId\":0,\"path\":\"flowable\",\"perms\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:37:09', 27); +INSERT INTO `sys_oper_log` VALUES (106, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2024-12-31 11:57:29\",\"icon\":\"message\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2021,\"menuName\":\"消息系统\",\"menuType\":\"M\",\"orderNum\":6,\"params\":{},\"parentId\":0,\"path\":\"modelMessage\",\"perms\":\"\",\"routeName\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:37:14', 17); +INSERT INTO `sys_oper_log` VALUES (107, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2024-03-07 19:38:34\",\"icon\":\"international\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2013,\"menuName\":\"Online\",\"menuType\":\"M\",\"orderNum\":5,\"params\":{},\"parentId\":0,\"path\":\"onlinedev\",\"perms\":\"\",\"routeName\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:37:18', 23); +INSERT INTO `sys_oper_log` VALUES (108, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2024-02-15 22:40:23\",\"icon\":\"excel\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2074,\"menuName\":\"文件管理\",\"menuType\":\"M\",\"orderNum\":4,\"params\":{},\"parentId\":0,\"path\":\"file\",\"perms\":\"\",\"routeName\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:37:23', 29); +INSERT INTO `sys_oper_log` VALUES (109, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2024-02-15 22:40:23\",\"icon\":\"form\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2040,\"menuName\":\"表单管理\",\"menuType\":\"M\",\"orderNum\":4,\"params\":{},\"parentId\":0,\"path\":\"formManagement\",\"perms\":\"\",\"routeName\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:37:27', 26); +INSERT INTO `sys_oper_log` VALUES (110, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2024-02-15 22:40:23\",\"icon\":\"money\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2000,\"menuName\":\"支付管理\",\"menuType\":\"M\",\"orderNum\":4,\"params\":{},\"parentId\":0,\"path\":\"pay\",\"perms\":\"\",\"routeName\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:37:31', 20); +INSERT INTO `sys_oper_log` VALUES (111, '代码生成', 6, 'com.boyue.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '研发部门', '/tool/gen/importTable', '127.0.0.1', '内网IP', '{\"tables\":\"html_pages\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:57:49', 51); +INSERT INTO `sys_oper_log` VALUES (112, '代码生成', 2, 'com.boyue.generator.controller.GenController.synchDb()', 'GET', 1, 'admin', '研发部门', '/tool/gen/synchDb/html_pages', '127.0.0.1', '内网IP', '{}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 19:04:38', 48); +INSERT INTO `sys_oper_log` VALUES (113, '代码生成', 2, 'com.boyue.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '研发部门', '/tool/gen', '127.0.0.1', '内网IP', '{\"allGenTableColumns\":[{\"capJavaField\":\"Id\",\"columnComment\":\"序号\",\"columnId\":1,\"columnName\":\"id\",\"columnType\":\"int(11)\",\"dictType\":\"\",\"edit\":false,\"htmlType\":\"input\",\"increment\":false,\"insert\":false,\"isIncrement\":\"0\",\"isInsert\":\"0\",\"isList\":\"1\",\"isPk\":\"1\",\"isRequired\":\"0\",\"javaField\":\"id\",\"javaType\":\"Long\",\"list\":true,\"params\":{},\"pk\":true,\"query\":false,\"queryType\":\"EQ\",\"required\":false,\"sort\":1,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"FormatId\",\"columnComment\":\"访问id\",\"columnId\":2,\"columnName\":\"format_id\",\"columnType\":\"varchar(6)\",\"dictType\":\"\",\"edit\":true,\"htmlType\":\"input\",\"increment\":false,\"insert\":true,\"isEdit\":\"1\",\"isIncrement\":\"0\",\"isInsert\":\"1\",\"isList\":\"1\",\"isPk\":\"0\",\"isQuery\":\"1\",\"isRequired\":\"1\",\"javaField\":\"formatId\",\"javaType\":\"String\",\"list\":true,\"params\":{},\"pk\":false,\"query\":true,\"queryType\":\"EQ\",\"required\":true,\"sort\":2,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"Title\",\"columnComment\":\"页面标题\",\"columnId\":3,\"columnName\":\"title\",\"columnType\":\"varchar(200)\",\"dictType\":\"\",\"edit\":true,\"htmlType\":\"input\",\"increment\":false,\"insert\":true,\"isEdit\":\"1\",\"isIncrement\":\"0\",\"isInsert\":\"1\",\"isList\":\"1\",\"isPk\":\"0\",\"isQuery\":\"1\",\"isRequired\":\"1\",\"javaField\":\"title\",\"javaType\":\"String\",\"list\":true,\"params\":{},\"pk\":false,\"query\":true,\"queryType\":\"EQ\",\"required\":true,\"sort\":3,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"Content\",\"columnComment\":\"HTML内容\",\"columnId\":4,\"columnName\":\"content\",\"columnType\":\"text\",\"dictType\":\"\",\"edit\":true,\"htmlType\":\"editor\",\"increment\":false,\"insert\":true,\"isEdit\":\"1\",\"isIncrement\":\"0\",\"isInsert\":\"1\",\"isList\":\"1\",\"isPk\":\"0\",\"isQuery\":\"1\",\"isRequired\":\"1\",\"javaField\":\"content\",\"javaType\":\"String\",\"list\":true,\"params\":{},\"pk\":false,\"query\":true,\"queryType\":\"EQ\",\"required\":true,\"sort\":4,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"PageType\",\"columnComment\":\"页面类型:法律规定 law、典型案例 case、表单下载from\",\"columnId\":5,\"columnName\":\"page_type\",\"columnTyp', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 19:06:45', 105); +INSERT INTO `sys_oper_log` VALUES (114, '代码生成', 8, 'com.boyue.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '研发部门', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"html_pages\"}', NULL, 0, NULL, '2025-05-28 19:06:51', 29); +INSERT INTO `sys_oper_log` VALUES (115, '菜单管理', 1, 'com.boyue.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createBy\":\"admin\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuName\":\"司法局\",\"menuType\":\"M\",\"orderNum\":4,\"params\":{},\"parentId\":0,\"path\":\"hasfj\",\"status\":\"0\",\"visible\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 19:08:03', 28); +INSERT INTO `sys_oper_log` VALUES (116, '代码生成', 2, 'com.boyue.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '研发部门', '/tool/gen', '127.0.0.1', '内网IP', '{\"allGenTableColumns\":[{\"capJavaField\":\"Id\",\"columnComment\":\"序号\",\"columnId\":1,\"columnName\":\"id\",\"columnType\":\"int(11)\",\"dictType\":\"\",\"edit\":false,\"htmlType\":\"input\",\"increment\":false,\"insert\":false,\"isIncrement\":\"0\",\"isInsert\":\"0\",\"isList\":\"1\",\"isPk\":\"1\",\"isRequired\":\"0\",\"javaField\":\"id\",\"javaType\":\"Long\",\"list\":true,\"params\":{},\"pk\":true,\"query\":false,\"queryType\":\"EQ\",\"required\":false,\"sort\":1,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"FormatId\",\"columnComment\":\"访问id\",\"columnId\":2,\"columnName\":\"format_id\",\"columnType\":\"varchar(6)\",\"dictType\":\"\",\"edit\":true,\"htmlType\":\"input\",\"increment\":false,\"insert\":true,\"isEdit\":\"1\",\"isIncrement\":\"0\",\"isInsert\":\"1\",\"isList\":\"1\",\"isPk\":\"0\",\"isQuery\":\"1\",\"isRequired\":\"1\",\"javaField\":\"formatId\",\"javaType\":\"String\",\"list\":true,\"params\":{},\"pk\":false,\"query\":true,\"queryType\":\"EQ\",\"required\":true,\"sort\":2,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"Title\",\"columnComment\":\"页面标题\",\"columnId\":3,\"columnName\":\"title\",\"columnType\":\"varchar(200)\",\"dictType\":\"\",\"edit\":true,\"htmlType\":\"input\",\"increment\":false,\"insert\":true,\"isEdit\":\"1\",\"isIncrement\":\"0\",\"isInsert\":\"1\",\"isList\":\"1\",\"isPk\":\"0\",\"isQuery\":\"1\",\"isRequired\":\"1\",\"javaField\":\"title\",\"javaType\":\"String\",\"list\":true,\"params\":{},\"pk\":false,\"query\":true,\"queryType\":\"EQ\",\"required\":true,\"sort\":3,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"Content\",\"columnComment\":\"HTML内容\",\"columnId\":4,\"columnName\":\"content\",\"columnType\":\"text\",\"dictType\":\"\",\"edit\":true,\"htmlType\":\"editor\",\"increment\":false,\"insert\":true,\"isEdit\":\"1\",\"isIncrement\":\"0\",\"isInsert\":\"1\",\"isList\":\"1\",\"isPk\":\"0\",\"isQuery\":\"1\",\"isRequired\":\"1\",\"javaField\":\"content\",\"javaType\":\"String\",\"list\":true,\"params\":{},\"pk\":false,\"query\":true,\"queryType\":\"EQ\",\"required\":true,\"sort\":4,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"PageType\",\"columnComment\":\"页面类型:法律规定 law、典型案例 case、表单下载from\",\"columnId\":5,\"columnName\":\"page_type\",\"columnTyp', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 19:09:02', 55); +INSERT INTO `sys_oper_log` VALUES (117, '代码生成', 8, 'com.boyue.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '研发部门', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"html_pages\"}', NULL, 0, NULL, '2025-05-28 19:09:04', 24); +INSERT INTO `sys_oper_log` VALUES (118, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"content\":\"
表单下载内容...
\",\"createTime\":\"2025-05-28 18:55:57\",\"formatId\":\"000001\",\"id\":7,\"pageType\":\"from\",\"pageUrl\":\"http://localhost/table.html?Id=000001\",\"params\":{},\"sortOrder\":30,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-28 20:23:58\",\"viewCount\":0}', NULL, 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Data truncated for column \'page_type\' at row 1\r\n### The error may exist in file [E:\\WORK\\boyue-kfcode\\boyue-java\\boyue-models\\boyue-hasfj\\target\\classes\\mapper\\hasfj\\HtmlPagesMapper.xml]\r\n### The error may involve com.boyue.hasfj.mapper.HtmlPagesMapper.updateHtmlPages-Inline\r\n### The error occurred while setting parameters\r\n### SQL: update html_pages SET format_id = ?, title = ?, content = ?, page_type = ?, page_url = ?, create_time = ?, update_time = ?, status = ?, sort_order = ?, view_count = ? where id = ?\r\n### Cause: java.sql.SQLException: Data truncated for column \'page_type\' at row 1\n; Data truncated for column \'page_type\' at row 1', '2025-05-28 20:23:58', 144); +INSERT INTO `sys_oper_log` VALUES (119, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"content\":\"
劳动法第四十条内容及解读...
\",\"createTime\":\"2025-05-28 18:55:57\",\"formatId\":\"000001\",\"id\":1,\"pageType\":\"law\",\"pageUrl\":\"http://localhost/show.html?Id=000001\",\"params\":{},\"sortOrder\":10,\"status\":1,\"title\":\"劳动法第四十条解读\",\"updateTime\":\"2025-05-28 20:53:47\",\"viewCount\":26}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 20:53:47', 12); +INSERT INTO `sys_oper_log` VALUES (120, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"content\":\"
表单下载内容...
\",\"createTime\":\"2025-05-28 18:55:57\",\"formatId\":\"000002\",\"id\":8,\"pageType\":\"from\",\"pageUrl\":\"http://localhost/table.html?Id=000002\",\"params\":{},\"sortOrder\":31,\"status\":1,\"title\":\"劳动合同模板\",\"updateTime\":\"2025-05-28 20:54:06\",\"viewCount\":0}', NULL, 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Data truncated for column \'page_type\' at row 1\r\n### The error may exist in file [E:\\WORK\\boyue-kfcode\\boyue-java\\boyue-models\\boyue-hasfj\\target\\classes\\mapper\\hasfj\\HtmlPagesMapper.xml]\r\n### The error may involve com.boyue.hasfj.mapper.HtmlPagesMapper.updateHtmlPages-Inline\r\n### The error occurred while setting parameters\r\n### SQL: update html_pages SET format_id = ?, title = ?, content = ?, page_type = ?, page_url = ?, create_time = ?, update_time = ?, status = ?, sort_order = ?, view_count = ? where id = ?\r\n### Cause: java.sql.SQLException: Data truncated for column \'page_type\' at row 1\n; Data truncated for column \'page_type\' at row 1', '2025-05-28 20:54:06', 5); +INSERT INTO `sys_oper_log` VALUES (121, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2025-05-28 19:08:03\",\"icon\":\"#\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2087,\"menuName\":\"司法局百问百答\",\"menuType\":\"M\",\"orderNum\":4,\"params\":{},\"parentId\":0,\"path\":\"hasfj\",\"perms\":\"\",\"routeName\":\"\",\"status\":\"0\",\"updateBy\":\"admin\",\"visible\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:19:06', 26); +INSERT INTO `sys_oper_log` VALUES (122, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2025-05-28 19:08:03\",\"icon\":\"example\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2087,\"menuName\":\"司法局百问百答\",\"menuType\":\"M\",\"orderNum\":4,\"params\":{},\"parentId\":0,\"path\":\"hasfj\",\"perms\":\"\",\"routeName\":\"\",\"status\":\"0\",\"updateBy\":\"admin\",\"visible\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:19:27', 13); +INSERT INTO `sys_oper_log` VALUES (123, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"component\":\"hasfj/hasfjpages/index\",\"createTime\":\"2025-05-28 19:09:34\",\"icon\":\"#\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2088,\"menuName\":\"司法局百问百答内容配置\",\"menuType\":\"C\",\"orderNum\":1,\"params\":{},\"parentId\":2087,\"path\":\"hasfjpages\",\"perms\":\"hasfj:hasfjpages:list\",\"routeName\":\"\",\"status\":\"0\",\"updateBy\":\"admin\",\"visible\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:21:31', 100); +INSERT INTO `sys_oper_log` VALUES (124, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"component\":\"hasfj/hasfjpages/index\",\"createTime\":\"2025-05-28 19:09:34\",\"icon\":\"#\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2088,\"menuName\":\"内容配置\",\"menuType\":\"C\",\"orderNum\":1,\"params\":{},\"parentId\":2087,\"path\":\"hasfjpages\",\"perms\":\"hasfj:hasfjpages:list\",\"routeName\":\"\",\"status\":\"0\",\"updateBy\":\"admin\",\"visible\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:22:07', 26); +INSERT INTO `sys_oper_log` VALUES (125, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"component\":\"hasfj/hasfjpages/index\",\"createTime\":\"2025-05-28 19:09:34\",\"icon\":\"edit\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2088,\"menuName\":\"内容配置\",\"menuType\":\"C\",\"orderNum\":1,\"params\":{},\"parentId\":2087,\"path\":\"hasfjpages\",\"perms\":\"hasfj:hasfjpages:list\",\"routeName\":\"\",\"status\":\"0\",\"updateBy\":\"admin\",\"visible\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:22:15', 10); +INSERT INTO `sys_oper_log` VALUES (126, '司法局法律规定、典型案例、单下载', 1, 'com.boyue.hasfj.controller.HtmlPagesController.add()', 'POST', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"content\":\"

000004

\",\"createTime\":\"2025-05-28 21:31:01\",\"formatId\":\"000004\",\"pageType\":\"law\",\"pageUrl\":\"000004\",\"params\":{},\"sortOrder\":10,\"status\":1,\"title\":\"000004\",\"viewCount\":0}', NULL, 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'update_time\' doesn\'t have a default value\r\n### The error may exist in file [E:\\WORK\\boyue-kfcode\\boyue-java\\boyue-models\\boyue-hasfj\\target\\classes\\mapper\\hasfj\\HtmlPagesMapper.xml]\r\n### The error may involve com.boyue.hasfj.mapper.HtmlPagesMapper.insertHtmlPages-Inline\r\n### The error occurred while setting parameters\r\n### SQL: insert into html_pages ( format_id, title, content, page_type, page_url, create_time, status, sort_order, view_count ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'update_time\' doesn\'t have a default value\n; Field \'update_time\' doesn\'t have a default value', '2025-05-28 21:31:01', 4); +INSERT INTO `sys_oper_log` VALUES (127, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"1\",\"content\":\"
劳动法第四十条内容及解读...
\",\"createTime\":\"2025-05-28 18:55:57\",\"formatId\":\"000001\",\"id\":1,\"pageType\":\"law\",\"pageUrl\":\"http://localhost/show.html?Id=000001\",\"params\":{},\"sortOrder\":10,\"status\":1,\"title\":\"劳动法第四十条解读\",\"updateTime\":\"2025-05-28 21:32:08\",\"viewCount\":35}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:32:08', 7); +INSERT INTO `sys_oper_log` VALUES (128, '菜单管理', 3, 'com.boyue.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/menu/2098', '127.0.0.1', '内网IP', '2098', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:48:55', 128); +INSERT INTO `sys_oper_log` VALUES (129, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 21:43:55\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-28 21:49:48\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:49:48', 122); +INSERT INTO `sys_oper_log` VALUES (130, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"案例分析组\",\"content\":\"

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

\",\"createTime\":\"2025-05-28 21:43:55\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"某公司劳资纠纷典型案例\",\"updateTime\":\"2025-05-28 21:50:00\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:50:00', 52); +INSERT INTO `sys_oper_log` VALUES (131, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 21:43:55\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":4,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-28 21:50:07\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:50:07', 18); +INSERT INTO `sys_oper_log` VALUES (132, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"法律法规编辑部\",\"content\":\"

合同法关于订立合同的规定

合同是平等主体的自然人、法人、其他组织之间设立、变更、终止民事权利义务关系的协议。婚姻、收养、监护等有关身份关系的协议,适用其他法律的规定。

\",\"createTime\":\"2025-05-28 21:43:55\",\"description\":\"合同法对于订立合同的基本规定和解释\",\"formatId\":\"000002\",\"id\":2,\"keywords\":\"合同法,合同订立,民事权利\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000002\",\"params\":{},\"sortOrder\":2,\"status\":1,\"title\":\"合同法关于订立合同的规定\",\"updateTime\":\"2025-05-28 21:50:19\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:50:19', 84); +INSERT INTO `sys_oper_log` VALUES (133, '司法局法律规定、典型案例、单下载', 5, 'com.boyue.hasfj.controller.HtmlPagesController.export()', 'POST', 1, 'admin', '研发部门', '/hasfj/hasfjpages/export', '127.0.0.1', '内网IP', '{\"pageSize\":\"10\",\"pageNum\":\"1\"}', NULL, 0, NULL, '2025-05-28 22:14:32', 617); +INSERT INTO `sys_oper_log` VALUES (134, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-28 22:19:39\",\"viewCount\":3}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 22:19:39', 82); +INSERT INTO `sys_oper_log` VALUES (135, '角色管理', 1, 'com.boyue.web.controller.system.SysRoleController.add()', 'POST', 1, 'admin', '研发部门', '/system/role', '127.0.0.1', '内网IP', '{\"admin\":false,\"createBy\":\"admin\",\"deptCheckStrictly\":true,\"deptIds\":[],\"flag\":false,\"menuCheckStrictly\":true,\"menuIds\":[1,100,1000,1001,1002,1003,1004,1005,1006,2097,2099,2100,2101,2102,2103,2104],\"params\":{},\"roleId\":100,\"roleKey\":\"sfj\",\"roleName\":\"司法局\",\"roleSort\":3,\"status\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:41:41', 74); +INSERT INTO `sys_oper_log` VALUES (136, '用户管理', 3, 'com.boyue.web.controller.system.SysUserController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/user/2', '127.0.0.1', '内网IP', '[2]', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:41:50', 49); +INSERT INTO `sys_oper_log` VALUES (137, '部门管理', 2, 'com.boyue.web.controller.system.SysDeptController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/dept', '127.0.0.1', '内网IP', '{\"ancestors\":\"0\",\"children\":[],\"deptId\":100,\"deptName\":\"博越科技\",\"email\":\"boyue@qq.com\",\"leader\":\"博越\",\"orderNum\":0,\"params\":{},\"parentId\":0,\"phone\":\"15888888888\",\"status\":\"0\",\"updateBy\":\"admin\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:42:28', 120); +INSERT INTO `sys_oper_log` VALUES (138, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/102', '127.0.0.1', '内网IP', '102', '{\"msg\":\"存在下级部门,不允许删除\",\"code\":601}', 0, NULL, '2025-05-29 08:42:32', 4); +INSERT INTO `sys_oper_log` VALUES (139, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/109', '127.0.0.1', '内网IP', '109', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:42:34', 25); +INSERT INTO `sys_oper_log` VALUES (140, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/108', '127.0.0.1', '内网IP', '108', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:42:36', 91); +INSERT INTO `sys_oper_log` VALUES (141, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/102', '127.0.0.1', '内网IP', '102', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:42:38', 22); +INSERT INTO `sys_oper_log` VALUES (142, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/107', '127.0.0.1', '内网IP', '107', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:42:43', 29); +INSERT INTO `sys_oper_log` VALUES (143, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/106', '127.0.0.1', '内网IP', '106', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:42:44', 30); +INSERT INTO `sys_oper_log` VALUES (144, '部门管理', 2, 'com.boyue.web.controller.system.SysDeptController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/dept', '127.0.0.1', '内网IP', '{\"ancestors\":\"0,100\",\"children\":[],\"deptId\":101,\"deptName\":\"淮安市\",\"email\":\"boyue@qq.com\",\"leader\":\"博越\",\"orderNum\":1,\"params\":{},\"parentId\":100,\"parentName\":\"博越科技\",\"phone\":\"15888888888\",\"status\":\"0\",\"updateBy\":\"admin\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:42:59', 76); +INSERT INTO `sys_oper_log` VALUES (145, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/105', '127.0.0.1', '内网IP', '105', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:43:02', 16); +INSERT INTO `sys_oper_log` VALUES (146, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/104', '127.0.0.1', '内网IP', '104', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:43:04', 20); +INSERT INTO `sys_oper_log` VALUES (147, '部门管理', 2, 'com.boyue.web.controller.system.SysDeptController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/dept', '127.0.0.1', '内网IP', '{\"ancestors\":\"0,100,101\",\"children\":[],\"deptId\":103,\"deptName\":\"司法局部门\",\"email\":\"sfj@qq.com\",\"leader\":\"司法局\",\"orderNum\":1,\"params\":{},\"parentId\":101,\"parentName\":\"淮安市\",\"phone\":\"15888888888\",\"status\":\"0\",\"updateBy\":\"admin\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:43:41', 130); +INSERT INTO `sys_oper_log` VALUES (148, '部门管理', 2, 'com.boyue.web.controller.system.SysDeptController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/dept', '127.0.0.1', '内网IP', '{\"ancestors\":\"0,100,101\",\"children\":[],\"deptId\":103,\"deptName\":\"司法局部门\",\"email\":\"sfj@qq.com\",\"leader\":\"司法局\",\"orderNum\":2,\"params\":{},\"parentId\":101,\"parentName\":\"淮安市\",\"phone\":\"15888888888\",\"status\":\"0\",\"updateBy\":\"admin\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:43:46', 29); +INSERT INTO `sys_oper_log` VALUES (149, '部门管理', 2, 'com.boyue.web.controller.system.SysDeptController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/dept', '127.0.0.1', '内网IP', '{\"ancestors\":\"0,100,101\",\"children\":[],\"deptId\":103,\"deptName\":\"管理\",\"email\":\"sfj@qq.com\",\"leader\":\"管理\",\"orderNum\":2,\"params\":{},\"parentId\":101,\"parentName\":\"淮安市\",\"phone\":\"15888888888\",\"status\":\"0\",\"updateBy\":\"admin\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:44:34', 66); +INSERT INTO `sys_oper_log` VALUES (150, '部门管理', 1, 'com.boyue.web.controller.system.SysDeptController.add()', 'POST', 1, 'admin', '研发部门', '/system/dept', '127.0.0.1', '内网IP', '{\"ancestors\":\"0,100,101\",\"children\":[],\"createBy\":\"admin\",\"deptName\":\"司法局\",\"orderNum\":3,\"params\":{},\"parentId\":101,\"status\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:44:51', 109); +INSERT INTO `sys_oper_log` VALUES (151, '用户管理', 1, 'com.boyue.web.controller.system.SysUserController.add()', 'POST', 1, 'admin', '研发部门', '/system/user', '127.0.0.1', '内网IP', '{\"admin\":false,\"createBy\":\"admin\",\"deptId\":103,\"nickName\":\"淮安市司法局\",\"params\":{},\"postIds\":[],\"roleIds\":[100],\"status\":\"0\",\"userId\":100,\"userName\":\"hasfj\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:45:27', 97); +INSERT INTO `sys_oper_log` VALUES (152, '用户管理', 2, 'com.boyue.web.controller.system.SysUserController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/user', '127.0.0.1', '内网IP', '{\"admin\":false,\"avatar\":\"\",\"createBy\":\"admin\",\"createTime\":\"2025-05-29 08:45:27\",\"delFlag\":\"0\",\"dept\":{\"ancestors\":\"0,100,101\",\"children\":[],\"deptId\":103,\"deptName\":\"管理\",\"leader\":\"管理\",\"orderNum\":2,\"params\":{},\"parentId\":101,\"status\":\"0\"},\"deptId\":200,\"email\":\"\",\"loginIp\":\"\",\"nickName\":\"淮安市司法局\",\"params\":{},\"phonenumber\":\"\",\"postIds\":[],\"roleIds\":[100],\"roles\":[{\"admin\":false,\"dataScope\":\"1\",\"deptCheckStrictly\":false,\"flag\":false,\"menuCheckStrictly\":false,\"params\":{},\"roleId\":100,\"roleKey\":\"sfj\",\"roleName\":\"司法局\",\"roleSort\":3,\"status\":\"0\"}],\"sex\":\"0\",\"status\":\"0\",\"updateBy\":\"admin\",\"userId\":100,\"userName\":\"hasfj\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:45:53', 101); +INSERT INTO `sys_oper_log` VALUES (153, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090531_b976.png\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:05:34\",\"viewCount\":6}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:05:34', 98); +INSERT INTO `sys_oper_log` VALUES (154, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090601_37f6.xls\",\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-29 09:06:03\",\"viewCount\":2}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:06:03', 50); +INSERT INTO `sys_oper_log` VALUES (155, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090531_b976.png\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:06:36\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:06:36', 33); +INSERT INTO `sys_oper_log` VALUES (156, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090531_b976.png\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:06:55\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:06:56', 114); +INSERT INTO `sys_oper_log` VALUES (157, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090531_b976.png\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:09:59\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:09:59', 118); +INSERT INTO `sys_oper_log` VALUES (158, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090531_b976.png\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:10:41\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:10:41', 130); +INSERT INTO `sys_oper_log` VALUES (159, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:17:00\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:17:00', 144); +INSERT INTO `sys_oper_log` VALUES (160, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[{\\\"name\\\":\\\"hasfjpages_1748441672046.xlsx\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529091727_6301.xlsx\\\"},{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\\\"}]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:20:57\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:20:58', 187); +INSERT INTO `sys_oper_log` VALUES (161, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090531_b976.png\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[{\\\"name\\\":\\\"hasfjpages_1748441672046.xlsx\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529091727_6301.xlsx\\\"}]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:21:13\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:21:13', 51); +INSERT INTO `sys_oper_log` VALUES (162, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[{\\\"name\\\":\\\"hasfjpages_1748441672046.xlsx\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529091727_6301.xlsx\\\"}]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:21:22\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:21:22', 44); +INSERT INTO `sys_oper_log` VALUES (163, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090531_b976.png\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[{\\\"name\\\":\\\"hasfjpages_1748441672046.xlsx\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529091727_6301.xlsx\\\"},{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\\\"}]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:23:39\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:23:39', 122); +INSERT INTO `sys_oper_log` VALUES (164, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:24:17\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:24:17', 91); +INSERT INTO `sys_oper_log` VALUES (165, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"hasfjpages_1748441672046.xlsx\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529091727_6301.xlsx\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-29 09:28:48\",\"viewCount\":4}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:28:48', 31); +INSERT INTO `sys_oper_log` VALUES (166, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"hasfjpages_1748441672046.xlsx\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529091727_6301.xlsx\\\"},{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-29 09:29:02\",\"viewCount\":5}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:29:02', 95); +INSERT INTO `sys_oper_log` VALUES (167, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-29 09:29:19\",\"viewCount\":6}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:29:19', 23); +INSERT INTO `sys_oper_log` VALUES (168, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"法律法规编辑部\",\"content\":\"

测试

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:38:39\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:38:39', 64); +INSERT INTO `sys_oper_log` VALUES (169, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-29 11:30:45\",\"viewCount\":9}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 11:30:45', 23); +INSERT INTO `sys_oper_log` VALUES (170, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《公司法》《个人独资企业法》《合伙企业法》

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 07:02:45\",\"viewCount\":215}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:02:45', 104); +INSERT INTO `sys_oper_log` VALUES (171, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

李某与王某成立“普通合伙企业”经营餐饮,后因亏损负债100万元,法院判令李某、王某承担无限连带责任。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000001\",\"id\":2,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000001\",\"params\":{},\"sortOrder\":2,\"status\":1,\"title\":\"某公司劳资纠纷典型案例\",\"updateTime\":\"2025-05-29 07:03:38\",\"viewCount\":4}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:03:38', 115); +INSERT INTO `sys_oper_log` VALUES (172, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\\\"},{\\\"name\\\":\\\"淮安市“七五”普法调查问卷.doc\\\",\\\"url\\\":\\\"http://hj.haxy.com.cn/profile/files/master/2025/05/29/20250529070442_e2a0.doc\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-29 07:04:51\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:04:51', 60); +INSERT INTO `sys_oper_log` VALUES (173, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《公司法》《个人独资企业法》《合伙企业法》

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-29 07:07:55\",\"viewCount\":215}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:07:55', 82); +INSERT INTO `sys_oper_log` VALUES (174, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

李某与王某成立“普通合伙企业”经营餐饮,后因亏损负债100万元,法院判令李某、王某承担无限连带责任。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000001\",\"id\":2,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000001\",\"params\":{},\"sortOrder\":2,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-29 07:08:06\",\"viewCount\":4}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:08:06', 46); +INSERT INTO `sys_oper_log` VALUES (175, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\\\"},{\\\"name\\\":\\\"淮安市“七五”普法调查问卷.doc\\\",\\\"url\\\":\\\"http://hj.haxy.com.cn/profile/files/master/2025/05/29/20250529070442_e2a0.doc\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-29 07:08:16\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:08:16', 38); +INSERT INTO `sys_oper_log` VALUES (176, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000002\",\"id\":4,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000002\",\"params\":{},\"sortOrder\":4,\"status\":1,\"title\":\"有限责任公司和股份有限公司的区别是什么?\",\"updateTime\":\"2025-05-29 07:08:49\",\"viewCount\":17}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:08:49', 56); +INSERT INTO `sys_oper_log` VALUES (177, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000002\",\"id\":5,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000002\",\"params\":{},\"sortOrder\":5,\"status\":1,\"title\":\"有限责任公司和股份有限公司的区别是什么?\",\"updateTime\":\"2025-05-29 07:08:59\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:08:59', 52); +INSERT INTO `sys_oper_log` VALUES (178, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000002\",\"id\":6,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000002\",\"params\":{},\"sortOrder\":6,\"status\":1,\"title\":\"有限责任公司和股份有限公司的区别是什么?\",\"updateTime\":\"2025-05-29 07:09:10\",\"viewCount\":1}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:09:11', 41); +INSERT INTO `sys_oper_log` VALUES (179, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000003\",\"id\":7,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000003\",\"params\":{},\"sortOrder\":7,\"status\":1,\"title\":\"如何确定企业名称?\",\"updateTime\":\"2025-05-29 07:09:30\",\"viewCount\":15}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:09:30', 36); +INSERT INTO `sys_oper_log` VALUES (180, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000003\",\"id\":8,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000003\",\"params\":{},\"sortOrder\":8,\"status\":1,\"title\":\"如何确定企业名称?\",\"updateTime\":\"2025-05-29 07:09:40\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:09:40', 27); +INSERT INTO `sys_oper_log` VALUES (181, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000003\",\"id\":9,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000003\",\"params\":{},\"sortOrder\":9,\"status\":1,\"title\":\"如何确定企业名称?\",\"updateTime\":\"2025-05-29 07:09:50\",\"viewCount\":2}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:09:50', 17); +INSERT INTO `sys_oper_log` VALUES (182, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《证券法》第七十八条,发行人及法律、行政法规和国务院证券监督管理机构规定的其他信息披露义务人,应当及时依法履行信息披露义务。信息披露义务人披露的信息,应当真实、准确、完整,简明清晰,通俗易懂,不得有虚假记载、误导性陈述或者重大遗漏。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000002\",\"id\":4,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000002\",\"params\":{},\"sortOrder\":4,\"status\":1,\"title\":\"有限责任公司和股份有限公司的区别是什么?\",\"updateTime\":\"2025-05-29 07:11:12\",\"viewCount\":17}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:11:12', 92); +INSERT INTO `sys_oper_log` VALUES (183, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

某科技创业团队初期仅3名股东,误以为股份公司“更规范易融资”,直接注册为股份公司。因股份公司需设股东大会、董事会、监事会,团队人数不足,决策效率低下;同时需定期披露年报、重大事项,合规成本高。天使投资机构因其结构复杂、股权转让受限(需股东大会批准)放弃投资,最终公司因资金链断裂解散清算。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000002\",\"id\":5,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000002\",\"params\":{},\"sortOrder\":5,\"status\":1,\"title\":\"有限责任公司和股份有限公司的区别是什么?\",\"updateTime\":\"2025-05-29 07:11:33\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:11:33', 65); +INSERT INTO `sys_oper_log` VALUES (184, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《企业名称登记管理规定》《企业名称登记管理规定实施办法》。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000003\",\"id\":7,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000003\",\"params\":{},\"sortOrder\":7,\"status\":1,\"title\":\"如何确定企业名称?\",\"updateTime\":\"2025-05-29 07:11:54\",\"viewCount\":15}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:11:54', 41); +INSERT INTO `sys_oper_log` VALUES (185, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

甲公司注册名称为“上海特斯拉新能源科技有限公司”,未经特斯拉公司授权。法院认定其名称攀附知名品牌商誉,构成不正当竞争,判令更名并赔偿20万元。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000003\",\"id\":8,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000003\",\"params\":{},\"sortOrder\":8,\"status\":1,\"title\":\"如何确定企业名称?\",\"updateTime\":\"2025-05-29 07:12:11\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:12:11', 44); +INSERT INTO `sys_oper_log` VALUES (186, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《公司法》第十条,公司的法定代表人按照公司章程的规定,由代表公司执行公司事务的董事或者经理担任。担任法定代表人的董事或者经理辞任的,视为同时辞去法定代表人。法定代表人辞任的,公司应当在法定代表人辞任之日起三十日内确定新的法定代表人。第十一条:法定代表人以公司名义从事的民事活动,其法律后果由公司承受。公司章程或者股东会对法定代表人职权的限制,不得对抗善意相对人。法定代表人因执行职务造成他人损害的,由公司承担民事责任。公司承担民事责任后,依照法律或者公司章程的规定,可以向有过错的法定代表人追偿。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000004\",\"id\":10,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000004\",\"params\":{},\"sortOrder\":10,\"status\":1,\"title\":\"法定代表人的要求有哪些?\",\"updateTime\":\"2025-05-29 07:12:43\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:12:43', 51); +INSERT INTO `sys_oper_log` VALUES (187, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

某公司法定代表人李某因个人债务被列为失信被执行人,法院限制其高消费。公司向银行申请贷款时,因李某信用瑕疵遭拒,资金链断裂导致停产。市场监管部门责令更换法定代表人,但因股东争议拖延,最终公司破产清算。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000004\",\"id\":11,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000004\",\"params\":{},\"sortOrder\":11,\"status\":1,\"title\":\"法定代表人的要求有哪些?\",\"updateTime\":\"2025-05-29 07:13:16\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:13:16', 75); +INSERT INTO `sys_oper_log` VALUES (188, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000004\",\"id\":12,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000004\",\"params\":{},\"sortOrder\":12,\"status\":1,\"title\":\"法定代表人的要求有哪些?\",\"updateTime\":\"2025-05-29 07:13:34\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:13:35', 75); +INSERT INTO `sys_oper_log` VALUES (189, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《公司法》第一百七十八条,有下列情形之一的,不得担任公司的董事、监事、高级管理人员:(一)无民事行为能力或者限制民事行为能力;(二)因贪污、贿赂、侵占财产、挪用财产或者破坏社会主义市场经济秩序,被判处刑罚,或者因犯罪被剥夺政治权利,执行期满未逾五年,被宣告缓刑的,自缓刑考验期满之日起未逾二年;(三)担任破产清算的公司、企业的董事或者厂长、经理,对该公司、企业的破产负有个人责任的,自该公司、企业破产清算完结之日起未逾三年;(四)担任因违法被吊销营业执照、责令关闭的公司、企业的法定代表人,并负有个人责任的,自该公司、企业被吊销营业执照、责令关闭之日起未逾三年;(五)个人因所负数额较大债务到期未清偿被人民法院列为失信被执行人。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000005\",\"id\":13,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000005\",\"params\":{},\"sortOrder\":13,\"status\":1,\"title\":\"董事、监事、高级管理人员的资格限制有哪些?\",\"updateTime\":\"2025-05-29 07:14:05\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:14:05', 56); +INSERT INTO `sys_oper_log` VALUES (190, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

某公司股东李某(公务员)通过亲属代持股权,后因公司债务纠纷被债权人揭发。法院认定代持协议无效,李某需退还全部股权收益,公司被处罚款10万元。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000005\",\"id\":14,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000005\",\"params\":{},\"sortOrder\":14,\"status\":1,\"title\":\"董事、监事、高级管理人员的资格限制有哪些?\",\"updateTime\":\"2025-05-29 07:14:42\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:14:42', 51); +INSERT INTO `sys_oper_log` VALUES (191, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000005\",\"id\":15,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000005\",\"params\":{},\"sortOrder\":15,\"status\":1,\"title\":\"董事、监事、高级管理人员的资格限制有哪些?\",\"updateTime\":\"2025-05-29 07:14:52\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:14:52', 39); +INSERT INTO `sys_oper_log` VALUES (192, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

最高人民法院关于适用《中华人民共和国公司法》若干问题的规定(三)第二十四条,有限责任公司的实际出资人与名义出资人订立合同,约定由实际出资人出资并享有投资权益,以名义出资人为名义股东,实际出资人与名义股东对该合同效力发生争议的,如无法律规定的无效情形,人民法院应当认定该合同有效。前款规定的实际出资人与名义股东因投资权益的归属发生争议,实际出资人以其实际履行了出资义务为由向名义股东主张权利的,人民法院应予支持。名义股东以公司股东名册记载、公司登记机关登记为由否认实际出资人权利的,人民法院不予支持。实际出资人未经公司其他股东半数以上同意,请求公司变更股东、签发出资证明书、记载于股东名册、记载于公司章程并办理公司登记机关登记的,人民法院不予支持。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000006\",\"id\":16,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000006\",\"params\":{},\"sortOrder\":16,\"status\":1,\"title\":\"隐名股东有哪些常见法律风险?\",\"updateTime\":\"2025-05-29 07:15:42\",\"viewCount\":1}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:15:42', 48); +INSERT INTO `sys_oper_log` VALUES (193, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

隐名股东李某委托张某代持某公司10%股权,张某未经同意将股权转让给王某,王某不知情且支付合理价款。王某善意取得股权,李某仅能要求张某赔偿损失。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000006\",\"id\":17,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000006\",\"params\":{},\"sortOrder\":17,\"status\":1,\"title\":\"隐名股东有哪些常见法律风险?\",\"updateTime\":\"2025-05-29 07:16:04\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:16:04', 57); +INSERT INTO `sys_oper_log` VALUES (194, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000006\",\"id\":18,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000006\",\"params\":{},\"sortOrder\":18,\"status\":1,\"title\":\"隐名股东有哪些常见法律风险?\",\"updateTime\":\"2025-05-29 07:16:18\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:16:18', 72); +INSERT INTO `sys_oper_log` VALUES (195, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《公司法》第六十五条,股东会会议由股东按照出资比例行使表决权;但是,公司章程另有规定的除外。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000007\",\"id\":19,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000007\",\"params\":{},\"sortOrder\":19,\"status\":1,\"title\":\"如何保持创始人在公司的控制权?\",\"updateTime\":\"2025-05-29 07:16:51\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:16:51', 74); +INSERT INTO `sys_oper_log` VALUES (196, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

某公司创始人通过“AB股”架构(1股10票投票权),即使持股比例仅15%,仍掌控董事会80%席位。公司上市后,其投票权超80%,确保战略决策权。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000007\",\"id\":20,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000007\",\"params\":{},\"sortOrder\":20,\"status\":1,\"title\":\"如何保持创始人在公司的控制权?\",\"updateTime\":\"2025-05-29 07:17:15\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:17:15', 54); +INSERT INTO `sys_oper_log` VALUES (197, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000007\",\"id\":21,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000007\",\"params\":{},\"sortOrder\":21,\"status\":1,\"title\":\"如何保持创始人在公司的控制权?\",\"updateTime\":\"2025-05-29 07:17:28\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:17:28', 49); +INSERT INTO `sys_oper_log` VALUES (198, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

\\t《公司法》第二百三十一条,公司经营管理发生严重困难,继续存续会使股东利益受到重大损失,通过其他途径不能解决的,持有公司百分之十以上表决权的股东,可以请求人民法院解散公司。

\\t最高人民法院关于适用《中华人民共和国公司法》若干问题的规定(二)第一条,单独或者合计持有公司全部股东表决权百分之十以上的股东,以下列事由之一提起解散公司诉讼,并符合公司法第一百八十二条规定的,人民法院应予受理:(一)公司持续两年以上无法召开股东会或者股东大会,公司经营管理发生严重困难的;(二)股东表决时无法达到法定或者公司章程规定的比例,持续两年以上不能做出有效的股东会或者股东大会决议,公司经营管理发生严重困难的;(三)公司董事长期冲突,且无法通过股东会或者股东大会解决,公司经营管理发生严重困难的;


\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000008\",\"id\":22,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000008\",\"params\":{},\"sortOrder\":22,\"status\":1,\"title\":\"如何防止出现公司僵局?\",\"updateTime\":\"2025-05-29 07:17:59\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:17:59', 68); +INSERT INTO `sys_oper_log` VALUES (199, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

某零售企业两位股东各持50%股权,因经营理念严重冲突,股东会无法通过重大决策(如拓展新店、引入投资),公司现金流枯竭,员工离职,被法院裁定解散。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000008\",\"id\":23,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000008\",\"params\":{},\"sortOrder\":23,\"status\":1,\"title\":\"如何防止出现公司僵局?\",\"updateTime\":\"2025-05-29 07:18:27\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:18:27', 61); +INSERT INTO `sys_oper_log` VALUES (200, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000008\",\"id\":24,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000008\",\"params\":{},\"sortOrder\":24,\"status\":1,\"title\":\"如何防止出现公司僵局?\",\"updateTime\":\"2025-05-29 07:18:40\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:18:40', 48); +INSERT INTO `sys_oper_log` VALUES (201, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《公司法》第四条,有限责任公司的股东以其认缴的出资额为限对公司承担责任;股份有限公司的股东以其认购的股份为限对公司承担责任。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000009\",\"id\":25,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000009\",\"params\":{},\"sortOrder\":25,\"status\":1,\"title\":\"如何合理确定注册资本?\",\"updateTime\":\"2025-05-29 07:19:12\",\"viewCount\":1}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:19:12', 51); +INSERT INTO `sys_oper_log` VALUES (202, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

\\t某公司注册资本8000万元(认缴期30年),实际运营资金仅200万元。后因合同纠纷负债500万元,法院认定股东恶意设置超长认缴期,判令股东立即补缴。


\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000009\",\"id\":26,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000009\",\"params\":{},\"sortOrder\":26,\"status\":1,\"title\":\"如何合理确定注册资本?\",\"updateTime\":\"2025-05-29 07:19:32\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:19:32', 69); +INSERT INTO `sys_oper_log` VALUES (203, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000009\",\"id\":27,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000009\",\"params\":{},\"sortOrder\":27,\"status\":1,\"title\":\"如何合理确定注册资本?\",\"updateTime\":\"2025-05-29 07:19:44\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:19:44', 117); +INSERT INTO `sys_oper_log` VALUES (204, '司法局法律规定、典型案例、单下载-删除附件', 3, 'com.boyue.hasfj.controller.HtmlPagesController.deleteAttachment()', 'POST', 1, 'admin', '管理', '/hasfj/hasfjpages/deleteAttachment', '49.87.176.188', 'XX XX', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\"}', '{\"msg\":\"删除附件失败\",\"code\":500}', 0, NULL, '2025-05-31 12:12:52', 47); +INSERT INTO `sys_oper_log` VALUES (205, '司法局法律规定、典型案例、单下载-删除附件', 3, 'com.boyue.hasfj.controller.HtmlPagesController.deleteAttachment()', 'POST', 1, 'admin', '管理', '/hasfj/hasfjpages/deleteAttachment', '49.87.176.188', 'XX XX', '{\"attachmentUrl\":\"http://hj.haxy.com.cn/profile/files/master/2025/05/29/20250529070442_e2a0.doc\"}', '{\"msg\":\"删除附件失败\",\"code\":500}', 0, NULL, '2025-05-31 12:12:56', 0); +INSERT INTO `sys_oper_log` VALUES (206, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '49.87.176.188', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\\\"},{\\\"name\\\":\\\"淮安市“七五”普法调查问卷.doc\\\",\\\"url\\\":\\\"http://hj.haxy.com.cn/profile/files/master/2025/05/29/20250529070442_e2a0.doc\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 04:12:58\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 12:12:58', 41); +INSERT INTO `sys_oper_log` VALUES (207, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '49.87.176.188', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"01应某某不服市城管局行政处罚行政复议决定书.docx\\\",\\\"url\\\":\\\"http://hj.haxy.com.cn/profile/files/master/2025/05/31/20250531041536_0786.docx\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 04:15:40\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 12:15:40', 74); +INSERT INTO `sys_oper_log` VALUES (208, '司法局法律规定、典型案例、单下载-删除附件', 3, 'com.boyue.hasfj.controller.HtmlPagesController.deleteAttachment()', 'POST', 1, 'admin', '管理', '/hasfj/hasfjpages/deleteAttachment', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://hj.haxy.com.cn/profile/files/master/2025/05/31/20250531041536_0786.docx\"}', '{\"msg\":\"删除附件失败\",\"code\":500}', 0, NULL, '2025-05-31 14:50:57', 10); +INSERT INTO `sys_oper_log` VALUES (209, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"01应某某不服市城管局行政处罚行政复议决定书.docx\\\",\\\"url\\\":\\\"http://hj.haxy.com.cn/profile/files/master/2025/05/31/20250531041536_0786.docx\\\"},{\\\"name\\\":\\\"2025-05-28会议室预约记录 (2).xls\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531145236_2193.xls\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 14:52:38\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 14:52:39', 69); +INSERT INTO `sys_oper_log` VALUES (210, '司法局法律规定、典型案例、单下载-删除附件', 3, 'com.boyue.hasfj.controller.HtmlPagesController.deleteAttachment()', 'POST', 1, 'admin', '管理', '/hasfj/hasfjpages/deleteAttachment', '180.125.41.129', 'XX XX', '{\"attachmentUrl\":\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531145236_2193.xls\"}', '{\"msg\":\"删除附件失败\",\"code\":500}', 0, NULL, '2025-05-31 15:04:35', 19); +INSERT INTO `sys_oper_log` VALUES (211, '司法局法律规定、典型案例、单下载-删除附件', 3, 'com.boyue.hasfj.controller.HtmlPagesController.deleteAttachment()', 'POST', 1, 'admin', '管理', '/hasfj/hasfjpages/deleteAttachment', '180.125.41.129', 'XX XX', '{\"attachmentUrl\":\"http://hj.haxy.com.cn/profile/files/master/2025/05/31/20250531041536_0786.docx\"}', '{\"msg\":\"删除附件失败\",\"code\":500}', 0, NULL, '2025-05-31 15:04:37', 0); +INSERT INTO `sys_oper_log` VALUES (212, '司法局法律规定、典型案例、单下载-删除附件', 3, 'com.boyue.hasfj.controller.HtmlPagesController.deleteAttachment()', 'POST', 1, 'admin', '管理', '/hasfj/hasfjpages/deleteAttachment', '218.2.75.254', 'XX XX', '{\"attachmentUrl\":\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531145236_2193.xls\"}', '{\"msg\":\"删除附件失败\",\"code\":500}', 0, NULL, '2025-05-31 15:05:18', 0); +INSERT INTO `sys_oper_log` VALUES (213, '司法局法律规定、典型案例、单下载-删除附件', 3, 'com.boyue.hasfj.controller.HtmlPagesController.deleteAttachment()', 'POST', 1, 'admin', '管理', '/hasfj/hasfjpages/deleteAttachment', '218.2.75.254', 'XX XX', '{\"attachmentUrl\":\"http://hj.haxy.com.cn/profile/files/master/2025/05/31/20250531041536_0786.docx\"}', '{\"msg\":\"删除附件失败\",\"code\":500}', 0, NULL, '2025-05-31 15:05:20', 1); +INSERT INTO `sys_oper_log` VALUES (214, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:08:12\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:08:14', 569); +INSERT INTO `sys_oper_log` VALUES (215, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025创新大赛提交.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531150820_1da0.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:08:22\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:08:22', 38); +INSERT INTO `sys_oper_log` VALUES (216, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531151028_e27c.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:10:30\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:10:31', 73); +INSERT INTO `sys_oper_log` VALUES (217, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531151028_e27c.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:13:20\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:13:21', 301); +INSERT INTO `sys_oper_log` VALUES (218, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025-05-28至2025-05-28会议室预约记录 (1).xls\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531151741_e50b.xls\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:17:43\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:17:43', 109); +INSERT INTO `sys_oper_log` VALUES (219, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531151028_e27c.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:18:59\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:19:00', 71); +INSERT INTO `sys_oper_log` VALUES (220, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025-05-28至2025-05-28会议室预约记录.xls\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531152447_76e9.xls\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:24:49\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:24:49', 104); +INSERT INTO `sys_oper_log` VALUES (221, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025-05-28至2025-05-28会议室预约记录.xls\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531152447_76e9.xls\\\"},{\\\"name\\\":\\\"2025创新大赛提交.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531150820_1da0.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:25:50\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:25:51', 81); +INSERT INTO `sys_oper_log` VALUES (222, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:32:04\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:32:05', 81); +INSERT INTO `sys_oper_log` VALUES (223, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025创新大赛提交.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531150820_1da0.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:32:16\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:32:18', 641); +INSERT INTO `sys_oper_log` VALUES (224, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 19:33:31\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 19:33:32', 151); +INSERT INTO `sys_oper_log` VALUES (225, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531151028_e27c.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 19:33:52\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 19:33:53', 104); +INSERT INTO `sys_oper_log` VALUES (226, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025创新大赛提交.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531150820_1da0.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 19:46:19\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 19:46:20', 112); +INSERT INTO `sys_oper_log` VALUES (227, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025创新大赛提交.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531150820_1da0.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 20:04:39\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 20:04:40', 83); +INSERT INTO `sys_oper_log` VALUES (228, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025创新大赛提交.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531150820_1da0.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 20:14:42\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 20:14:43', 84); +INSERT INTO `sys_oper_log` VALUES (229, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025-05-23至2025-05-23会议室预约记录.xls\\\",\\\"url\\\":\\\"/profile/2025/05/31\\\\\\\\20250531203546_d135.xls\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 20:35:48\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 20:35:49', 100); +INSERT INTO `sys_oper_log` VALUES (230, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531151028_e27c.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-06-01 11:03:48\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-06-01 11:03:49', 346); + +-- ---------------------------- +-- Table structure for sys_post +-- ---------------------------- +DROP TABLE IF EXISTS `sys_post`; +CREATE TABLE `sys_post` ( + `post_id` bigint NOT NULL AUTO_INCREMENT COMMENT '岗位ID', + `post_code` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '岗位编码', + `post_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '岗位名称', + `post_sort` int NOT NULL COMMENT '显示顺序', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '状态(0正常 1停用)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`post_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '岗位信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_post +-- ---------------------------- +INSERT INTO `sys_post` VALUES (1, 'ceo', '董事长', 1, '0', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_post` VALUES (2, 'se', '项目经理', 2, '0', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_post` VALUES (3, 'hr', '人力资源', 3, '0', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_post` VALUES (4, 'user', '普通员工', 4, '0', 'admin', '2025-05-26 17:20:06', '', NULL, ''); + +-- ---------------------------- +-- Table structure for sys_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role`; +CREATE TABLE `sys_role` ( + `role_id` bigint NOT NULL AUTO_INCREMENT COMMENT '角色ID', + `role_name` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '角色名称', + `role_key` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '角色权限字符串', + `role_sort` int NOT NULL COMMENT '显示顺序', + `data_scope` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '1' COMMENT '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)', + `menu_check_strictly` tinyint(1) NULL DEFAULT 1 COMMENT '菜单树选择项是否关联显示', + `dept_check_strictly` tinyint(1) NULL DEFAULT 1 COMMENT '部门树选择项是否关联显示', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '角色状态(0正常 1停用)', + `del_flag` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`role_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 101 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '角色信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role +-- ---------------------------- +INSERT INTO `sys_role` VALUES (1, '超级管理员', 'admin', 1, '1', 1, 1, '0', '0', 'admin', '2025-05-26 17:20:06', '', NULL, '超级管理员'); +INSERT INTO `sys_role` VALUES (2, '普通角色', 'common', 2, '2', 1, 1, '0', '0', 'admin', '2025-05-26 17:20:06', '', NULL, '普通角色'); +INSERT INTO `sys_role` VALUES (100, '司法局', 'sfj', 3, '1', 1, 1, '0', '0', 'admin', '2025-05-29 08:41:41', '', NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_role_dept +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role_dept`; +CREATE TABLE `sys_role_dept` ( + `role_id` bigint NOT NULL COMMENT '角色ID', + `dept_id` bigint NOT NULL COMMENT '部门ID', + PRIMARY KEY (`role_id`, `dept_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '角色和部门关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role_dept +-- ---------------------------- +INSERT INTO `sys_role_dept` VALUES (2, 100); +INSERT INTO `sys_role_dept` VALUES (2, 101); +INSERT INTO `sys_role_dept` VALUES (2, 105); + +-- ---------------------------- +-- Table structure for sys_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role_menu`; +CREATE TABLE `sys_role_menu` ( + `role_id` bigint NOT NULL COMMENT '角色ID', + `menu_id` bigint NOT NULL COMMENT '菜单ID', + PRIMARY KEY (`role_id`, `menu_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '角色和菜单关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role_menu +-- ---------------------------- +INSERT INTO `sys_role_menu` VALUES (2, 1); +INSERT INTO `sys_role_menu` VALUES (2, 2); +INSERT INTO `sys_role_menu` VALUES (2, 3); +INSERT INTO `sys_role_menu` VALUES (2, 4); +INSERT INTO `sys_role_menu` VALUES (2, 100); +INSERT INTO `sys_role_menu` VALUES (2, 101); +INSERT INTO `sys_role_menu` VALUES (2, 102); +INSERT INTO `sys_role_menu` VALUES (2, 103); +INSERT INTO `sys_role_menu` VALUES (2, 104); +INSERT INTO `sys_role_menu` VALUES (2, 105); +INSERT INTO `sys_role_menu` VALUES (2, 106); +INSERT INTO `sys_role_menu` VALUES (2, 107); +INSERT INTO `sys_role_menu` VALUES (2, 108); +INSERT INTO `sys_role_menu` VALUES (2, 109); +INSERT INTO `sys_role_menu` VALUES (2, 110); +INSERT INTO `sys_role_menu` VALUES (2, 111); +INSERT INTO `sys_role_menu` VALUES (2, 112); +INSERT INTO `sys_role_menu` VALUES (2, 113); +INSERT INTO `sys_role_menu` VALUES (2, 114); +INSERT INTO `sys_role_menu` VALUES (2, 115); +INSERT INTO `sys_role_menu` VALUES (2, 116); +INSERT INTO `sys_role_menu` VALUES (2, 117); +INSERT INTO `sys_role_menu` VALUES (2, 500); +INSERT INTO `sys_role_menu` VALUES (2, 501); +INSERT INTO `sys_role_menu` VALUES (2, 1000); +INSERT INTO `sys_role_menu` VALUES (2, 1001); +INSERT INTO `sys_role_menu` VALUES (2, 1002); +INSERT INTO `sys_role_menu` VALUES (2, 1003); +INSERT INTO `sys_role_menu` VALUES (2, 1004); +INSERT INTO `sys_role_menu` VALUES (2, 1005); +INSERT INTO `sys_role_menu` VALUES (2, 1006); +INSERT INTO `sys_role_menu` VALUES (2, 1007); +INSERT INTO `sys_role_menu` VALUES (2, 1008); +INSERT INTO `sys_role_menu` VALUES (2, 1009); +INSERT INTO `sys_role_menu` VALUES (2, 1010); +INSERT INTO `sys_role_menu` VALUES (2, 1011); +INSERT INTO `sys_role_menu` VALUES (2, 1012); +INSERT INTO `sys_role_menu` VALUES (2, 1013); +INSERT INTO `sys_role_menu` VALUES (2, 1014); +INSERT INTO `sys_role_menu` VALUES (2, 1015); +INSERT INTO `sys_role_menu` VALUES (2, 1016); +INSERT INTO `sys_role_menu` VALUES (2, 1017); +INSERT INTO `sys_role_menu` VALUES (2, 1018); +INSERT INTO `sys_role_menu` VALUES (2, 1019); +INSERT INTO `sys_role_menu` VALUES (2, 1020); +INSERT INTO `sys_role_menu` VALUES (2, 1021); +INSERT INTO `sys_role_menu` VALUES (2, 1022); +INSERT INTO `sys_role_menu` VALUES (2, 1023); +INSERT INTO `sys_role_menu` VALUES (2, 1024); +INSERT INTO `sys_role_menu` VALUES (2, 1025); +INSERT INTO `sys_role_menu` VALUES (2, 1026); +INSERT INTO `sys_role_menu` VALUES (2, 1027); +INSERT INTO `sys_role_menu` VALUES (2, 1028); +INSERT INTO `sys_role_menu` VALUES (2, 1029); +INSERT INTO `sys_role_menu` VALUES (2, 1030); +INSERT INTO `sys_role_menu` VALUES (2, 1031); +INSERT INTO `sys_role_menu` VALUES (2, 1032); +INSERT INTO `sys_role_menu` VALUES (2, 1033); +INSERT INTO `sys_role_menu` VALUES (2, 1034); +INSERT INTO `sys_role_menu` VALUES (2, 1035); +INSERT INTO `sys_role_menu` VALUES (2, 1036); +INSERT INTO `sys_role_menu` VALUES (2, 1037); +INSERT INTO `sys_role_menu` VALUES (2, 1038); +INSERT INTO `sys_role_menu` VALUES (2, 1039); +INSERT INTO `sys_role_menu` VALUES (2, 1040); +INSERT INTO `sys_role_menu` VALUES (2, 1041); +INSERT INTO `sys_role_menu` VALUES (2, 1042); +INSERT INTO `sys_role_menu` VALUES (2, 1043); +INSERT INTO `sys_role_menu` VALUES (2, 1044); +INSERT INTO `sys_role_menu` VALUES (2, 1045); +INSERT INTO `sys_role_menu` VALUES (2, 1046); +INSERT INTO `sys_role_menu` VALUES (2, 1047); +INSERT INTO `sys_role_menu` VALUES (2, 1048); +INSERT INTO `sys_role_menu` VALUES (2, 1049); +INSERT INTO `sys_role_menu` VALUES (2, 1050); +INSERT INTO `sys_role_menu` VALUES (2, 1051); +INSERT INTO `sys_role_menu` VALUES (2, 1052); +INSERT INTO `sys_role_menu` VALUES (2, 1053); +INSERT INTO `sys_role_menu` VALUES (2, 1054); +INSERT INTO `sys_role_menu` VALUES (2, 1055); +INSERT INTO `sys_role_menu` VALUES (2, 1056); +INSERT INTO `sys_role_menu` VALUES (2, 1057); +INSERT INTO `sys_role_menu` VALUES (2, 1058); +INSERT INTO `sys_role_menu` VALUES (2, 1059); +INSERT INTO `sys_role_menu` VALUES (2, 1060); +INSERT INTO `sys_role_menu` VALUES (100, 1); +INSERT INTO `sys_role_menu` VALUES (100, 100); +INSERT INTO `sys_role_menu` VALUES (100, 1000); +INSERT INTO `sys_role_menu` VALUES (100, 1001); +INSERT INTO `sys_role_menu` VALUES (100, 1002); +INSERT INTO `sys_role_menu` VALUES (100, 1003); +INSERT INTO `sys_role_menu` VALUES (100, 1004); +INSERT INTO `sys_role_menu` VALUES (100, 1005); +INSERT INTO `sys_role_menu` VALUES (100, 1006); +INSERT INTO `sys_role_menu` VALUES (100, 2097); +INSERT INTO `sys_role_menu` VALUES (100, 2099); +INSERT INTO `sys_role_menu` VALUES (100, 2100); +INSERT INTO `sys_role_menu` VALUES (100, 2101); +INSERT INTO `sys_role_menu` VALUES (100, 2102); +INSERT INTO `sys_role_menu` VALUES (100, 2103); +INSERT INTO `sys_role_menu` VALUES (100, 2104); + +-- ---------------------------- +-- Table structure for sys_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user`; +CREATE TABLE `sys_user` ( + `user_id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID', + `dept_id` bigint NULL DEFAULT NULL COMMENT '部门ID', + `user_name` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户账号', + `nick_name` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户昵称', + `user_type` varchar(2) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '00' COMMENT '用户类型(00系统用户)', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '用户邮箱', + `phonenumber` varchar(11) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '手机号码', + `sex` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '用户性别(0男 1女 2未知)', + `avatar` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '头像地址', + `password` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '密码', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '帐号状态(0正常 1停用)', + `del_flag` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `login_ip` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '最后登录IP', + `login_date` datetime NULL DEFAULT NULL COMMENT '最后登录时间', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`user_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 101 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user +-- ---------------------------- +INSERT INTO `sys_user` VALUES (1, 103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', 'avatar/admin/1/20250526183841-avatar.png', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '218.2.75.254', '2025-06-02 19:33:32', 'admin', '2025-05-26 17:20:06', '', '2025-06-02 19:33:32', '管理员'); +INSERT INTO `sys_user` VALUES (2, 105, 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '2', '127.0.0.1', '2025-05-26 17:20:06', 'admin', '2025-05-26 17:20:06', '', NULL, '测试员'); +INSERT INTO `sys_user` VALUES (100, 200, 'hasfj', '淮安市司法局', '00', '', '', '0', '', '$2a$10$.ZiW8u/mWmHPannD4ewWOenMlUR/BD6lYUrVJopOWfB69..5BJEx2', '0', '0', '114.238.34.181', '2025-05-29 14:57:16', 'admin', '2025-05-29 08:45:27', 'admin', '2025-05-29 14:57:15', NULL); + +-- ---------------------------- +-- Table structure for sys_user_post +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_post`; +CREATE TABLE `sys_user_post` ( + `user_id` bigint NOT NULL COMMENT '用户ID', + `post_id` bigint NOT NULL COMMENT '岗位ID', + PRIMARY KEY (`user_id`, `post_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户与岗位关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user_post +-- ---------------------------- +INSERT INTO `sys_user_post` VALUES (1, 1); + +-- ---------------------------- +-- Table structure for sys_user_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_role`; +CREATE TABLE `sys_user_role` ( + `user_id` bigint NOT NULL COMMENT '用户ID', + `role_id` bigint NOT NULL COMMENT '角色ID', + PRIMARY KEY (`user_id`, `role_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户和角色关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user_role +-- ---------------------------- +INSERT INTO `sys_user_role` VALUES (1, 1); +INSERT INTO `sys_user_role` VALUES (100, 100); + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/sql/hasfj/boyuehasfj.sql b/sql/hasfj/boyuehasfj.sql new file mode 100644 index 0000000..b86db7b --- /dev/null +++ b/sql/hasfj/boyuehasfj.sql @@ -0,0 +1,3879 @@ +/* + Navicat Premium Dump SQL + + Source Server : 222.184.49.22测试 + Source Server Type : MySQL + Source Server Version : 80405 (8.4.5) + Source Host : 222.184.49.22:3307 + Source Schema : boyuehasfj + + Target Server Type : MySQL + Target Server Version : 80405 (8.4.5) + File Encoding : 65001 + + Date: 02/06/2025 20:14:56 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for act_app_appdef +-- ---------------------------- +DROP TABLE IF EXISTS `act_app_appdef`; +CREATE TABLE `act_app_appdef` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `REV_` int NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `VERSION_` int NOT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `RESOURCE_NAME_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DESCRIPTION_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_APP_DEF_DPLY`(`DEPLOYMENT_ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_app_appdef +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_app_deployment +-- ---------------------------- +DROP TABLE IF EXISTS `act_app_deployment`; +CREATE TABLE `act_app_deployment` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DEPLOY_TIME_` datetime(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_app_deployment +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_app_deployment_resource +-- ---------------------------- +DROP TABLE IF EXISTS `act_app_deployment_resource`; +CREATE TABLE `act_app_deployment_resource` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `RESOURCE_BYTES_` longblob NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_APP_RSRC_DPL`(`DEPLOYMENT_ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_app_deployment_resource +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_cmmn_casedef +-- ---------------------------- +DROP TABLE IF EXISTS `act_cmmn_casedef`; +CREATE TABLE `act_cmmn_casedef` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `REV_` int NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `VERSION_` int NOT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `RESOURCE_NAME_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DESCRIPTION_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `HAS_GRAPHICAL_NOTATION_` tinyint NULL DEFAULT NULL, + `DGRM_RESOURCE_NAME_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `HAS_START_FORM_KEY_` tinyint NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_CASE_DEF_DPLY`(`DEPLOYMENT_ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_cmmn_casedef +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_cmmn_deployment +-- ---------------------------- +DROP TABLE IF EXISTS `act_cmmn_deployment`; +CREATE TABLE `act_cmmn_deployment` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DEPLOY_TIME_` datetime(3) NULL DEFAULT NULL, + `PARENT_DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_cmmn_deployment +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_cmmn_deployment_resource +-- ---------------------------- +DROP TABLE IF EXISTS `act_cmmn_deployment_resource`; +CREATE TABLE `act_cmmn_deployment_resource` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `RESOURCE_BYTES_` longblob NULL, + `GENERATED_` tinyint NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_CMMN_RSRC_DPL`(`DEPLOYMENT_ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_cmmn_deployment_resource +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_cmmn_hi_case_inst +-- ---------------------------- +DROP TABLE IF EXISTS `act_cmmn_hi_case_inst`; +CREATE TABLE `act_cmmn_hi_case_inst` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `REV_` int NOT NULL, + `BUSINESS_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `PARENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CASE_DEF_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `STATE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `START_TIME_` datetime(3) NULL DEFAULT NULL, + `END_TIME_` datetime(3) NULL DEFAULT NULL, + `START_USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CALLBACK_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CALLBACK_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `REFERENCE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `REFERENCE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `LAST_REACTIVATION_TIME_` datetime(3) NULL DEFAULT NULL, + `LAST_REACTIVATION_USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `BUSINESS_STATUS_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_HI_CASE_INST_END`(`END_TIME_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_cmmn_hi_case_inst +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_cmmn_hi_mil_inst +-- ---------------------------- +DROP TABLE IF EXISTS `act_cmmn_hi_mil_inst`; +CREATE TABLE `act_cmmn_hi_mil_inst` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `REV_` int NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `TIME_STAMP_` datetime(3) NOT NULL, + `CASE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `CASE_DEF_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_cmmn_hi_mil_inst +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_cmmn_hi_plan_item_inst +-- ---------------------------- +DROP TABLE IF EXISTS `act_cmmn_hi_plan_item_inst`; +CREATE TABLE `act_cmmn_hi_plan_item_inst` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `REV_` int NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `STATE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CASE_DEF_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CASE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `STAGE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `IS_STAGE_` tinyint NULL DEFAULT NULL, + `ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `ITEM_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `ITEM_DEFINITION_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CREATE_TIME_` datetime(3) NULL DEFAULT NULL, + `LAST_AVAILABLE_TIME_` datetime(3) NULL DEFAULT NULL, + `LAST_ENABLED_TIME_` datetime(3) NULL DEFAULT NULL, + `LAST_DISABLED_TIME_` datetime(3) NULL DEFAULT NULL, + `LAST_STARTED_TIME_` datetime(3) NULL DEFAULT NULL, + `LAST_SUSPENDED_TIME_` datetime(3) NULL DEFAULT NULL, + `COMPLETED_TIME_` datetime(3) NULL DEFAULT NULL, + `OCCURRED_TIME_` datetime(3) NULL DEFAULT NULL, + `TERMINATED_TIME_` datetime(3) NULL DEFAULT NULL, + `EXIT_TIME_` datetime(3) NULL DEFAULT NULL, + `ENDED_TIME_` datetime(3) NULL DEFAULT NULL, + `LAST_UPDATED_TIME_` datetime(3) NULL DEFAULT NULL, + `START_USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `REFERENCE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `REFERENCE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `ENTRY_CRITERION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `EXIT_CRITERION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `SHOW_IN_OVERVIEW_` tinyint NULL DEFAULT NULL, + `EXTRA_VALUE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DERIVED_CASE_DEF_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `LAST_UNAVAILABLE_TIME_` datetime(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_HI_PLAN_ITEM_INST_CASE`(`CASE_INST_ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_cmmn_hi_plan_item_inst +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_cmmn_ru_case_inst +-- ---------------------------- +DROP TABLE IF EXISTS `act_cmmn_ru_case_inst`; +CREATE TABLE `act_cmmn_ru_case_inst` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `REV_` int NOT NULL, + `BUSINESS_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `PARENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CASE_DEF_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `STATE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `START_TIME_` datetime(3) NULL DEFAULT NULL, + `START_USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CALLBACK_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CALLBACK_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `LOCK_TIME_` datetime(3) NULL DEFAULT NULL, + `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `IS_COMPLETEABLE_` tinyint NULL DEFAULT NULL, + `REFERENCE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `REFERENCE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `LAST_REACTIVATION_TIME_` datetime(3) NULL DEFAULT NULL, + `LAST_REACTIVATION_USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `BUSINESS_STATUS_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_CASE_INST_CASE_DEF`(`CASE_DEF_ID_`) USING BTREE, + INDEX `ACT_IDX_CASE_INST_PARENT`(`PARENT_ID_`) USING BTREE, + INDEX `ACT_IDX_CASE_INST_REF_ID_`(`REFERENCE_ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_cmmn_ru_case_inst +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_cmmn_ru_mil_inst +-- ---------------------------- +DROP TABLE IF EXISTS `act_cmmn_ru_mil_inst`; +CREATE TABLE `act_cmmn_ru_mil_inst` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `TIME_STAMP_` datetime(3) NOT NULL, + `CASE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `CASE_DEF_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_MIL_CASE_DEF`(`CASE_DEF_ID_`) USING BTREE, + INDEX `ACT_IDX_MIL_CASE_INST`(`CASE_INST_ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_cmmn_ru_mil_inst +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_cmmn_ru_plan_item_inst +-- ---------------------------- +DROP TABLE IF EXISTS `act_cmmn_ru_plan_item_inst`; +CREATE TABLE `act_cmmn_ru_plan_item_inst` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `REV_` int NOT NULL, + `CASE_DEF_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CASE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `STAGE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `IS_STAGE_` tinyint NULL DEFAULT NULL, + `ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `STATE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CREATE_TIME_` datetime(3) NULL DEFAULT NULL, + `START_USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `REFERENCE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `REFERENCE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `ITEM_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `ITEM_DEFINITION_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `IS_COMPLETEABLE_` tinyint NULL DEFAULT NULL, + `IS_COUNT_ENABLED_` tinyint NULL DEFAULT NULL, + `VAR_COUNT_` int NULL DEFAULT NULL, + `SENTRY_PART_INST_COUNT_` int NULL DEFAULT NULL, + `LAST_AVAILABLE_TIME_` datetime(3) NULL DEFAULT NULL, + `LAST_ENABLED_TIME_` datetime(3) NULL DEFAULT NULL, + `LAST_DISABLED_TIME_` datetime(3) NULL DEFAULT NULL, + `LAST_STARTED_TIME_` datetime(3) NULL DEFAULT NULL, + `LAST_SUSPENDED_TIME_` datetime(3) NULL DEFAULT NULL, + `COMPLETED_TIME_` datetime(3) NULL DEFAULT NULL, + `OCCURRED_TIME_` datetime(3) NULL DEFAULT NULL, + `TERMINATED_TIME_` datetime(3) NULL DEFAULT NULL, + `EXIT_TIME_` datetime(3) NULL DEFAULT NULL, + `ENDED_TIME_` datetime(3) NULL DEFAULT NULL, + `ENTRY_CRITERION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `EXIT_CRITERION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `EXTRA_VALUE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DERIVED_CASE_DEF_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `LAST_UNAVAILABLE_TIME_` datetime(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_PLAN_ITEM_CASE_DEF`(`CASE_DEF_ID_`) USING BTREE, + INDEX `ACT_IDX_PLAN_ITEM_CASE_INST`(`CASE_INST_ID_`) USING BTREE, + INDEX `ACT_IDX_PLAN_ITEM_STAGE_INST`(`STAGE_INST_ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_cmmn_ru_plan_item_inst +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_cmmn_ru_sentry_part_inst +-- ---------------------------- +DROP TABLE IF EXISTS `act_cmmn_ru_sentry_part_inst`; +CREATE TABLE `act_cmmn_ru_sentry_part_inst` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `REV_` int NOT NULL, + `CASE_DEF_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CASE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `PLAN_ITEM_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `ON_PART_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `IF_PART_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `TIME_STAMP_` datetime(3) NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_SENTRY_CASE_DEF`(`CASE_DEF_ID_`) USING BTREE, + INDEX `ACT_IDX_SENTRY_CASE_INST`(`CASE_INST_ID_`) USING BTREE, + INDEX `ACT_IDX_SENTRY_PLAN_ITEM`(`PLAN_ITEM_INST_ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_cmmn_ru_sentry_part_inst +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_dmn_decision +-- ---------------------------- +DROP TABLE IF EXISTS `act_dmn_decision`; +CREATE TABLE `act_dmn_decision` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `VERSION_` int NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `RESOURCE_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DESCRIPTION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DECISION_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_dmn_decision +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_dmn_deployment +-- ---------------------------- +DROP TABLE IF EXISTS `act_dmn_deployment`; +CREATE TABLE `act_dmn_deployment` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DEPLOY_TIME_` datetime(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `PARENT_DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_dmn_deployment +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_dmn_deployment_resource +-- ---------------------------- +DROP TABLE IF EXISTS `act_dmn_deployment_resource`; +CREATE TABLE `act_dmn_deployment_resource` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `RESOURCE_BYTES_` longblob NULL, + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_dmn_deployment_resource +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_dmn_hi_decision_execution +-- ---------------------------- +DROP TABLE IF EXISTS `act_dmn_hi_decision_execution`; +CREATE TABLE `act_dmn_hi_decision_execution` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `DECISION_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `START_TIME_` datetime(3) NULL DEFAULT NULL, + `END_TIME_` datetime(3) NULL DEFAULT NULL, + `INSTANCE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `EXECUTION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `ACTIVITY_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `FAILED_` tinyint NULL DEFAULT 0, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `EXECUTION_JSON_` longtext CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_DMN_INSTANCE_ID`(`INSTANCE_ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_dmn_hi_decision_execution +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_evt_log +-- ---------------------------- +DROP TABLE IF EXISTS `act_evt_log`; +CREATE TABLE `act_evt_log` ( + `LOG_NR_` bigint NOT NULL AUTO_INCREMENT, + `TYPE_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TIME_STAMP_` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DATA_` longblob NULL, + `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `LOCK_TIME_` timestamp(3) NULL DEFAULT NULL, + `IS_PROCESSED_` tinyint NULL DEFAULT 0, + PRIMARY KEY (`LOG_NR_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_evt_log +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_ge_bytearray +-- ---------------------------- +DROP TABLE IF EXISTS `act_ge_bytearray`; +CREATE TABLE `act_ge_bytearray` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `BYTES_` longblob NULL, + `GENERATED_` tinyint NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_FK_BYTEARR_DEPL`(`DEPLOYMENT_ID_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_BYTEARR_DEPL` FOREIGN KEY (`DEPLOYMENT_ID_`) REFERENCES `act_re_deployment` (`id_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_ge_bytearray +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_ge_property +-- ---------------------------- +DROP TABLE IF EXISTS `act_ge_property`; +CREATE TABLE `act_ge_property` ( + `NAME_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `VALUE_` varchar(300) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `REV_` int NULL DEFAULT NULL, + PRIMARY KEY (`NAME_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_ge_property +-- ---------------------------- +INSERT INTO `act_ge_property` VALUES ('app.schema.version', '7.1.0.2', 1); +INSERT INTO `act_ge_property` VALUES ('cfg.execution-related-entities-count', 'true', 1); +INSERT INTO `act_ge_property` VALUES ('cfg.task-related-entities-count', 'true', 1); +INSERT INTO `act_ge_property` VALUES ('cmmn.schema.version', '7.1.0.2', 1); +INSERT INTO `act_ge_property` VALUES ('common.schema.version', '7.1.0.2', 1); +INSERT INTO `act_ge_property` VALUES ('dmn.schema.version', '7.1.0.2', 1); +INSERT INTO `act_ge_property` VALUES ('eventregistry.schema.version', '7.1.0.2', 1); +INSERT INTO `act_ge_property` VALUES ('next.dbid', '1', 1); +INSERT INTO `act_ge_property` VALUES ('schema.history', 'create(7.1.0.2)', 1); +INSERT INTO `act_ge_property` VALUES ('schema.version', '7.1.0.2', 1); + +-- ---------------------------- +-- Table structure for act_hi_actinst +-- ---------------------------- +DROP TABLE IF EXISTS `act_hi_actinst`; +CREATE TABLE `act_hi_actinst` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT 1, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `ACT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CALL_PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ACT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ACT_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `ASSIGNEE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `START_TIME_` datetime(3) NOT NULL, + `END_TIME_` datetime(3) NULL DEFAULT NULL, + `TRANSACTION_ORDER_` int NULL DEFAULT NULL, + `DURATION_` bigint NULL DEFAULT NULL, + `DELETE_REASON_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_HI_ACT_INST_START`(`START_TIME_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_ACT_INST_END`(`END_TIME_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_ACT_INST_PROCINST`(`PROC_INST_ID_` ASC, `ACT_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_ACT_INST_EXEC`(`EXECUTION_ID_` ASC, `ACT_ID_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_hi_actinst +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_hi_attachment +-- ---------------------------- +DROP TABLE IF EXISTS `act_hi_attachment`; +CREATE TABLE `act_hi_attachment` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DESCRIPTION_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `URL_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CONTENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TIME_` datetime(3) NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_hi_attachment +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_hi_comment +-- ---------------------------- +DROP TABLE IF EXISTS `act_hi_comment`; +CREATE TABLE `act_hi_comment` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TIME_` datetime(3) NOT NULL, + `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ACTION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `MESSAGE_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `FULL_MSG_` longblob NULL, + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_hi_comment +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_hi_detail +-- ---------------------------- +DROP TABLE IF EXISTS `act_hi_detail`; +CREATE TABLE `act_hi_detail` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ACT_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `VAR_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `REV_` int NULL DEFAULT NULL, + `TIME_` datetime(3) NOT NULL, + `BYTEARRAY_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DOUBLE_` double NULL DEFAULT NULL, + `LONG_` bigint NULL DEFAULT NULL, + `TEXT_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TEXT2_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_HI_DETAIL_PROC_INST`(`PROC_INST_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_DETAIL_ACT_INST`(`ACT_INST_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_DETAIL_TIME`(`TIME_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_DETAIL_NAME`(`NAME_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_DETAIL_TASK_ID`(`TASK_ID_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_hi_detail +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_hi_entitylink +-- ---------------------------- +DROP TABLE IF EXISTS `act_hi_entitylink`; +CREATE TABLE `act_hi_entitylink` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `LINK_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CREATE_TIME_` datetime(3) NULL DEFAULT NULL, + `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PARENT_ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `REF_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `REF_SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `REF_SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ROOT_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ROOT_SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HIERARCHY_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_HI_ENT_LNK_SCOPE`(`SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC, `LINK_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_ENT_LNK_REF_SCOPE`(`REF_SCOPE_ID_` ASC, `REF_SCOPE_TYPE_` ASC, `LINK_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_ENT_LNK_ROOT_SCOPE`(`ROOT_SCOPE_ID_` ASC, `ROOT_SCOPE_TYPE_` ASC, `LINK_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_ENT_LNK_SCOPE_DEF`(`SCOPE_DEFINITION_ID_` ASC, `SCOPE_TYPE_` ASC, `LINK_TYPE_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_hi_entitylink +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_hi_identitylink +-- ---------------------------- +DROP TABLE IF EXISTS `act_hi_identitylink`; +CREATE TABLE `act_hi_identitylink` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `GROUP_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CREATE_TIME_` datetime(3) NULL DEFAULT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_HI_IDENT_LNK_USER`(`USER_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_IDENT_LNK_SCOPE`(`SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_IDENT_LNK_SUB_SCOPE`(`SUB_SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_IDENT_LNK_SCOPE_DEF`(`SCOPE_DEFINITION_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_IDENT_LNK_TASK`(`TASK_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_IDENT_LNK_PROCINST`(`PROC_INST_ID_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_hi_identitylink +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_hi_procinst +-- ---------------------------- +DROP TABLE IF EXISTS `act_hi_procinst`; +CREATE TABLE `act_hi_procinst` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT 1, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `BUSINESS_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `START_TIME_` datetime(3) NOT NULL, + `END_TIME_` datetime(3) NULL DEFAULT NULL, + `DURATION_` bigint NULL DEFAULT NULL, + `START_USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `START_ACT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `END_ACT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUPER_PROCESS_INSTANCE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DELETE_REASON_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CALLBACK_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CALLBACK_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `REFERENCE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `REFERENCE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROPAGATED_STAGE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `BUSINESS_STATUS_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + UNIQUE INDEX `PROC_INST_ID_`(`PROC_INST_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_PRO_INST_END`(`END_TIME_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_PRO_I_BUSKEY`(`BUSINESS_KEY_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_PRO_SUPER_PROCINST`(`SUPER_PROCESS_INSTANCE_ID_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_hi_procinst +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_hi_taskinst +-- ---------------------------- +DROP TABLE IF EXISTS `act_hi_taskinst`; +CREATE TABLE `act_hi_taskinst` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT 1, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TASK_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TASK_DEF_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROPAGATED_STAGE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `STATE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PARENT_TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DESCRIPTION_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ASSIGNEE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `START_TIME_` datetime(3) NOT NULL, + `IN_PROGRESS_TIME_` datetime(3) NULL DEFAULT NULL, + `IN_PROGRESS_STARTED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CLAIM_TIME_` datetime(3) NULL DEFAULT NULL, + `CLAIMED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUSPENDED_TIME_` datetime(3) NULL DEFAULT NULL, + `SUSPENDED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `END_TIME_` datetime(3) NULL DEFAULT NULL, + `COMPLETED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DURATION_` bigint NULL DEFAULT NULL, + `DELETE_REASON_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PRIORITY_` int NULL DEFAULT NULL, + `IN_PROGRESS_DUE_DATE_` datetime(3) NULL DEFAULT NULL, + `DUE_DATE_` datetime(3) NULL DEFAULT NULL, + `FORM_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + `LAST_UPDATED_TIME_` datetime(3) NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_HI_TASK_SCOPE`(`SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_TASK_SUB_SCOPE`(`SUB_SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_TASK_SCOPE_DEF`(`SCOPE_DEFINITION_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_TASK_INST_PROCINST`(`PROC_INST_ID_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_hi_taskinst +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_hi_tsk_log +-- ---------------------------- +DROP TABLE IF EXISTS `act_hi_tsk_log`; +CREATE TABLE `act_hi_tsk_log` ( + `ID_` bigint NOT NULL AUTO_INCREMENT, + `TYPE_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `TIME_STAMP_` timestamp(3) NOT NULL, + `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DATA_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_ACT_HI_TSK_LOG_TASK`(`TASK_ID_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_hi_tsk_log +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_hi_varinst +-- ---------------------------- +DROP TABLE IF EXISTS `act_hi_varinst`; +CREATE TABLE `act_hi_varinst` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT 1, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `VAR_TYPE_` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `BYTEARRAY_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DOUBLE_` double NULL DEFAULT NULL, + `LONG_` bigint NULL DEFAULT NULL, + `TEXT_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TEXT2_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `META_INFO_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CREATE_TIME_` datetime(3) NULL DEFAULT NULL, + `LAST_UPDATED_TIME_` datetime(3) NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_HI_PROCVAR_NAME_TYPE`(`NAME_` ASC, `VAR_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_VAR_SCOPE_ID_TYPE`(`SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_VAR_SUB_ID_TYPE`(`SUB_SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_PROCVAR_PROC_INST`(`PROC_INST_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_PROCVAR_TASK_ID`(`TASK_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_HI_PROCVAR_EXE`(`EXECUTION_ID_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_hi_varinst +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_id_bytearray +-- ---------------------------- +DROP TABLE IF EXISTS `act_id_bytearray`; +CREATE TABLE `act_id_bytearray` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `BYTES_` longblob NULL, + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_id_bytearray +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_id_group +-- ---------------------------- +DROP TABLE IF EXISTS `act_id_group`; +CREATE TABLE `act_id_group` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_id_group +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_id_info +-- ---------------------------- +DROP TABLE IF EXISTS `act_id_info`; +CREATE TABLE `act_id_info` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `USER_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TYPE_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `VALUE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PASSWORD_` longblob NULL, + `PARENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_id_info +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_id_membership +-- ---------------------------- +DROP TABLE IF EXISTS `act_id_membership`; +CREATE TABLE `act_id_membership` ( + `USER_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `GROUP_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + PRIMARY KEY (`USER_ID_`, `GROUP_ID_`) USING BTREE, + INDEX `ACT_FK_MEMB_GROUP`(`GROUP_ID_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_MEMB_GROUP` FOREIGN KEY (`GROUP_ID_`) REFERENCES `act_id_group` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_MEMB_USER` FOREIGN KEY (`USER_ID_`) REFERENCES `act_id_user` (`id_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_id_membership +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_id_priv +-- ---------------------------- +DROP TABLE IF EXISTS `act_id_priv`; +CREATE TABLE `act_id_priv` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + UNIQUE INDEX `ACT_UNIQ_PRIV_NAME`(`NAME_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_id_priv +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_id_priv_mapping +-- ---------------------------- +DROP TABLE IF EXISTS `act_id_priv_mapping`; +CREATE TABLE `act_id_priv_mapping` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `PRIV_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `GROUP_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_FK_PRIV_MAPPING`(`PRIV_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_PRIV_USER`(`USER_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_PRIV_GROUP`(`GROUP_ID_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_PRIV_MAPPING` FOREIGN KEY (`PRIV_ID_`) REFERENCES `act_id_priv` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_id_priv_mapping +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_id_property +-- ---------------------------- +DROP TABLE IF EXISTS `act_id_property`; +CREATE TABLE `act_id_property` ( + `NAME_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `VALUE_` varchar(300) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `REV_` int NULL DEFAULT NULL, + PRIMARY KEY (`NAME_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_id_property +-- ---------------------------- +INSERT INTO `act_id_property` VALUES ('schema.version', '7.1.0.2', 1); + +-- ---------------------------- +-- Table structure for act_id_token +-- ---------------------------- +DROP TABLE IF EXISTS `act_id_token`; +CREATE TABLE `act_id_token` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `TOKEN_VALUE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TOKEN_DATE_` timestamp(3) NULL DEFAULT NULL, + `IP_ADDRESS_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `USER_AGENT_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TOKEN_DATA_` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_id_token +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_id_user +-- ---------------------------- +DROP TABLE IF EXISTS `act_id_user`; +CREATE TABLE `act_id_user` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `FIRST_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `LAST_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DISPLAY_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EMAIL_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PWD_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PICTURE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_id_user +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_procdef_info +-- ---------------------------- +DROP TABLE IF EXISTS `act_procdef_info`; +CREATE TABLE `act_procdef_info` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `INFO_JSON_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + UNIQUE INDEX `ACT_UNIQ_INFO_PROCDEF`(`PROC_DEF_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_INFO_PROCDEF`(`PROC_DEF_ID_` ASC) USING BTREE, + INDEX `ACT_FK_INFO_JSON_BA`(`INFO_JSON_ID_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_INFO_JSON_BA` FOREIGN KEY (`INFO_JSON_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_INFO_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`id_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_procdef_info +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_re_deployment +-- ---------------------------- +DROP TABLE IF EXISTS `act_re_deployment`; +CREATE TABLE `act_re_deployment` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + `DEPLOY_TIME_` timestamp(3) NULL DEFAULT NULL, + `DERIVED_FROM_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DERIVED_FROM_ROOT_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PARENT_DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ENGINE_VERSION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_re_deployment +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_re_model +-- ---------------------------- +DROP TABLE IF EXISTS `act_re_model`; +CREATE TABLE `act_re_model` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `LAST_UPDATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `VERSION_` int NULL DEFAULT NULL, + `META_INFO_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EDITOR_SOURCE_VALUE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EDITOR_SOURCE_EXTRA_VALUE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_FK_MODEL_SOURCE`(`EDITOR_SOURCE_VALUE_ID_` ASC) USING BTREE, + INDEX `ACT_FK_MODEL_SOURCE_EXTRA`(`EDITOR_SOURCE_EXTRA_VALUE_ID_` ASC) USING BTREE, + INDEX `ACT_FK_MODEL_DEPLOYMENT`(`DEPLOYMENT_ID_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_MODEL_DEPLOYMENT` FOREIGN KEY (`DEPLOYMENT_ID_`) REFERENCES `act_re_deployment` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_MODEL_SOURCE` FOREIGN KEY (`EDITOR_SOURCE_VALUE_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_MODEL_SOURCE_EXTRA` FOREIGN KEY (`EDITOR_SOURCE_EXTRA_VALUE_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_re_model +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_re_procdef +-- ---------------------------- +DROP TABLE IF EXISTS `act_re_procdef`; +CREATE TABLE `act_re_procdef` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `VERSION_` int NOT NULL, + `DEPLOYMENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `RESOURCE_NAME_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DGRM_RESOURCE_NAME_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DESCRIPTION_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HAS_START_FORM_KEY_` tinyint NULL DEFAULT NULL, + `HAS_GRAPHICAL_NOTATION_` tinyint NULL DEFAULT NULL, + `SUSPENSION_STATE_` int NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + `ENGINE_VERSION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DERIVED_FROM_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DERIVED_FROM_ROOT_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DERIVED_VERSION_` int NOT NULL DEFAULT 0, + PRIMARY KEY (`ID_`) USING BTREE, + UNIQUE INDEX `ACT_UNIQ_PROCDEF`(`KEY_` ASC, `VERSION_` ASC, `DERIVED_VERSION_` ASC, `TENANT_ID_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_re_procdef +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_ru_actinst +-- ---------------------------- +DROP TABLE IF EXISTS `act_ru_actinst`; +CREATE TABLE `act_ru_actinst` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT 1, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `ACT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CALL_PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ACT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ACT_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `ASSIGNEE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `START_TIME_` datetime(3) NOT NULL, + `END_TIME_` datetime(3) NULL DEFAULT NULL, + `DURATION_` bigint NULL DEFAULT NULL, + `TRANSACTION_ORDER_` int NULL DEFAULT NULL, + `DELETE_REASON_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_RU_ACTI_START`(`START_TIME_` ASC) USING BTREE, + INDEX `ACT_IDX_RU_ACTI_END`(`END_TIME_` ASC) USING BTREE, + INDEX `ACT_IDX_RU_ACTI_PROC`(`PROC_INST_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_RU_ACTI_PROC_ACT`(`PROC_INST_ID_` ASC, `ACT_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_RU_ACTI_EXEC`(`EXECUTION_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_RU_ACTI_EXEC_ACT`(`EXECUTION_ID_` ASC, `ACT_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_RU_ACTI_TASK`(`TASK_ID_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_ru_actinst +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_ru_deadletter_job +-- ---------------------------- +DROP TABLE IF EXISTS `act_ru_deadletter_job`; +CREATE TABLE `act_ru_deadletter_job` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `EXCLUSIVE_` tinyint(1) NULL DEFAULT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROCESS_INSTANCE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ELEMENT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CORRELATION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXCEPTION_STACK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXCEPTION_MSG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DUEDATE_` timestamp(3) NULL DEFAULT NULL, + `REPEAT_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HANDLER_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HANDLER_CFG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CUSTOM_VALUES_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_DEADLETTER_JOB_EXCEPTION_STACK_ID`(`EXCEPTION_STACK_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_DEADLETTER_JOB_CUSTOM_VALUES_ID`(`CUSTOM_VALUES_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_DEADLETTER_JOB_CORRELATION_ID`(`CORRELATION_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_DJOB_SCOPE`(`SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_DJOB_SUB_SCOPE`(`SUB_SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_DJOB_SCOPE_DEF`(`SCOPE_DEFINITION_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_FK_DEADLETTER_JOB_EXECUTION`(`EXECUTION_ID_` ASC) USING BTREE, + INDEX `ACT_FK_DEADLETTER_JOB_PROCESS_INSTANCE`(`PROCESS_INSTANCE_ID_` ASC) USING BTREE, + INDEX `ACT_FK_DEADLETTER_JOB_PROC_DEF`(`PROC_DEF_ID_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_DEADLETTER_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_DEADLETTER_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_DEADLETTER_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`id_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_DEADLETTER_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_DEADLETTER_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `act_ru_execution` (`id_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_ru_deadletter_job +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_ru_entitylink +-- ---------------------------- +DROP TABLE IF EXISTS `act_ru_entitylink`; +CREATE TABLE `act_ru_entitylink` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `CREATE_TIME_` datetime(3) NULL DEFAULT NULL, + `LINK_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PARENT_ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `REF_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `REF_SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `REF_SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ROOT_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ROOT_SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HIERARCHY_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_ENT_LNK_SCOPE`(`SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC, `LINK_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_ENT_LNK_REF_SCOPE`(`REF_SCOPE_ID_` ASC, `REF_SCOPE_TYPE_` ASC, `LINK_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_ENT_LNK_ROOT_SCOPE`(`ROOT_SCOPE_ID_` ASC, `ROOT_SCOPE_TYPE_` ASC, `LINK_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_ENT_LNK_SCOPE_DEF`(`SCOPE_DEFINITION_ID_` ASC, `SCOPE_TYPE_` ASC, `LINK_TYPE_` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_ru_entitylink +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_ru_event_subscr +-- ---------------------------- +DROP TABLE IF EXISTS `act_ru_event_subscr`; +CREATE TABLE `act_ru_event_subscr` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `EVENT_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `EVENT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ACTIVITY_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CONFIGURATION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CREATED_` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_DEFINITION_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `LOCK_TIME_` timestamp(3) NULL DEFAULT NULL, + `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_EVENT_SUBSCR_CONFIG_`(`CONFIGURATION_` ASC) USING BTREE, + INDEX `ACT_IDX_EVENT_SUBSCR_EXEC_ID`(`EXECUTION_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_EVENT_SUBSCR_PROC_ID`(`PROC_INST_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_EVENT_SUBSCR_SCOPEREF_`(`SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_EVENT_EXEC` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`id_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_ru_event_subscr +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_ru_execution +-- ---------------------------- +DROP TABLE IF EXISTS `act_ru_execution`; +CREATE TABLE `act_ru_execution` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `BUSINESS_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PARENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUPER_EXEC_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ROOT_PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ACT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `IS_ACTIVE_` tinyint NULL DEFAULT NULL, + `IS_CONCURRENT_` tinyint NULL DEFAULT NULL, + `IS_SCOPE_` tinyint NULL DEFAULT NULL, + `IS_EVENT_SCOPE_` tinyint NULL DEFAULT NULL, + `IS_MI_ROOT_` tinyint NULL DEFAULT NULL, + `SUSPENSION_STATE_` int NULL DEFAULT NULL, + `CACHED_ENT_STATE_` int NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `START_ACT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `START_TIME_` datetime(3) NULL DEFAULT NULL, + `START_USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `LOCK_TIME_` timestamp(3) NULL DEFAULT NULL, + `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `IS_COUNT_ENABLED_` tinyint NULL DEFAULT NULL, + `EVT_SUBSCR_COUNT_` int NULL DEFAULT NULL, + `TASK_COUNT_` int NULL DEFAULT NULL, + `JOB_COUNT_` int NULL DEFAULT NULL, + `TIMER_JOB_COUNT_` int NULL DEFAULT NULL, + `SUSP_JOB_COUNT_` int NULL DEFAULT NULL, + `DEADLETTER_JOB_COUNT_` int NULL DEFAULT NULL, + `EXTERNAL_WORKER_JOB_COUNT_` int NULL DEFAULT NULL, + `VAR_COUNT_` int NULL DEFAULT NULL, + `ID_LINK_COUNT_` int NULL DEFAULT NULL, + `CALLBACK_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CALLBACK_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `REFERENCE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `REFERENCE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROPAGATED_STAGE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `BUSINESS_STATUS_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_EXEC_BUSKEY`(`BUSINESS_KEY_` ASC) USING BTREE, + INDEX `ACT_IDC_EXEC_ROOT`(`ROOT_PROC_INST_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_EXEC_REF_ID_`(`REFERENCE_ID_` ASC) USING BTREE, + INDEX `ACT_FK_EXE_PROCINST`(`PROC_INST_ID_` ASC) USING BTREE, + INDEX `ACT_FK_EXE_PARENT`(`PARENT_ID_` ASC) USING BTREE, + INDEX `ACT_FK_EXE_SUPER`(`SUPER_EXEC_` ASC) USING BTREE, + INDEX `ACT_FK_EXE_PROCDEF`(`PROC_DEF_ID_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_EXE_PARENT` FOREIGN KEY (`PARENT_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE CASCADE ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_EXE_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_EXE_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `ACT_FK_EXE_SUPER` FOREIGN KEY (`SUPER_EXEC_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE CASCADE ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_ru_execution +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_ru_external_job +-- ---------------------------- +DROP TABLE IF EXISTS `act_ru_external_job`; +CREATE TABLE `act_ru_external_job` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `LOCK_EXP_TIME_` timestamp(3) NULL DEFAULT NULL, + `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXCLUSIVE_` tinyint(1) NULL DEFAULT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROCESS_INSTANCE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ELEMENT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CORRELATION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `RETRIES_` int NULL DEFAULT NULL, + `EXCEPTION_STACK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXCEPTION_MSG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DUEDATE_` timestamp(3) NULL DEFAULT NULL, + `REPEAT_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HANDLER_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HANDLER_CFG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CUSTOM_VALUES_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_EXTERNAL_JOB_EXCEPTION_STACK_ID`(`EXCEPTION_STACK_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_EXTERNAL_JOB_CUSTOM_VALUES_ID`(`CUSTOM_VALUES_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_EXTERNAL_JOB_CORRELATION_ID`(`CORRELATION_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_EJOB_SCOPE`(`SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_EJOB_SUB_SCOPE`(`SUB_SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_EJOB_SCOPE_DEF`(`SCOPE_DEFINITION_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_EXTERNAL_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_EXTERNAL_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_ru_external_job +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_ru_history_job +-- ---------------------------- +DROP TABLE IF EXISTS `act_ru_history_job`; +CREATE TABLE `act_ru_history_job` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `LOCK_EXP_TIME_` timestamp(3) NULL DEFAULT NULL, + `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `RETRIES_` int NULL DEFAULT NULL, + `EXCEPTION_STACK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXCEPTION_MSG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HANDLER_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HANDLER_CFG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CUSTOM_VALUES_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ADV_HANDLER_CFG_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_ru_history_job +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_ru_identitylink +-- ---------------------------- +DROP TABLE IF EXISTS `act_ru_identitylink`; +CREATE TABLE `act_ru_identitylink` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `GROUP_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_IDENT_LNK_USER`(`USER_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_IDENT_LNK_GROUP`(`GROUP_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_IDENT_LNK_SCOPE`(`SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_IDENT_LNK_SUB_SCOPE`(`SUB_SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_IDENT_LNK_SCOPE_DEF`(`SCOPE_DEFINITION_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_ATHRZ_PROCEDEF`(`PROC_DEF_ID_` ASC) USING BTREE, + INDEX `ACT_FK_TSKASS_TASK`(`TASK_ID_` ASC) USING BTREE, + INDEX `ACT_FK_IDL_PROCINST`(`PROC_INST_ID_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_ATHRZ_PROCEDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_IDL_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_TSKASS_TASK` FOREIGN KEY (`TASK_ID_`) REFERENCES `act_ru_task` (`id_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_ru_identitylink +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_ru_job +-- ---------------------------- +DROP TABLE IF EXISTS `act_ru_job`; +CREATE TABLE `act_ru_job` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `LOCK_EXP_TIME_` timestamp(3) NULL DEFAULT NULL, + `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXCLUSIVE_` tinyint(1) NULL DEFAULT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROCESS_INSTANCE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ELEMENT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CORRELATION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `RETRIES_` int NULL DEFAULT NULL, + `EXCEPTION_STACK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXCEPTION_MSG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DUEDATE_` timestamp(3) NULL DEFAULT NULL, + `REPEAT_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HANDLER_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HANDLER_CFG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CUSTOM_VALUES_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_JOB_EXCEPTION_STACK_ID`(`EXCEPTION_STACK_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_JOB_CUSTOM_VALUES_ID`(`CUSTOM_VALUES_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_JOB_CORRELATION_ID`(`CORRELATION_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_JOB_SCOPE`(`SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_JOB_SUB_SCOPE`(`SUB_SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_JOB_SCOPE_DEF`(`SCOPE_DEFINITION_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_FK_JOB_EXECUTION`(`EXECUTION_ID_` ASC) USING BTREE, + INDEX `ACT_FK_JOB_PROCESS_INSTANCE`(`PROCESS_INSTANCE_ID_` ASC) USING BTREE, + INDEX `ACT_FK_JOB_PROC_DEF`(`PROC_DEF_ID_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_ru_job +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_ru_suspended_job +-- ---------------------------- +DROP TABLE IF EXISTS `act_ru_suspended_job`; +CREATE TABLE `act_ru_suspended_job` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `EXCLUSIVE_` tinyint(1) NULL DEFAULT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROCESS_INSTANCE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ELEMENT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CORRELATION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `RETRIES_` int NULL DEFAULT NULL, + `EXCEPTION_STACK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXCEPTION_MSG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DUEDATE_` timestamp(3) NULL DEFAULT NULL, + `REPEAT_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HANDLER_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HANDLER_CFG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CUSTOM_VALUES_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_SUSPENDED_JOB_EXCEPTION_STACK_ID`(`EXCEPTION_STACK_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_SUSPENDED_JOB_CUSTOM_VALUES_ID`(`CUSTOM_VALUES_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_SUSPENDED_JOB_CORRELATION_ID`(`CORRELATION_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_SJOB_SCOPE`(`SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_SJOB_SUB_SCOPE`(`SUB_SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_SJOB_SCOPE_DEF`(`SCOPE_DEFINITION_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_FK_SUSPENDED_JOB_EXECUTION`(`EXECUTION_ID_` ASC) USING BTREE, + INDEX `ACT_FK_SUSPENDED_JOB_PROCESS_INSTANCE`(`PROCESS_INSTANCE_ID_` ASC) USING BTREE, + INDEX `ACT_FK_SUSPENDED_JOB_PROC_DEF`(`PROC_DEF_ID_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_SUSPENDED_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_SUSPENDED_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_SUSPENDED_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_SUSPENDED_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_SUSPENDED_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_ru_suspended_job +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_ru_task +-- ---------------------------- +DROP TABLE IF EXISTS `act_ru_task`; +CREATE TABLE `act_ru_task` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TASK_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROPAGATED_STAGE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `STATE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PARENT_TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DESCRIPTION_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TASK_DEF_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ASSIGNEE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DELEGATION_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PRIORITY_` int NULL DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `IN_PROGRESS_TIME_` datetime(3) NULL DEFAULT NULL, + `IN_PROGRESS_STARTED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CLAIM_TIME_` datetime(3) NULL DEFAULT NULL, + `CLAIMED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUSPENDED_TIME_` datetime(3) NULL DEFAULT NULL, + `SUSPENDED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `IN_PROGRESS_DUE_DATE_` datetime(3) NULL DEFAULT NULL, + `DUE_DATE_` datetime(3) NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUSPENSION_STATE_` int NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + `FORM_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `IS_COUNT_ENABLED_` tinyint NULL DEFAULT NULL, + `VAR_COUNT_` int NULL DEFAULT NULL, + `ID_LINK_COUNT_` int NULL DEFAULT NULL, + `SUB_TASK_COUNT_` int NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_TASK_CREATE`(`CREATE_TIME_` ASC) USING BTREE, + INDEX `ACT_IDX_TASK_SCOPE`(`SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_TASK_SUB_SCOPE`(`SUB_SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_TASK_SCOPE_DEF`(`SCOPE_DEFINITION_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_FK_TASK_EXE`(`EXECUTION_ID_` ASC) USING BTREE, + INDEX `ACT_FK_TASK_PROCINST`(`PROC_INST_ID_` ASC) USING BTREE, + INDEX `ACT_FK_TASK_PROCDEF`(`PROC_DEF_ID_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_TASK_EXE` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_TASK_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_TASK_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_ru_task +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_ru_timer_job +-- ---------------------------- +DROP TABLE IF EXISTS `act_ru_timer_job`; +CREATE TABLE `act_ru_timer_job` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `LOCK_EXP_TIME_` timestamp(3) NULL DEFAULT NULL, + `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXCLUSIVE_` tinyint(1) NULL DEFAULT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROCESS_INSTANCE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `ELEMENT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CORRELATION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `RETRIES_` int NULL DEFAULT NULL, + `EXCEPTION_STACK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `EXCEPTION_MSG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DUEDATE_` timestamp(3) NULL DEFAULT NULL, + `REPEAT_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HANDLER_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `HANDLER_CFG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CUSTOM_VALUES_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_TIMER_JOB_EXCEPTION_STACK_ID`(`EXCEPTION_STACK_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_TIMER_JOB_CUSTOM_VALUES_ID`(`CUSTOM_VALUES_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_TIMER_JOB_CORRELATION_ID`(`CORRELATION_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_TIMER_JOB_DUEDATE`(`DUEDATE_` ASC) USING BTREE, + INDEX `ACT_IDX_TJOB_SCOPE`(`SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_TJOB_SUB_SCOPE`(`SUB_SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_TJOB_SCOPE_DEF`(`SCOPE_DEFINITION_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_FK_TIMER_JOB_EXECUTION`(`EXECUTION_ID_` ASC) USING BTREE, + INDEX `ACT_FK_TIMER_JOB_PROCESS_INSTANCE`(`PROCESS_INSTANCE_ID_` ASC) USING BTREE, + INDEX `ACT_FK_TIMER_JOB_PROC_DEF`(`PROC_DEF_ID_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_TIMER_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_TIMER_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_TIMER_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_TIMER_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_TIMER_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_ru_timer_job +-- ---------------------------- + +-- ---------------------------- +-- Table structure for act_ru_variable +-- ---------------------------- +DROP TABLE IF EXISTS `act_ru_variable`; +CREATE TABLE `act_ru_variable` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `BYTEARRAY_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `DOUBLE_` double NULL DEFAULT NULL, + `LONG_` bigint NULL DEFAULT NULL, + `TEXT_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TEXT2_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `META_INFO_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `ACT_IDX_RU_VAR_SCOPE_ID_TYPE`(`SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_IDX_RU_VAR_SUB_ID_TYPE`(`SUB_SCOPE_ID_` ASC, `SCOPE_TYPE_` ASC) USING BTREE, + INDEX `ACT_FK_VAR_BYTEARRAY`(`BYTEARRAY_ID_` ASC) USING BTREE, + INDEX `ACT_IDX_VARIABLE_TASK_ID`(`TASK_ID_` ASC) USING BTREE, + INDEX `ACT_FK_VAR_EXE`(`EXECUTION_ID_` ASC) USING BTREE, + INDEX `ACT_FK_VAR_PROCINST`(`PROC_INST_ID_` ASC) USING BTREE, + CONSTRAINT `ACT_FK_VAR_BYTEARRAY` FOREIGN KEY (`BYTEARRAY_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_VAR_EXE` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT, + CONSTRAINT `ACT_FK_VAR_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of act_ru_variable +-- ---------------------------- + +-- ---------------------------- +-- Table structure for flw_channel_definition +-- ---------------------------- +DROP TABLE IF EXISTS `flw_channel_definition`; +CREATE TABLE `flw_channel_definition` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `VERSION_` int NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CREATE_TIME_` datetime(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `RESOURCE_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DESCRIPTION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `IMPLEMENTATION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of flw_channel_definition +-- ---------------------------- + +-- ---------------------------- +-- Table structure for flw_event_definition +-- ---------------------------- +DROP TABLE IF EXISTS `flw_event_definition`; +CREATE TABLE `flw_event_definition` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `VERSION_` int NULL DEFAULT NULL, + `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `RESOURCE_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DESCRIPTION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of flw_event_definition +-- ---------------------------- + +-- ---------------------------- +-- Table structure for flw_event_deployment +-- ---------------------------- +DROP TABLE IF EXISTS `flw_event_deployment`; +CREATE TABLE `flw_event_deployment` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DEPLOY_TIME_` datetime(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `PARENT_DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of flw_event_deployment +-- ---------------------------- + +-- ---------------------------- +-- Table structure for flw_event_resource +-- ---------------------------- +DROP TABLE IF EXISTS `flw_event_resource`; +CREATE TABLE `flw_event_resource` ( + `ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL, + `RESOURCE_BYTES_` longblob NULL, + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of flw_event_resource +-- ---------------------------- + +-- ---------------------------- +-- Table structure for flw_ru_batch +-- ---------------------------- +DROP TABLE IF EXISTS `flw_ru_batch`; +CREATE TABLE `flw_ru_batch` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `TYPE_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `SEARCH_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SEARCH_KEY2_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CREATE_TIME_` datetime(3) NOT NULL, + `COMPLETE_TIME_` datetime(3) NULL DEFAULT NULL, + `STATUS_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `BATCH_DOC_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of flw_ru_batch +-- ---------------------------- + +-- ---------------------------- +-- Table structure for flw_ru_batch_part +-- ---------------------------- +DROP TABLE IF EXISTS `flw_ru_batch_part`; +CREATE TABLE `flw_ru_batch_part` ( + `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `REV_` int NULL DEFAULT NULL, + `BATCH_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TYPE_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL, + `SCOPE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SEARCH_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `SEARCH_KEY2_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `CREATE_TIME_` datetime(3) NOT NULL, + `COMPLETE_TIME_` datetime(3) NULL DEFAULT NULL, + `STATUS_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `RESULT_DOC_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT '', + PRIMARY KEY (`ID_`) USING BTREE, + INDEX `FLW_IDX_BATCH_PART`(`BATCH_ID_` ASC) USING BTREE, + CONSTRAINT `FLW_FK_BATCH_PART_PARENT` FOREIGN KEY (`BATCH_ID_`) REFERENCES `flw_ru_batch` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of flw_ru_batch_part +-- ---------------------------- + +-- ---------------------------- +-- Table structure for form_data +-- ---------------------------- +DROP TABLE IF EXISTS `form_data`; +CREATE TABLE `form_data` ( + `data_id` bigint NOT NULL AUTO_INCREMENT COMMENT '数据ID', + `form_id` bigint NOT NULL COMMENT '关联的表单ID', + `form_version` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '表单版本(与模板表版本一致)', + `data_content` json NOT NULL COMMENT '表单数据内容(JSON格式)', + `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'draft' COMMENT '数据状态(draft, submitted, approved, rejected)', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + PRIMARY KEY (`data_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '表单数据表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of form_data +-- ---------------------------- + +-- ---------------------------- +-- Table structure for form_template +-- ---------------------------- +DROP TABLE IF EXISTS `form_template`; +CREATE TABLE `form_template` ( + `form_id` bigint NOT NULL AUTO_INCREMENT COMMENT '表单ID', + `form_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表单名称', + `form_schema` json NULL COMMENT '表单JSON Schema(vForm配置)', + `form_version` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '1.0.0' COMMENT '表单版本(语义化版本)', + `form_status` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '0' COMMENT '发布状态(0: 草稿, 1: 已发布, 2: 已停用)', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + PRIMARY KEY (`form_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '表单模板表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of form_template +-- ---------------------------- + +-- ---------------------------- +-- Table structure for gen_join_table +-- ---------------------------- +DROP TABLE IF EXISTS `gen_join_table`; +CREATE TABLE `gen_join_table` ( + `table_id` bigint NOT NULL COMMENT '表编号', + `left_table_id` bigint NOT NULL COMMENT '左表名称', + `right_table_id` bigint NOT NULL COMMENT '右表编号', + `left_table_alias` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '左表别名', + `right_table_alias` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '右表别名', + `left_table_fk` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '左表关联键', + `right_table_fk` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '右表关联键', + `join_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '关联类型', + `join_columns` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '关联字段', + `order_num` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '序号', + `new_table_id` bigint NOT NULL COMMENT '新表编号', + PRIMARY KEY (`table_id`, `right_table_id`, `left_table_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of gen_join_table +-- ---------------------------- + +-- ---------------------------- +-- Table structure for gen_table +-- ---------------------------- +DROP TABLE IF EXISTS `gen_table`; +CREATE TABLE `gen_table` ( + `table_id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `table_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表名称', + `table_alias` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表别名', + `table_comment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '表描述', + `have_sub_column` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '0' COMMENT '是否含有关联字段', + `sub_table_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联子表的表名', + `sub_table_fk_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '子表关联的外键名', + `class_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '实体类名称', + `tpl_category` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'crud' COMMENT '使用的模板(crud单表操作 tree树表操作)', + `tpl_web_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'element-plus' COMMENT '使用的模板类型', + `package_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '生成包路径', + `module_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '生成模块名', + `business_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '生成业务名', + `function_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '生成功能名', + `function_author` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '生成功能作者', + `gen_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '0' COMMENT '生成代码方式(0zip压缩包 1自定义路径)', + `gen_path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '/' COMMENT '生成路径(不填默认项目路径)', + `options` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '其它生成选项', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`table_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成业务表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of gen_table +-- ---------------------------- +INSERT INTO `gen_table` VALUES (1, 'html_pages', 'hp', '司法局法律规定、典型案例、表单下载表', '0', NULL, NULL, 'HtmlPages', 'crud', 'element-plus', 'com.boyue.hasfj', 'hasfj', 'hasfjpages', '司法局法律规定、典型案例、单下载', 'boyue', '0', '/', '{\"parentMenuId\":2087}', 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02', NULL); + +-- ---------------------------- +-- Table structure for gen_table_column +-- ---------------------------- +DROP TABLE IF EXISTS `gen_table_column`; +CREATE TABLE `gen_table_column` ( + `column_id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `table_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '归属表编号', + `column_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '列名称', + `column_comment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '列描述', + `column_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '列类型', + `java_type` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'JAVA类型', + `java_field` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'JAVA字段名', + `is_pk` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否主键(1是)', + `is_increment` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否自增(1是)', + `is_required` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否必填(1是)', + `is_insert` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否为插入字段(1是)', + `is_edit` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否编辑字段(1是)', + `is_list` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否列表字段(1是)', + `is_query` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否查询字段(1是)', + `query_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'EQ' COMMENT '查询方式(等于、不等于、大于、小于、范围)', + `html_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)', + `dict_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '字典类型', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `sub_column_table_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联表名称', + `sub_column_fk_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联字段名称', + `sub_column_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '映射字段名称', + `sub_column_java_field` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '映射字段JAVA字段名', + `sub_column_java_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '映射字段JAVA类型', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`column_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成业务表字段' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of gen_table_column +-- ---------------------------- +INSERT INTO `gen_table_column` VALUES (1, '1', 'id', '序号', 'int(11)', 'Long', 'id', '1', '0', '0', '0', NULL, '1', NULL, 'EQ', 'input', '', 1, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (2, '1', 'format_id', '访问id', 'varchar(6)', 'String', 'formatId', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 2, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (3, '1', 'title', '页面标题', 'varchar(200)', 'String', 'title', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 3, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (4, '1', 'content', 'HTML内容', 'text', 'String', 'content', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'editor', '', 4, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (5, '1', 'page_type', '页面类型:法律规定 law、典型案例 case、表单下载from', 'enum(\'law\',\'case\',\'form\')', 'String', 'pageType', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'select', '', 5, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (6, '1', 'page_url', '页面访问URL', 'varchar(255)', 'String', 'pageUrl', '0', '0', '1', '1', '1', '1', '0', 'EQ', 'input', '', 6, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (7, '1', 'create_time', '创建时间', 'datetime', 'LocalDate', 'createTime', '0', '0', '1', '1', NULL, '1', NULL, 'EQ', 'datetime', '', 7, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (8, '1', 'update_time', '更新时间', 'datetime', 'LocalDate', 'updateTime', '0', '0', '1', '1', '1', '1', NULL, 'EQ', 'datetime', '', 8, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (9, '1', 'status', '状态:1-启用,0-禁用', 'tinyint(4)', 'Integer', 'status', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'radio', '', 9, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (10, '1', 'sort_order', '排序序号,数值越小排序越靠前,用于自定义显示顺序', 'int(11)', 'Long', 'sortOrder', '0', '0', '1', '1', '1', '1', '0', 'EQ', 'input', '', 10, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (11, '1', 'view_count', '浏览次数,记录页面被访问的总次数', 'int(11)', 'Long', 'viewCount', '0', '0', '1', '1', '1', '1', '0', 'EQ', 'input', '', 11, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (12, '1', 'author', '作者/负责人,记录页面的创建者或负责维护的人员', 'varchar(50)', 'String', 'author', '0', '0', '0', '1', '1', '1', '0', 'EQ', 'input', '', 12, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (13, '1', 'keywords', 'SEO关键词,用于搜索引擎优化', 'varchar(200)', 'String', 'keywords', '0', '0', '0', '1', '1', '1', '0', 'EQ', 'input', '', 13, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); +INSERT INTO `gen_table_column` VALUES (14, '1', 'description', 'SEO描述,用于搜索引擎结果展示的页面摘要', 'varchar(500)', 'String', 'description', '0', '0', '0', '1', '1', '1', '0', 'EQ', 'textarea', '', 14, NULL, NULL, NULL, NULL, NULL, 'admin', '2025-05-28 18:57:49', '', '2025-05-28 19:09:02'); + +-- ---------------------------- +-- Table structure for html_pages +-- ---------------------------- +DROP TABLE IF EXISTS `html_pages`; +CREATE TABLE `html_pages` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `format_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `page_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `page_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL, + `attachment_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `author` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `status` int NULL DEFAULT 1, + `sort_order` bigint NULL DEFAULT 100, + `view_count` bigint NULL DEFAULT 0, + `keywords` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `description` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `update_time` datetime NULL DEFAULT NULL, + `create_time` datetime NULL DEFAULT NULL, + `multi_attachments` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '多附件URLs,JSON格式存储多个附件URL及名称', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_html_pages_format_id`(`format_id` ASC) USING BTREE, + INDEX `idx_html_pages_page_type`(`page_type` ASC) USING BTREE, + INDEX `idx_html_pages_status`(`status` ASC) USING BTREE, + INDEX `idx_html_pages_sort_order`(`sort_order` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 451 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '页面内容' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of html_pages +-- ---------------------------- +INSERT INTO `html_pages` VALUES (1, '000001', 'law', '/show.html?Id=000001', '如何确定企业形式', '

《公司法》《个人独资企业法》《合伙企业法》

', '', '法律法规编辑部', 1, 1, 221, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-06-02 19:45:04', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (2, '000001', 'case', '/showcase.html?Id=000001', '如何确定企业形式', '

李某与王某成立“普通合伙企业”经营餐饮,后因亏损负债100万元,法院判令李某、王某承担无限连带责任。

', NULL, '案例分析组', 1, 2, 4, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:08:06', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (3, '000001', 'form', '/table.html?Id=000001', '如何确定企业形式', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', '', '表单管理员', 1, 3, 11, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-06-01 11:03:49', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (4, '000002', 'law', '/show.html?Id=000002', '有限责任公司和股份有限公司的区别是什么?', '

《证券法》第七十八条,发行人及法律、行政法规和国务院证券监督管理机构规定的其他信息披露义务人,应当及时依法履行信息披露义务。信息披露义务人披露的信息,应当真实、准确、完整,简明清晰,通俗易懂,不得有虚假记载、误导性陈述或者重大遗漏。

', NULL, '法律法规编辑部', 1, 4, 17, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:11:13', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (5, '000002', 'case', '/showcase.html?Id=000002', '有限责任公司和股份有限公司的区别是什么?', '

某科技创业团队初期仅3名股东,误以为股份公司“更规范易融资”,直接注册为股份公司。因股份公司需设股东大会、董事会、监事会,团队人数不足,决策效率低下;同时需定期披露年报、重大事项,合规成本高。天使投资机构因其结构复杂、股权转让受限(需股东大会批准)放弃投资,最终公司因资金链断裂解散清算。

', NULL, '案例分析组', 1, 5, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:11:33', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (6, '000002', 'form', '/table.html?Id=000002', '有限责任公司和股份有限公司的区别是什么?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 6, 1, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:09:11', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (7, '000003', 'law', '/show.html?Id=000003', '如何确定企业名称?', '

《企业名称登记管理规定》《企业名称登记管理规定实施办法》。

', NULL, '法律法规编辑部', 1, 7, 15, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:11:54', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (8, '000003', 'case', '/showcase.html?Id=000003', '如何确定企业名称?', '

甲公司注册名称为“上海特斯拉新能源科技有限公司”,未经特斯拉公司授权。法院认定其名称攀附知名品牌商誉,构成不正当竞争,判令更名并赔偿20万元。

', NULL, '案例分析组', 1, 8, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:12:12', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (9, '000003', 'form', '/table.html?Id=000003', '如何确定企业名称?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 9, 2, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:09:50', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (10, '000004', 'law', '/show.html?Id=000004', '法定代表人的要求有哪些?', '

《公司法》第十条,公司的法定代表人按照公司章程的规定,由代表公司执行公司事务的董事或者经理担任。担任法定代表人的董事或者经理辞任的,视为同时辞去法定代表人。法定代表人辞任的,公司应当在法定代表人辞任之日起三十日内确定新的法定代表人。第十一条:法定代表人以公司名义从事的民事活动,其法律后果由公司承受。公司章程或者股东会对法定代表人职权的限制,不得对抗善意相对人。法定代表人因执行职务造成他人损害的,由公司承担民事责任。公司承担民事责任后,依照法律或者公司章程的规定,可以向有过错的法定代表人追偿。

', NULL, '法律法规编辑部', 1, 10, 7, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:12:43', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (11, '000004', 'case', '/showcase.html?Id=000004', '法定代表人的要求有哪些?', '

某公司法定代表人李某因个人债务被列为失信被执行人,法院限制其高消费。公司向银行申请贷款时,因李某信用瑕疵遭拒,资金链断裂导致停产。市场监管部门责令更换法定代表人,但因股东争议拖延,最终公司破产清算。

', NULL, '案例分析组', 1, 11, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:13:17', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (12, '000004', 'form', '/table.html?Id=000004', '法定代表人的要求有哪些?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 12, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:13:35', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (13, '000005', 'law', '/show.html?Id=000005', '董事、监事、高级管理人员的资格限制有哪些?', '

《公司法》第一百七十八条,有下列情形之一的,不得担任公司的董事、监事、高级管理人员:(一)无民事行为能力或者限制民事行为能力;(二)因贪污、贿赂、侵占财产、挪用财产或者破坏社会主义市场经济秩序,被判处刑罚,或者因犯罪被剥夺政治权利,执行期满未逾五年,被宣告缓刑的,自缓刑考验期满之日起未逾二年;(三)担任破产清算的公司、企业的董事或者厂长、经理,对该公司、企业的破产负有个人责任的,自该公司、企业破产清算完结之日起未逾三年;(四)担任因违法被吊销营业执照、责令关闭的公司、企业的法定代表人,并负有个人责任的,自该公司、企业被吊销营业执照、责令关闭之日起未逾三年;(五)个人因所负数额较大债务到期未清偿被人民法院列为失信被执行人。

', NULL, '法律法规编辑部', 1, 13, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:14:05', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (14, '000005', 'case', '/showcase.html?Id=000005', '董事、监事、高级管理人员的资格限制有哪些?', '

某公司股东李某(公务员)通过亲属代持股权,后因公司债务纠纷被债权人揭发。法院认定代持协议无效,李某需退还全部股权收益,公司被处罚款10万元。

', NULL, '案例分析组', 1, 14, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:14:42', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (15, '000005', 'form', '/table.html?Id=000005', '董事、监事、高级管理人员的资格限制有哪些?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 15, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:14:52', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (16, '000006', 'law', '/show.html?Id=000006', '隐名股东有哪些常见法律风险?', '

最高人民法院关于适用《中华人民共和国公司法》若干问题的规定(三)第二十四条,有限责任公司的实际出资人与名义出资人订立合同,约定由实际出资人出资并享有投资权益,以名义出资人为名义股东,实际出资人与名义股东对该合同效力发生争议的,如无法律规定的无效情形,人民法院应当认定该合同有效。前款规定的实际出资人与名义股东因投资权益的归属发生争议,实际出资人以其实际履行了出资义务为由向名义股东主张权利的,人民法院应予支持。名义股东以公司股东名册记载、公司登记机关登记为由否认实际出资人权利的,人民法院不予支持。实际出资人未经公司其他股东半数以上同意,请求公司变更股东、签发出资证明书、记载于股东名册、记载于公司章程并办理公司登记机关登记的,人民法院不予支持。

', NULL, '法律法规编辑部', 1, 16, 1, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:15:42', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (17, '000006', 'case', '/showcase.html?Id=000006', '隐名股东有哪些常见法律风险?', '

隐名股东李某委托张某代持某公司10%股权,张某未经同意将股权转让给王某,王某不知情且支付合理价款。王某善意取得股权,李某仅能要求张某赔偿损失。

', NULL, '案例分析组', 1, 17, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:16:04', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (18, '000006', 'form', '/table.html?Id=000006', '隐名股东有哪些常见法律风险?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 18, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:16:19', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (19, '000007', 'law', '/show.html?Id=000007', '如何保持创始人在公司的控制权?', '

《公司法》第六十五条,股东会会议由股东按照出资比例行使表决权;但是,公司章程另有规定的除外。

', NULL, '法律法规编辑部', 1, 19, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:16:52', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (20, '000007', 'case', '/showcase.html?Id=000007', '如何保持创始人在公司的控制权?', '

某公司创始人通过“AB股”架构(1股10票投票权),即使持股比例仅15%,仍掌控董事会80%席位。公司上市后,其投票权超80%,确保战略决策权。

', NULL, '案例分析组', 1, 20, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:17:15', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (21, '000007', 'form', '/table.html?Id=000007', '如何保持创始人在公司的控制权?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 21, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:17:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (22, '000008', 'law', '/show.html?Id=000008', '如何防止出现公司僵局?', '

《公司法》第二百三十一条,公司经营管理发生严重困难,继续存续会使股东利益受到重大损失,通过其他途径不能解决的,持有公司百分之十以上表决权的股东,可以请求人民法院解散公司。

最高人民法院关于适用《中华人民共和国公司法》若干问题的规定(二)第一条,单独或者合计持有公司全部股东表决权百分之十以上的股东,以下列事由之一提起解散公司诉讼,并符合公司法第一百八十二条规定的,人民法院应予受理:(一)公司持续两年以上无法召开股东会或者股东大会,公司经营管理发生严重困难的;(二)股东表决时无法达到法定或者公司章程规定的比例,持续两年以上不能做出有效的股东会或者股东大会决议,公司经营管理发生严重困难的;(三)公司董事长期冲突,且无法通过股东会或者股东大会解决,公司经营管理发生严重困难的;


', NULL, '法律法规编辑部', 1, 22, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:18:00', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (23, '000008', 'case', '/showcase.html?Id=000008', '如何防止出现公司僵局?', '

某零售企业两位股东各持50%股权,因经营理念严重冲突,股东会无法通过重大决策(如拓展新店、引入投资),公司现金流枯竭,员工离职,被法院裁定解散。

', NULL, '案例分析组', 1, 23, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:18:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (24, '000008', 'form', '/table.html?Id=000008', '如何防止出现公司僵局?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 24, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:18:40', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (25, '000009', 'law', '/show.html?Id=000009', '如何合理确定注册资本?', '

《公司法》第四条,有限责任公司的股东以其认缴的出资额为限对公司承担责任;股份有限公司的股东以其认购的股份为限对公司承担责任。

', NULL, '法律法规编辑部', 1, 25, 1, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-29 15:19:12', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (26, '000009', 'case', '/showcase.html?Id=000009', '如何合理确定注册资本?', '

某公司注册资本8000万元(认缴期30年),实际运营资金仅200万元。后因合同纠纷负债500万元,法院认定股东恶意设置超长认缴期,判令股东立即补缴。


', NULL, '案例分析组', 1, 26, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-29 15:19:32', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (27, '000009', 'form', '/table.html?Id=000009', '如何合理确定注册资本?', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 27, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-29 15:19:44', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (28, '000010', 'law', '/show.html?Id=000010', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 28, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (29, '000010', 'case', '/showcase.html?Id=000010', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 29, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (30, '000010', 'form', '/table.html?Id=000010', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 30, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (31, '000011', 'law', '/show.html?Id=000011', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 31, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (32, '000011', 'case', '/showcase.html?Id=000011', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 32, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (33, '000011', 'form', '/table.html?Id=000011', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 33, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (34, '000012', 'law', '/show.html?Id=000012', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 34, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (35, '000012', 'case', '/showcase.html?Id=000012', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 35, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (36, '000012', 'form', '/table.html?Id=000012', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 36, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (37, '000013', 'law', '/show.html?Id=000013', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 37, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (38, '000013', 'case', '/showcase.html?Id=000013', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 38, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (39, '000013', 'form', '/table.html?Id=000013', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 39, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (40, '000014', 'law', '/show.html?Id=000014', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 40, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (41, '000014', 'case', '/showcase.html?Id=000014', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 41, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (42, '000014', 'form', '/table.html?Id=000014', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 42, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (43, '000015', 'law', '/show.html?Id=000015', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 43, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (44, '000015', 'case', '/showcase.html?Id=000015', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 44, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (45, '000015', 'form', '/table.html?Id=000015', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 45, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (46, '000016', 'law', '/show.html?Id=000016', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 46, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (47, '000016', 'case', '/showcase.html?Id=000016', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 47, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (48, '000016', 'form', '/table.html?Id=000016', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 48, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (49, '000017', 'law', '/show.html?Id=000017', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 49, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (50, '000017', 'case', '/showcase.html?Id=000017', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 50, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (51, '000017', 'form', '/table.html?Id=000017', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 51, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (52, '000018', 'law', '/show.html?Id=000018', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 52, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (53, '000018', 'case', '/showcase.html?Id=000018', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 53, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (54, '000018', 'form', '/table.html?Id=000018', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 54, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (55, '000019', 'law', '/show.html?Id=000019', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 55, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (56, '000019', 'case', '/showcase.html?Id=000019', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 56, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (57, '000019', 'form', '/table.html?Id=000019', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 57, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (58, '000020', 'law', '/show.html?Id=000020', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 58, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (59, '000020', 'case', '/showcase.html?Id=000020', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 59, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (60, '000020', 'form', '/table.html?Id=000020', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 60, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (61, '000021', 'law', '/show.html?Id=000021', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 61, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (62, '000021', 'case', '/showcase.html?Id=000021', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 62, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (63, '000021', 'form', '/table.html?Id=000021', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 63, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (64, '000022', 'law', '/show.html?Id=000022', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 64, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (65, '000022', 'case', '/showcase.html?Id=000022', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 65, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (66, '000022', 'form', '/table.html?Id=000022', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 66, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (67, '000023', 'law', '/show.html?Id=000023', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 67, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (68, '000023', 'case', '/showcase.html?Id=000023', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 68, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (69, '000023', 'form', '/table.html?Id=000023', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 69, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (70, '000024', 'law', '/show.html?Id=000024', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 70, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (71, '000024', 'case', '/showcase.html?Id=000024', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 71, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (72, '000024', 'form', '/table.html?Id=000024', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 72, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (73, '000025', 'law', '/show.html?Id=000025', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 73, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (74, '000025', 'case', '/showcase.html?Id=000025', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 74, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (75, '000025', 'form', '/table.html?Id=000025', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 75, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (76, '000026', 'law', '/show.html?Id=000026', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 76, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (77, '000026', 'case', '/showcase.html?Id=000026', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 77, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (78, '000026', 'form', '/table.html?Id=000026', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 78, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (79, '000027', 'law', '/show.html?Id=000027', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 79, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (80, '000027', 'case', '/showcase.html?Id=000027', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 80, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (81, '000027', 'form', '/table.html?Id=000027', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 81, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (82, '000028', 'law', '/show.html?Id=000028', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 82, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (83, '000028', 'case', '/showcase.html?Id=000028', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 83, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (84, '000028', 'form', '/table.html?Id=000028', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 84, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (85, '000029', 'law', '/show.html?Id=000029', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 85, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (86, '000029', 'case', '/showcase.html?Id=000029', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 86, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (87, '000029', 'form', '/table.html?Id=000029', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 87, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (88, '000030', 'law', '/show.html?Id=000030', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 88, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (89, '000030', 'case', '/showcase.html?Id=000030', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 89, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (90, '000030', 'form', '/table.html?Id=000030', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 90, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (91, '000031', 'law', '/show.html?Id=000031', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 91, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (92, '000031', 'case', '/showcase.html?Id=000031', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 92, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (93, '000031', 'form', '/table.html?Id=000031', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 93, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (94, '000032', 'law', '/show.html?Id=000032', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 94, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (95, '000032', 'case', '/showcase.html?Id=000032', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 95, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (96, '000032', 'form', '/table.html?Id=000032', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 96, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (97, '000033', 'law', '/show.html?Id=000033', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 97, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (98, '000033', 'case', '/showcase.html?Id=000033', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 98, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (99, '000033', 'form', '/table.html?Id=000033', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 99, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (100, '000034', 'law', '/show.html?Id=000034', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 100, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (101, '000034', 'case', '/showcase.html?Id=000034', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 101, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (102, '000034', 'form', '/table.html?Id=000034', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 102, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (103, '000035', 'law', '/show.html?Id=000035', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 103, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (104, '000035', 'case', '/showcase.html?Id=000035', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 104, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (105, '000035', 'form', '/table.html?Id=000035', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 105, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (106, '000036', 'law', '/show.html?Id=000036', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 106, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (107, '000036', 'case', '/showcase.html?Id=000036', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 107, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (108, '000036', 'form', '/table.html?Id=000036', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 108, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (109, '000037', 'law', '/show.html?Id=000037', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 109, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (110, '000037', 'case', '/showcase.html?Id=000037', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 110, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (111, '000037', 'form', '/table.html?Id=000037', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 111, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (112, '000038', 'law', '/show.html?Id=000038', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 112, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (113, '000038', 'case', '/showcase.html?Id=000038', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 113, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (114, '000038', 'form', '/table.html?Id=000038', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 114, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (115, '000039', 'law', '/show.html?Id=000039', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 115, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (116, '000039', 'case', '/showcase.html?Id=000039', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 116, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (117, '000039', 'form', '/table.html?Id=000039', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 117, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (118, '000040', 'law', '/show.html?Id=000040', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 118, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (119, '000040', 'case', '/showcase.html?Id=000040', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 119, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (120, '000040', 'form', '/table.html?Id=000040', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 120, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (121, '000041', 'law', '/show.html?Id=000041', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 121, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (122, '000041', 'case', '/showcase.html?Id=000041', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 122, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (123, '000041', 'form', '/table.html?Id=000041', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 123, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (124, '000042', 'law', '/show.html?Id=000042', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 124, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (125, '000042', 'case', '/showcase.html?Id=000042', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 125, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (126, '000042', 'form', '/table.html?Id=000042', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 126, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (127, '000043', 'law', '/show.html?Id=000043', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 127, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (128, '000043', 'case', '/showcase.html?Id=000043', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 128, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (129, '000043', 'form', '/table.html?Id=000043', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 129, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (130, '000044', 'law', '/show.html?Id=000044', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 130, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (131, '000044', 'case', '/showcase.html?Id=000044', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 131, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (132, '000044', 'form', '/table.html?Id=000044', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 132, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (133, '000045', 'law', '/show.html?Id=000045', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 133, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (134, '000045', 'case', '/showcase.html?Id=000045', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 134, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (135, '000045', 'form', '/table.html?Id=000045', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 135, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (136, '000046', 'law', '/show.html?Id=000046', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 136, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (137, '000046', 'case', '/showcase.html?Id=000046', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 137, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (138, '000046', 'form', '/table.html?Id=000046', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 138, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (139, '000047', 'law', '/show.html?Id=000047', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 139, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (140, '000047', 'case', '/showcase.html?Id=000047', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 140, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (141, '000047', 'form', '/table.html?Id=000047', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 141, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (142, '000048', 'law', '/show.html?Id=000048', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 142, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (143, '000048', 'case', '/showcase.html?Id=000048', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 143, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (144, '000048', 'form', '/table.html?Id=000048', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 144, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (145, '000049', 'law', '/show.html?Id=000049', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 145, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (146, '000049', 'case', '/showcase.html?Id=000049', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 146, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (147, '000049', 'form', '/table.html?Id=000049', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 147, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (148, '000050', 'law', '/show.html?Id=000050', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 148, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (149, '000050', 'case', '/showcase.html?Id=000050', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 149, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (150, '000050', 'form', '/table.html?Id=000050', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 150, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (151, '000051', 'law', '/show.html?Id=000051', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 151, 1, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:11:40', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (152, '000051', 'case', '/showcase.html?Id=000051', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 152, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (153, '000051', 'form', '/table.html?Id=000051', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 153, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (154, '000052', 'law', '/show.html?Id=000052', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 154, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (155, '000052', 'case', '/showcase.html?Id=000052', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 155, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (156, '000052', 'form', '/table.html?Id=000052', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 156, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (157, '000053', 'law', '/show.html?Id=000053', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 157, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (158, '000053', 'case', '/showcase.html?Id=000053', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 158, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (159, '000053', 'form', '/table.html?Id=000053', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 159, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (160, '000054', 'law', '/show.html?Id=000054', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 160, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (161, '000054', 'case', '/showcase.html?Id=000054', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 161, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (162, '000054', 'form', '/table.html?Id=000054', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 162, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (163, '000055', 'law', '/show.html?Id=000055', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 163, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (164, '000055', 'case', '/showcase.html?Id=000055', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 164, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (165, '000055', 'form', '/table.html?Id=000055', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 165, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (166, '000056', 'law', '/show.html?Id=000056', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 166, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (167, '000056', 'case', '/showcase.html?Id=000056', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 167, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (168, '000056', 'form', '/table.html?Id=000056', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 168, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (169, '000057', 'law', '/show.html?Id=000057', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 169, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (170, '000057', 'case', '/showcase.html?Id=000057', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 170, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (171, '000057', 'form', '/table.html?Id=000057', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 171, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (172, '000058', 'law', '/show.html?Id=000058', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 172, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (173, '000058', 'case', '/showcase.html?Id=000058', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 173, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (174, '000058', 'form', '/table.html?Id=000058', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 174, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (175, '000059', 'law', '/show.html?Id=000059', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 175, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (176, '000059', 'case', '/showcase.html?Id=000059', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 176, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (177, '000059', 'form', '/table.html?Id=000059', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 177, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (178, '000060', 'law', '/show.html?Id=000060', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 178, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (179, '000060', 'case', '/showcase.html?Id=000060', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 179, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (180, '000060', 'form', '/table.html?Id=000060', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 180, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (181, '000061', 'law', '/show.html?Id=000061', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 181, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (182, '000061', 'case', '/showcase.html?Id=000061', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 182, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (183, '000061', 'form', '/table.html?Id=000061', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 183, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (184, '000062', 'law', '/show.html?Id=000062', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 184, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (185, '000062', 'case', '/showcase.html?Id=000062', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 185, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (186, '000062', 'form', '/table.html?Id=000062', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 186, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (187, '000063', 'law', '/show.html?Id=000063', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 187, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (188, '000063', 'case', '/showcase.html?Id=000063', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 188, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (189, '000063', 'form', '/table.html?Id=000063', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 189, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (190, '000064', 'law', '/show.html?Id=000064', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 190, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (191, '000064', 'case', '/showcase.html?Id=000064', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 191, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (192, '000064', 'form', '/table.html?Id=000064', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 192, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (193, '000065', 'law', '/show.html?Id=000065', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 193, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (194, '000065', 'case', '/showcase.html?Id=000065', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 194, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (195, '000065', 'form', '/table.html?Id=000065', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 195, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (196, '000066', 'law', '/show.html?Id=000066', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 196, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (197, '000066', 'case', '/showcase.html?Id=000066', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 197, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (198, '000066', 'form', '/table.html?Id=000066', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 198, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (199, '000067', 'law', '/show.html?Id=000067', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 199, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (200, '000067', 'case', '/showcase.html?Id=000067', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 200, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (201, '000067', 'form', '/table.html?Id=000067', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 201, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (202, '000068', 'law', '/show.html?Id=000068', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 202, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (203, '000068', 'case', '/showcase.html?Id=000068', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 203, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (204, '000068', 'form', '/table.html?Id=000068', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 204, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (205, '000069', 'law', '/show.html?Id=000069', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 205, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (206, '000069', 'case', '/showcase.html?Id=000069', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 206, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (207, '000069', 'form', '/table.html?Id=000069', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 207, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (208, '000070', 'law', '/show.html?Id=000070', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 208, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (209, '000070', 'case', '/showcase.html?Id=000070', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 209, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (210, '000070', 'form', '/table.html?Id=000070', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 210, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (211, '000071', 'law', '/show.html?Id=000071', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 211, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (212, '000071', 'case', '/showcase.html?Id=000071', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 212, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (213, '000071', 'form', '/table.html?Id=000071', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 213, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (214, '000072', 'law', '/show.html?Id=000072', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 214, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (215, '000072', 'case', '/showcase.html?Id=000072', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 215, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (216, '000072', 'form', '/table.html?Id=000072', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 216, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (217, '000073', 'law', '/show.html?Id=000073', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 217, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (218, '000073', 'case', '/showcase.html?Id=000073', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 218, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (219, '000073', 'form', '/table.html?Id=000073', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 219, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (220, '000074', 'law', '/show.html?Id=000074', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 220, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (221, '000074', 'case', '/showcase.html?Id=000074', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 221, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (222, '000074', 'form', '/table.html?Id=000074', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 222, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (223, '000075', 'law', '/show.html?Id=000075', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 223, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (224, '000075', 'case', '/showcase.html?Id=000075', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 224, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (225, '000075', 'form', '/table.html?Id=000075', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 225, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (226, '000076', 'law', '/show.html?Id=000076', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 226, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (227, '000076', 'case', '/showcase.html?Id=000076', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 227, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (228, '000076', 'form', '/table.html?Id=000076', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 228, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (229, '000077', 'law', '/show.html?Id=000077', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 229, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (230, '000077', 'case', '/showcase.html?Id=000077', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 230, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (231, '000077', 'form', '/table.html?Id=000077', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 231, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (232, '000078', 'law', '/show.html?Id=000078', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 232, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (233, '000078', 'case', '/showcase.html?Id=000078', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 233, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (234, '000078', 'form', '/table.html?Id=000078', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 234, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (235, '000079', 'law', '/show.html?Id=000079', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 235, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (236, '000079', 'case', '/showcase.html?Id=000079', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 236, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (237, '000079', 'form', '/table.html?Id=000079', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 237, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (238, '000080', 'law', '/show.html?Id=000080', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 238, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (239, '000080', 'case', '/showcase.html?Id=000080', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 239, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (240, '000080', 'form', '/table.html?Id=000080', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 240, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (241, '000081', 'law', '/show.html?Id=000081', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 241, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (242, '000081', 'case', '/showcase.html?Id=000081', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 242, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (243, '000081', 'form', '/table.html?Id=000081', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 243, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (244, '000082', 'law', '/show.html?Id=000082', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 244, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (245, '000082', 'case', '/showcase.html?Id=000082', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 245, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (246, '000082', 'form', '/table.html?Id=000082', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 246, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (247, '000083', 'law', '/show.html?Id=000083', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 247, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (248, '000083', 'case', '/showcase.html?Id=000083', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 248, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (249, '000083', 'form', '/table.html?Id=000083', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 249, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (250, '000084', 'law', '/show.html?Id=000084', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 250, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (251, '000084', 'case', '/showcase.html?Id=000084', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 251, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (252, '000084', 'form', '/table.html?Id=000084', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 252, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (253, '000085', 'law', '/show.html?Id=000085', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 253, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (254, '000085', 'case', '/showcase.html?Id=000085', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 254, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (255, '000085', 'form', '/table.html?Id=000085', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 255, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (256, '000086', 'law', '/show.html?Id=000086', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 256, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (257, '000086', 'case', '/showcase.html?Id=000086', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 257, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (258, '000086', 'form', '/table.html?Id=000086', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 258, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (259, '000087', 'law', '/show.html?Id=000087', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 259, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (260, '000087', 'case', '/showcase.html?Id=000087', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 260, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (261, '000087', 'form', '/table.html?Id=000087', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 261, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (262, '000088', 'law', '/show.html?Id=000088', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 262, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (263, '000088', 'case', '/showcase.html?Id=000088', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 263, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (264, '000088', 'form', '/table.html?Id=000088', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 264, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (265, '000089', 'law', '/show.html?Id=000089', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 265, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (266, '000089', 'case', '/showcase.html?Id=000089', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 266, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (267, '000089', 'form', '/table.html?Id=000089', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 267, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (268, '000090', 'law', '/show.html?Id=000090', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 268, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (269, '000090', 'case', '/showcase.html?Id=000090', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 269, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (270, '000090', 'form', '/table.html?Id=000090', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 270, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (271, '000091', 'law', '/show.html?Id=000091', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 271, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (272, '000091', 'case', '/showcase.html?Id=000091', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 272, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (273, '000091', 'form', '/table.html?Id=000091', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 273, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (274, '000092', 'law', '/show.html?Id=000092', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 274, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (275, '000092', 'case', '/showcase.html?Id=000092', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 275, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (276, '000092', 'form', '/table.html?Id=000092', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 276, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (277, '000093', 'law', '/show.html?Id=000093', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 277, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (278, '000093', 'case', '/showcase.html?Id=000093', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 278, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (279, '000093', 'form', '/table.html?Id=000093', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 279, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (280, '000094', 'law', '/show.html?Id=000094', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 280, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (281, '000094', 'case', '/showcase.html?Id=000094', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 281, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (282, '000094', 'form', '/table.html?Id=000094', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 282, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (283, '000095', 'law', '/show.html?Id=000095', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 283, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (284, '000095', 'case', '/showcase.html?Id=000095', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 284, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (285, '000095', 'form', '/table.html?Id=000095', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 285, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (286, '000096', 'law', '/show.html?Id=000096', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 286, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (287, '000096', 'case', '/showcase.html?Id=000096', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 287, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (288, '000096', 'form', '/table.html?Id=000096', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 288, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (289, '000097', 'law', '/show.html?Id=000097', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 289, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (290, '000097', 'case', '/showcase.html?Id=000097', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 290, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (291, '000097', 'form', '/table.html?Id=000097', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 291, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (292, '000098', 'law', '/show.html?Id=000098', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 292, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (293, '000098', 'case', '/showcase.html?Id=000098', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 293, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (294, '000098', 'form', '/table.html?Id=000098', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 294, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (295, '000099', 'law', '/show.html?Id=000099', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 295, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (296, '000099', 'case', '/showcase.html?Id=000099', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 296, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (297, '000099', 'form', '/table.html?Id=000099', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 297, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (298, '000100', 'law', '/show.html?Id=000100', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 298, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (299, '000100', 'case', '/showcase.html?Id=000100', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 299, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (300, '000100', 'form', '/table.html?Id=000100', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 300, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (301, '000101', 'law', '/show.html?Id=000101', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 301, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (302, '000101', 'case', '/showcase.html?Id=000101', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 302, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (303, '000101', 'form', '/table.html?Id=000101', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 303, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (304, '000102', 'law', '/show.html?Id=000102', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 304, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (305, '000102', 'case', '/showcase.html?Id=000102', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 305, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (306, '000102', 'form', '/table.html?Id=000102', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 306, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (307, '000103', 'law', '/show.html?Id=000103', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 307, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (308, '000103', 'case', '/showcase.html?Id=000103', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 308, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (309, '000103', 'form', '/table.html?Id=000103', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 309, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (310, '000104', 'law', '/show.html?Id=000104', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 310, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (311, '000104', 'case', '/showcase.html?Id=000104', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 311, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (312, '000104', 'form', '/table.html?Id=000104', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 312, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (313, '000105', 'law', '/show.html?Id=000105', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 313, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (314, '000105', 'case', '/showcase.html?Id=000105', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 314, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (315, '000105', 'form', '/table.html?Id=000105', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 315, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (316, '000106', 'law', '/show.html?Id=000106', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 316, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (317, '000106', 'case', '/showcase.html?Id=000106', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 317, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (318, '000106', 'form', '/table.html?Id=000106', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 318, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (319, '000107', 'law', '/show.html?Id=000107', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 319, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (320, '000107', 'case', '/showcase.html?Id=000107', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 320, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (321, '000107', 'form', '/table.html?Id=000107', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 321, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (322, '000108', 'law', '/show.html?Id=000108', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 322, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (323, '000108', 'case', '/showcase.html?Id=000108', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 323, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (324, '000108', 'form', '/table.html?Id=000108', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 324, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (325, '000109', 'law', '/show.html?Id=000109', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 325, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (326, '000109', 'case', '/showcase.html?Id=000109', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 326, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (327, '000109', 'form', '/table.html?Id=000109', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 327, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (328, '000110', 'law', '/show.html?Id=000110', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 328, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (329, '000110', 'case', '/showcase.html?Id=000110', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 329, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (330, '000110', 'form', '/table.html?Id=000110', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 330, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (331, '000111', 'law', '/show.html?Id=000111', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 331, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (332, '000111', 'case', '/showcase.html?Id=000111', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 332, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (333, '000111', 'form', '/table.html?Id=000111', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 333, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (334, '000112', 'law', '/show.html?Id=000112', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 334, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (335, '000112', 'case', '/showcase.html?Id=000112', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 335, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (336, '000112', 'form', '/table.html?Id=000112', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 336, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (337, '000113', 'law', '/show.html?Id=000113', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 337, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (338, '000113', 'case', '/showcase.html?Id=000113', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 338, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (339, '000113', 'form', '/table.html?Id=000113', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 339, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (340, '000114', 'law', '/show.html?Id=000114', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 340, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (341, '000114', 'case', '/showcase.html?Id=000114', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 341, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (342, '000114', 'form', '/table.html?Id=000114', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 342, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (343, '000115', 'law', '/show.html?Id=000115', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 343, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (344, '000115', 'case', '/showcase.html?Id=000115', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 344, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (345, '000115', 'form', '/table.html?Id=000115', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 345, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (346, '000116', 'law', '/show.html?Id=000116', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 346, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (347, '000116', 'case', '/showcase.html?Id=000116', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 347, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (348, '000116', 'form', '/table.html?Id=000116', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 348, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (349, '000117', 'law', '/show.html?Id=000117', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 349, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (350, '000117', 'case', '/showcase.html?Id=000117', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 350, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (351, '000117', 'form', '/table.html?Id=000117', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 351, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (352, '000118', 'law', '/show.html?Id=000118', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 352, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (353, '000118', 'case', '/showcase.html?Id=000118', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 353, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (354, '000118', 'form', '/table.html?Id=000118', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 354, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (355, '000119', 'law', '/show.html?Id=000119', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 355, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (356, '000119', 'case', '/showcase.html?Id=000119', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 356, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (357, '000119', 'form', '/table.html?Id=000119', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 357, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (358, '000120', 'law', '/show.html?Id=000120', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 358, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (359, '000120', 'case', '/showcase.html?Id=000120', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 359, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (360, '000120', 'form', '/table.html?Id=000120', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 360, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (361, '000121', 'law', '/show.html?Id=000121', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 361, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (362, '000121', 'case', '/showcase.html?Id=000121', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 362, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (363, '000121', 'form', '/table.html?Id=000121', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 363, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (364, '000122', 'law', '/show.html?Id=000122', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 364, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (365, '000122', 'case', '/showcase.html?Id=000122', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 365, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (366, '000122', 'form', '/table.html?Id=000122', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 366, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (367, '000123', 'law', '/show.html?Id=000123', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 367, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (368, '000123', 'case', '/showcase.html?Id=000123', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 368, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (369, '000123', 'form', '/table.html?Id=000123', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 369, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (370, '000124', 'law', '/show.html?Id=000124', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 370, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (371, '000124', 'case', '/showcase.html?Id=000124', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 371, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (372, '000124', 'form', '/table.html?Id=000124', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 372, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (373, '000125', 'law', '/show.html?Id=000125', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 373, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (374, '000125', 'case', '/showcase.html?Id=000125', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 374, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (375, '000125', 'form', '/table.html?Id=000125', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 375, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (376, '000126', 'law', '/show.html?Id=000126', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 376, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (377, '000126', 'case', '/showcase.html?Id=000126', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 377, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (378, '000126', 'form', '/table.html?Id=000126', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 378, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (379, '000127', 'law', '/show.html?Id=000127', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 379, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (380, '000127', 'case', '/showcase.html?Id=000127', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 380, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (381, '000127', 'form', '/table.html?Id=000127', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 381, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (382, '000128', 'law', '/show.html?Id=000128', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 382, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (383, '000128', 'case', '/showcase.html?Id=000128', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 383, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (384, '000128', 'form', '/table.html?Id=000128', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 384, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (385, '000129', 'law', '/show.html?Id=000129', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 385, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (386, '000129', 'case', '/showcase.html?Id=000129', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 386, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (387, '000129', 'form', '/table.html?Id=000129', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 387, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (388, '000130', 'law', '/show.html?Id=000130', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 388, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (389, '000130', 'case', '/showcase.html?Id=000130', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 389, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (390, '000130', 'form', '/table.html?Id=000130', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 390, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (391, '000131', 'law', '/show.html?Id=000131', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 391, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (392, '000131', 'case', '/showcase.html?Id=000131', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 392, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (393, '000131', 'form', '/table.html?Id=000131', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 393, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (394, '000132', 'law', '/show.html?Id=000132', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 394, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (395, '000132', 'case', '/showcase.html?Id=000132', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 395, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (396, '000132', 'form', '/table.html?Id=000132', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 396, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (397, '000133', 'law', '/show.html?Id=000133', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 397, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (398, '000133', 'case', '/showcase.html?Id=000133', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 398, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (399, '000133', 'form', '/table.html?Id=000133', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 399, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (400, '000134', 'law', '/show.html?Id=000134', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 400, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (401, '000134', 'case', '/showcase.html?Id=000134', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 401, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (402, '000134', 'form', '/table.html?Id=000134', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 402, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (403, '000135', 'law', '/show.html?Id=000135', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 403, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (404, '000135', 'case', '/showcase.html?Id=000135', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 404, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (405, '000135', 'form', '/table.html?Id=000135', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 405, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (406, '000136', 'law', '/show.html?Id=000136', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 406, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (407, '000136', 'case', '/showcase.html?Id=000136', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 407, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (408, '000136', 'form', '/table.html?Id=000136', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 408, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (409, '000137', 'law', '/show.html?Id=000137', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 409, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (410, '000137', 'case', '/showcase.html?Id=000137', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 410, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (411, '000137', 'form', '/table.html?Id=000137', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 411, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (412, '000138', 'law', '/show.html?Id=000138', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 412, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (413, '000138', 'case', '/showcase.html?Id=000138', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 413, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (414, '000138', 'form', '/table.html?Id=000138', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 414, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (415, '000139', 'law', '/show.html?Id=000139', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 415, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (416, '000139', 'case', '/showcase.html?Id=000139', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 416, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (417, '000139', 'form', '/table.html?Id=000139', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 417, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (418, '000140', 'law', '/show.html?Id=000140', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 418, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (419, '000140', 'case', '/showcase.html?Id=000140', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 419, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (420, '000140', 'form', '/table.html?Id=000140', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 420, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (421, '000141', 'law', '/show.html?Id=000141', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 421, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (422, '000141', 'case', '/showcase.html?Id=000141', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 422, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (423, '000141', 'form', '/table.html?Id=000141', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 423, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (424, '000142', 'law', '/show.html?Id=000142', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 424, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (425, '000142', 'case', '/showcase.html?Id=000142', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 425, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (426, '000142', 'form', '/table.html?Id=000142', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 426, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (427, '000143', 'law', '/show.html?Id=000143', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 427, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (428, '000143', 'case', '/showcase.html?Id=000143', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 428, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (429, '000143', 'form', '/table.html?Id=000143', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 429, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (430, '000144', 'law', '/show.html?Id=000144', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 430, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (431, '000144', 'case', '/showcase.html?Id=000144', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 431, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (432, '000144', 'form', '/table.html?Id=000144', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 432, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (433, '000145', 'law', '/show.html?Id=000145', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 433, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (434, '000145', 'case', '/showcase.html?Id=000145', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 434, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (435, '000145', 'form', '/table.html?Id=000145', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 435, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (436, '000146', 'law', '/show.html?Id=000146', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 436, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (437, '000146', 'case', '/showcase.html?Id=000146', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 437, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (438, '000146', 'form', '/table.html?Id=000146', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 438, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (439, '000147', 'law', '/show.html?Id=000147', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 439, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (440, '000147', 'case', '/showcase.html?Id=000147', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 440, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (441, '000147', 'form', '/table.html?Id=000147', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 441, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (442, '000148', 'law', '/show.html?Id=000148', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 442, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (443, '000148', 'case', '/showcase.html?Id=000148', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 443, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (444, '000148', 'form', '/table.html?Id=000148', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 444, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (445, '000149', 'law', '/show.html?Id=000149', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 445, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (446, '000149', 'case', '/showcase.html?Id=000149', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 446, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (447, '000149', 'form', '/table.html?Id=000149', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 447, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (448, '000150', 'law', '/show.html?Id=000150', '劳动法第四十一条解释', '

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

', NULL, '法律法规编辑部', 1, 448, 0, '劳动法,工作时间,加班', '本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (449, '000150', 'case', '/showcase.html?Id=000150', '某公司劳资纠纷典型案例', '

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

', NULL, '案例分析组', 1, 449, 0, '劳资纠纷,加班费,劳动仲裁', '典型劳资纠纷案例分析及处理结果', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); +INSERT INTO `html_pages` VALUES (450, '000150', 'form', '/table.html?Id=000150', '劳动仲裁申请表', '

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

', NULL, '表单管理员', 1, 450, 0, '劳动仲裁,申请表,劳动争议', '劳动争议仲裁申请表格及填写说明', '2025-05-28 22:07:28', '2025-05-28 22:07:28', '[]'); + +-- ---------------------------- +-- Table structure for message_system +-- ---------------------------- +DROP TABLE IF EXISTS `message_system`; +CREATE TABLE `message_system` ( + `message_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `message_title` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '标题', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `send_mode` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发送方式(0平台 1手机号 2 邮箱)', + `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '号码', + `message_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '消息内容', + `message_recipient` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '接收人', + `message_status` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '消息状态(0未读 1已读)', + `message_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '消息类型', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`message_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of message_system +-- ---------------------------- + +-- ---------------------------- +-- Table structure for message_template +-- ---------------------------- +DROP TABLE IF EXISTS `message_template`; +CREATE TABLE `message_template` ( + `template_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `template_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '模版名称', + `template_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '模版CODE', + `template_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '模版类型', + `template_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '模版内容', + `template_variable` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '变量属性', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`template_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '模版表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of message_template +-- ---------------------------- + +-- ---------------------------- +-- Table structure for message_variable +-- ---------------------------- +DROP TABLE IF EXISTS `message_variable`; +CREATE TABLE `message_variable` ( + `variable_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `variable_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '变量名称', + `variable_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '变量类型', + `variable_content` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '变量内容', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`variable_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '变量表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of message_variable +-- ---------------------------- + +-- ---------------------------- +-- Table structure for oauth_user +-- ---------------------------- +DROP TABLE IF EXISTS `oauth_user`; +CREATE TABLE `oauth_user` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', + `uuid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '第三方系统的唯一ID,详细解释请参考:名词解释', + `user_id` bigint NOT NULL COMMENT '用户ID', + `source` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '第三方用户来源,可选值:GITHUB、GITEE、QQ,更多请参考:AuthDefaultSource.java(opens new window)', + `access_token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户的授权令牌', + `expire_in` int NULL DEFAULT NULL COMMENT '第三方用户的授权令牌的有效期,部分平台可能没有', + `refresh_token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '刷新令牌,部分平台可能没有', + `open_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '第三方用户的 open id,部分平台可能没有', + `uid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '第三方用户的 ID,部分平台可能没有', + `access_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '个别平台的授权信息,部分平台可能没有', + `union_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '第三方用户的 union id,部分平台可能没有', + `scope` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '第三方用户授予的权限,部分平台可能没有', + `token_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '个别平台的授权信息,部分平台可能没有', + `id_token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'id token,部分平台可能没有', + `mac_algorithm` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '小米平台用户的附带属性,部分平台可能没有', + `mac_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '小米平台用户的附带属性,部分平台可能没有', + `code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户的授权code,部分平台可能没有', + `oauth_token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'Twitter平台用户的附带属性,部分平台可能没有', + `oauth_token_secret` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'Twitter平台用户的附带属性,部分平台可能没有', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '第三方登录' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of oauth_user +-- ---------------------------- + +-- ---------------------------- +-- Table structure for online_mb +-- ---------------------------- +DROP TABLE IF EXISTS `online_mb`; +CREATE TABLE `online_mb` ( + `mb_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `tag` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '标签名', + `tag_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '标签id', + `parameter_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '参数类型', + `result_map` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '结果类型', + `sql_text` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'sql语句', + `path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '请求路径', + `method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '请求方式', + `result_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '响应类型', + `actuator` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '执行器', + `user_id` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否需要userId', + `dept_id` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否需要deptId', + `permission_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '许可类型', + `permission_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '许可值', + `del_flag` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)', + PRIMARY KEY (`mb_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '在线接口' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of online_mb +-- ---------------------------- + +-- ---------------------------- +-- Table structure for pay_invoice +-- ---------------------------- +DROP TABLE IF EXISTS `pay_invoice`; +CREATE TABLE `pay_invoice` ( + `invoice_id` bigint NOT NULL AUTO_INCREMENT COMMENT '发票id', + `order_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '订单号', + `invoice_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发票类型', + `invoice_header` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发票抬头', + `invoice_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '纳税人识别号', + `invoice_phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '收票人手机号', + `invoice_email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '收票人邮箱', + `invoice_remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发票备注', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`invoice_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '发票' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of pay_invoice +-- ---------------------------- + +-- ---------------------------- +-- Table structure for pay_order +-- ---------------------------- +DROP TABLE IF EXISTS `pay_order`; +CREATE TABLE `pay_order` ( + `order_id` bigint NOT NULL AUTO_INCREMENT COMMENT '订单id', + `order_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '订单号', + `third_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '第三方订单号', + `order_status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '订单状态', + `total_amount` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '订单总金额', + `actual_amount` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '实际支付金额', + `order_content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '订单内容', + `order_message` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '负载信息', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`order_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '订单' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of pay_order +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_blob_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_blob_triggers`; +CREATE TABLE `qrtz_blob_triggers` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键', + `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键', + `blob_data` blob NULL COMMENT '存放持久化Trigger对象', + PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, + CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Blob类型的触发器表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_blob_triggers +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_calendars +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_calendars`; +CREATE TABLE `qrtz_calendars` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `calendar_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '日历名称', + `calendar` blob NOT NULL COMMENT '存放持久化calendar对象', + PRIMARY KEY (`sched_name`, `calendar_name`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '日历信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_calendars +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_cron_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_cron_triggers`; +CREATE TABLE `qrtz_cron_triggers` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键', + `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键', + `cron_expression` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'cron表达式', + `time_zone_id` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '时区', + PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, + CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Cron类型的触发器表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_cron_triggers +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_fired_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_fired_triggers`; +CREATE TABLE `qrtz_fired_triggers` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `entry_id` varchar(95) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度器实例id', + `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键', + `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键', + `instance_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度器实例名', + `fired_time` bigint NOT NULL COMMENT '触发的时间', + `sched_time` bigint NOT NULL COMMENT '定时器制定的时间', + `priority` int NOT NULL COMMENT '优先级', + `state` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '状态', + `job_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '任务名称', + `job_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '任务组名', + `is_nonconcurrent` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否并发', + `requests_recovery` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '是否接受恢复执行', + PRIMARY KEY (`sched_name`, `entry_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '已触发的触发器表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_fired_triggers +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_job_details +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_job_details`; +CREATE TABLE `qrtz_job_details` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `job_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '任务名称', + `job_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '任务组名', + `description` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '相关介绍', + `job_class_name` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '执行任务类名称', + `is_durable` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '是否持久化', + `is_nonconcurrent` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '是否并发', + `is_update_data` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '是否更新数据', + `requests_recovery` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '是否接受恢复执行', + `job_data` blob NULL COMMENT '存放持久化job对象', + PRIMARY KEY (`sched_name`, `job_name`, `job_group`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '任务详细信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_job_details +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_locks +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_locks`; +CREATE TABLE `qrtz_locks` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `lock_name` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '悲观锁名称', + PRIMARY KEY (`sched_name`, `lock_name`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '存储的悲观锁信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_locks +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_paused_trigger_grps +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`; +CREATE TABLE `qrtz_paused_trigger_grps` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键', + PRIMARY KEY (`sched_name`, `trigger_group`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '暂停的触发器表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_paused_trigger_grps +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_scheduler_state +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_scheduler_state`; +CREATE TABLE `qrtz_scheduler_state` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `instance_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '实例名称', + `last_checkin_time` bigint NOT NULL COMMENT '上次检查时间', + `checkin_interval` bigint NOT NULL COMMENT '检查间隔时间', + PRIMARY KEY (`sched_name`, `instance_name`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '调度器状态表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_scheduler_state +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_simple_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_simple_triggers`; +CREATE TABLE `qrtz_simple_triggers` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键', + `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键', + `repeat_count` bigint NOT NULL COMMENT '重复的次数统计', + `repeat_interval` bigint NOT NULL COMMENT '重复的间隔时间', + `times_triggered` bigint NOT NULL COMMENT '已经触发的次数', + PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, + CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '简单触发器的信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_simple_triggers +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_simprop_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_simprop_triggers`; +CREATE TABLE `qrtz_simprop_triggers` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键', + `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键', + `str_prop_1` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'String类型的trigger的第一个参数', + `str_prop_2` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'String类型的trigger的第二个参数', + `str_prop_3` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'String类型的trigger的第三个参数', + `int_prop_1` int NULL DEFAULT NULL COMMENT 'int类型的trigger的第一个参数', + `int_prop_2` int NULL DEFAULT NULL COMMENT 'int类型的trigger的第二个参数', + `long_prop_1` bigint NULL DEFAULT NULL COMMENT 'long类型的trigger的第一个参数', + `long_prop_2` bigint NULL DEFAULT NULL COMMENT 'long类型的trigger的第二个参数', + `dec_prop_1` decimal(13, 4) NULL DEFAULT NULL COMMENT 'decimal类型的trigger的第一个参数', + `dec_prop_2` decimal(13, 4) NULL DEFAULT NULL COMMENT 'decimal类型的trigger的第二个参数', + `bool_prop_1` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'Boolean类型的trigger的第一个参数', + `bool_prop_2` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'Boolean类型的trigger的第二个参数', + PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, + CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '同步机制的行锁表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_simprop_triggers +-- ---------------------------- + +-- ---------------------------- +-- Table structure for qrtz_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_triggers`; +CREATE TABLE `qrtz_triggers` ( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调度名称', + `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '触发器的名字', + `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '触发器所属组的名字', + `job_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_job_details表job_name的外键', + `job_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'qrtz_job_details表job_group的外键', + `description` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '相关介绍', + `next_fire_time` bigint NULL DEFAULT NULL COMMENT '上一次触发时间(毫秒)', + `prev_fire_time` bigint NULL DEFAULT NULL COMMENT '下一次触发时间(默认为-1表示不触发)', + `priority` int NULL DEFAULT NULL COMMENT '优先级', + `trigger_state` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '触发器状态', + `trigger_type` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '触发器的类型', + `start_time` bigint NOT NULL COMMENT '开始时间', + `end_time` bigint NULL DEFAULT NULL COMMENT '结束时间', + `calendar_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '日程表名称', + `misfire_instr` smallint NULL DEFAULT NULL COMMENT '补偿执行的策略', + `job_data` blob NULL COMMENT '存放持久化job对象', + PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, + INDEX `sched_name`(`sched_name` ASC, `job_name` ASC, `job_group` ASC) USING BTREE, + CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `job_name`, `job_group`) REFERENCES `qrtz_job_details` (`sched_name`, `job_name`, `job_group`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '触发器详细信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of qrtz_triggers +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_config +-- ---------------------------- +DROP TABLE IF EXISTS `sys_config`; +CREATE TABLE `sys_config` ( + `config_id` int NOT NULL AUTO_INCREMENT COMMENT '参数主键', + `config_name` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '参数名称', + `config_key` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '参数键名', + `config_value` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '参数键值', + `config_type` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT 'N' COMMENT '系统内置(Y是 N否)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`config_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 106 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '参数配置表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_config +-- ---------------------------- +INSERT INTO `sys_config` VALUES (1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-green', 'Y', 'admin', '2023-04-13 20:46:20', 'admin', '2023-04-22 00:45:19', '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow'); +INSERT INTO `sys_config` VALUES (2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', '2023-04-13 20:46:20', '', NULL, '初始化密码 123456'); +INSERT INTO `sys_config` VALUES (3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-light', 'Y', 'admin', '2023-04-13 20:46:20', 'admin', '2023-04-22 00:45:25', '深色主题theme-dark,浅色主题theme-light'); +INSERT INTO `sys_config` VALUES (4, '账号自助-验证码开关', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', '2023-04-13 20:46:20', '', NULL, '是否开启验证码功能(true开启,false关闭)'); +INSERT INTO `sys_config` VALUES (5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'true', 'Y', 'admin', '2023-04-13 20:46:20', 'admin', '2023-04-22 00:41:41', '是否开启注册用户功能(true开启,false关闭)'); +INSERT INTO `sys_config` VALUES (100, '主题颜色', 'sys.index.theme', '#11A983', 'Y', 'admin', '2023-04-22 00:57:18', 'admin', '2023-04-22 00:58:23', NULL); +INSERT INTO `sys_config` VALUES (101, '开启TopNav', 'sys.index.topNav', 'false', 'Y', 'admin', '2023-04-22 00:58:59', '', NULL, NULL); +INSERT INTO `sys_config` VALUES (102, '开启Tags-Views', 'sys.index.tagsView', 'true', 'Y', 'admin', '2023-04-22 00:59:40', '', NULL, NULL); +INSERT INTO `sys_config` VALUES (103, '显示Logo', 'sys.index.sidebarLogo', 'true', 'Y', 'admin', '2023-04-22 01:00:20', '', NULL, NULL); +INSERT INTO `sys_config` VALUES (104, '固定Header', 'sys.index.fixedHeader', 'true', 'Y', 'admin', '2023-04-22 01:00:53', '', NULL, NULL); +INSERT INTO `sys_config` VALUES (105, '动态标题', 'sys.index.dynamicTitle', 'true', 'Y', 'admin', '2023-04-22 01:01:26', 'admin', '2023-04-22 01:01:41', NULL); + +-- ---------------------------- +-- Table structure for sys_deploy_form +-- ---------------------------- +DROP TABLE IF EXISTS `sys_deploy_form`; +CREATE TABLE `sys_deploy_form` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `form_id` bigint NULL DEFAULT NULL COMMENT '表单主键', + `deploy_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '流程实例主键', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 9623 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '流程实例关联表单' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_deploy_form +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_dept +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dept`; +CREATE TABLE `sys_dept` ( + `dept_id` bigint NOT NULL AUTO_INCREMENT COMMENT '部门id', + `parent_id` bigint NULL DEFAULT 0 COMMENT '父部门id', + `ancestors` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '祖级列表', + `dept_name` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '部门名称', + `order_num` int NULL DEFAULT 0 COMMENT '显示顺序', + `leader` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '负责人', + `phone` varchar(11) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系电话', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '邮箱', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '部门状态(0正常 1停用)', + `del_flag` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`dept_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 201 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '部门表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_dept +-- ---------------------------- +INSERT INTO `sys_dept` VALUES (100, 0, '0', '博越科技', 0, '博越', '15888888888', 'boyue@qq.com', '0', '0', 'admin', '2025-05-26 17:20:06', 'admin', '2025-05-29 08:42:28'); +INSERT INTO `sys_dept` VALUES (101, 100, '0,100', '淮安市', 1, '博越', '15888888888', 'boyue@qq.com', '0', '0', 'admin', '2025-05-26 17:20:06', 'admin', '2025-05-29 08:42:59'); +INSERT INTO `sys_dept` VALUES (102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2025-05-26 17:20:06', '', NULL); +INSERT INTO `sys_dept` VALUES (103, 101, '0,100,101', '管理', 2, '管理', '15888888888', 'sfj@qq.com', '0', '0', 'admin', '2025-05-26 17:20:06', 'admin', '2025-05-29 08:44:34'); +INSERT INTO `sys_dept` VALUES (104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2025-05-26 17:20:06', '', NULL); +INSERT INTO `sys_dept` VALUES (105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2025-05-26 17:20:06', '', NULL); +INSERT INTO `sys_dept` VALUES (106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2025-05-26 17:20:06', '', NULL); +INSERT INTO `sys_dept` VALUES (107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2025-05-26 17:20:06', '', NULL); +INSERT INTO `sys_dept` VALUES (108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2025-05-26 17:20:06', '', NULL); +INSERT INTO `sys_dept` VALUES (109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2025-05-26 17:20:06', '', NULL); +INSERT INTO `sys_dept` VALUES (200, 101, '0,100,101', '司法局', 3, NULL, NULL, NULL, '0', '0', 'admin', '2025-05-29 08:44:51', '', NULL); + +-- ---------------------------- +-- Table structure for sys_dict_data +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dict_data`; +CREATE TABLE `sys_dict_data` ( + `dict_code` bigint NOT NULL AUTO_INCREMENT COMMENT '字典编码', + `dict_sort` int NULL DEFAULT 0 COMMENT '字典排序', + `dict_label` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '字典标签', + `dict_value` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '字典键值', + `dict_type` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '字典类型', + `css_class` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '样式属性(其他样式扩展)', + `list_class` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '表格回显样式', + `is_default` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT 'N' COMMENT '是否默认(Y是 N否)', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '状态(0正常 1停用)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`dict_code`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 160 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '字典数据表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_dict_data +-- ---------------------------- +INSERT INTO `sys_dict_data` VALUES (1, 1, '男', '0', 'sys_user_sex', '', '', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '性别男'); +INSERT INTO `sys_dict_data` VALUES (2, 2, '女', '1', 'sys_user_sex', '', '', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '性别女'); +INSERT INTO `sys_dict_data` VALUES (3, 3, '未知', '2', 'sys_user_sex', '', '', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '性别未知'); +INSERT INTO `sys_dict_data` VALUES (4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '显示菜单'); +INSERT INTO `sys_dict_data` VALUES (5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '隐藏菜单'); +INSERT INTO `sys_dict_data` VALUES (6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '正常状态'); +INSERT INTO `sys_dict_data` VALUES (7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '停用状态'); +INSERT INTO `sys_dict_data` VALUES (8, 1, '正常', '0', 'sys_job_status', '', 'primary', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '正常状态'); +INSERT INTO `sys_dict_data` VALUES (9, 2, '暂停', '1', 'sys_job_status', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '停用状态'); +INSERT INTO `sys_dict_data` VALUES (10, 1, '默认', 'DEFAULT', 'sys_job_group', '', '', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '默认分组'); +INSERT INTO `sys_dict_data` VALUES (11, 2, '系统', 'SYSTEM', 'sys_job_group', '', '', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '系统分组'); +INSERT INTO `sys_dict_data` VALUES (12, 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '系统默认是'); +INSERT INTO `sys_dict_data` VALUES (13, 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '系统默认否'); +INSERT INTO `sys_dict_data` VALUES (14, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '通知'); +INSERT INTO `sys_dict_data` VALUES (15, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '公告'); +INSERT INTO `sys_dict_data` VALUES (16, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '正常状态'); +INSERT INTO `sys_dict_data` VALUES (17, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '关闭状态'); +INSERT INTO `sys_dict_data` VALUES (18, 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '其他操作'); +INSERT INTO `sys_dict_data` VALUES (19, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '新增操作'); +INSERT INTO `sys_dict_data` VALUES (20, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '修改操作'); +INSERT INTO `sys_dict_data` VALUES (21, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '删除操作'); +INSERT INTO `sys_dict_data` VALUES (22, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '授权操作'); +INSERT INTO `sys_dict_data` VALUES (23, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '导出操作'); +INSERT INTO `sys_dict_data` VALUES (24, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '导入操作'); +INSERT INTO `sys_dict_data` VALUES (25, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '强退操作'); +INSERT INTO `sys_dict_data` VALUES (26, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '生成操作'); +INSERT INTO `sys_dict_data` VALUES (27, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '清空操作'); +INSERT INTO `sys_dict_data` VALUES (28, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '正常状态'); +INSERT INTO `sys_dict_data` VALUES (29, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '停用状态'); +INSERT INTO `sys_dict_data` VALUES (100, 0, 'POST', 'POST', 'online_api_method', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:23:23', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (101, 0, 'GET', 'GET', 'online_api_method', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:23:30', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (102, 0, 'PUT', 'PUT', 'online_api_method', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:23:37', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (103, 0, 'DELETE', 'DELETE', 'online_api_method', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:23:49', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (104, 0, 'select', 'select', 'online_api_tag', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:24:06', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (105, 0, 'update', 'update', 'online_api_tag', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:24:12', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (106, 0, 'insert', 'insert', 'online_api_tag', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:24:18', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (107, 0, 'delete', 'delete', 'online_api_tag', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:24:26', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (108, 0, 'selectList', 'selectList', 'online_api_actuator', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:25:00', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (109, 0, 'insert', 'insert', 'online_api_actuator', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:25:05', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (110, 0, 'selectOne', 'selectOne', 'online_api_actuator', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:25:11', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (111, 0, 'update', 'update', 'online_api_actuator', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:25:16', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (112, 0, 'delete', 'delete', 'online_api_actuator', NULL, 'default', 'N', '0', 'admin', '2024-02-21 18:25:21', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (142, 0, '未读', '0', 'message_status', NULL, 'primary', 'N', '0', 'xl', '2024-12-21 15:13:02', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (143, 1, '已读', '1', 'message_status', NULL, 'success', 'N', '0', 'xl', '2024-12-21 15:13:15', 'xl', '2024-12-21 15:13:22', NULL); +INSERT INTO `sys_dict_data` VALUES (144, 0, '平台', '0', 'send_mode', NULL, 'primary', 'N', '0', 'xl', '2024-12-25 09:40:01', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (145, 1, '短信', '1', 'send_mode', NULL, 'success', 'N', '0', 'xl', '2024-12-25 09:40:16', 'xl', '2025-01-01 10:12:07', NULL); +INSERT INTO `sys_dict_data` VALUES (146, 2, '邮件', '2', 'send_mode', NULL, 'warning', 'N', '0', 'xl', '2024-12-25 09:40:28', 'xl', '2025-01-01 10:12:14', NULL); +INSERT INTO `sys_dict_data` VALUES (147, 0, '验证码', '0', 'template_type', NULL, 'primary', 'N', '0', 'xl', '2025-01-03 09:22:52', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (148, 0, '通知', '0', 'message_type', NULL, 'primary', 'N', '0', 'xl', '2025-01-03 15:12:29', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (149, 0, '提示', '1', 'message_type', NULL, 'success', 'N', '0', 'xl', '2025-01-03 15:12:41', 'xl', '2025-01-03 15:12:45', NULL); +INSERT INTO `sys_dict_data` VALUES (150, 1, '推广', '1', 'template_type', NULL, 'success', 'N', '0', 'xl', '2025-01-03 15:13:15', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (151, 0, '系统指定', 'fixed', 'exp_data_type', NULL, 'default', 'N', '0', 'admin', '2024-03-12 09:04:46', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (152, 0, '动态选择', 'dynamic', 'exp_data_type', NULL, 'default', 'N', '0', 'admin', '2024-03-12 09:05:02', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (153, 0, '任务监听', '1', 'sys_listener_type', NULL, 'default', 'N', '0', 'admin', '2022-12-25 11:47:26', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (154, 2, '执行监听', '2', 'sys_listener_type', NULL, 'default', 'N', '0', 'admin', '2022-12-25 11:47:37', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (155, 0, 'JAVA类', 'classListener', 'sys_listener_value_type', NULL, 'default', 'N', '0', 'admin', '2022-12-25 11:48:55', 'admin', '2024-09-05 21:38:02', NULL); +INSERT INTO `sys_dict_data` VALUES (156, 0, '表达式', 'expressionListener', 'sys_listener_value_type', NULL, 'default', 'N', '0', 'admin', '2022-12-25 11:49:05', 'admin', '2024-09-05 21:38:10', NULL); +INSERT INTO `sys_dict_data` VALUES (157, 0, '代理表达式', 'delegateExpressionListener', 'sys_listener_value_type', NULL, 'default', 'N', '0', 'admin', '2022-12-25 11:49:16', 'admin', '2024-09-05 21:38:16', NULL); +INSERT INTO `sys_dict_data` VALUES (158, 0, '请假', 'leave', 'sys_process_category', NULL, 'default', 'N', '0', 'admin', '2024-03-12 09:08:42', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (159, 0, '报销', 'expense', 'sys_process_category', NULL, 'default', 'N', '0', 'admin', '2024-03-12 09:09:02', '', NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_dict_type +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dict_type`; +CREATE TABLE `sys_dict_type` ( + `dict_id` bigint NOT NULL AUTO_INCREMENT COMMENT '字典主键', + `dict_name` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '字典名称', + `dict_type` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '字典类型', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '状态(0正常 1停用)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`dict_id`) USING BTREE, + UNIQUE INDEX `dict_type`(`dict_type` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 109 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '字典类型表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_dict_type +-- ---------------------------- +INSERT INTO `sys_dict_type` VALUES (1, '用户性别', 'sys_user_sex', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '用户性别列表'); +INSERT INTO `sys_dict_type` VALUES (2, '菜单状态', 'sys_show_hide', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '菜单状态列表'); +INSERT INTO `sys_dict_type` VALUES (3, '系统开关', 'sys_normal_disable', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '系统开关列表'); +INSERT INTO `sys_dict_type` VALUES (4, '任务状态', 'sys_job_status', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '任务状态列表'); +INSERT INTO `sys_dict_type` VALUES (5, '任务分组', 'sys_job_group', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '任务分组列表'); +INSERT INTO `sys_dict_type` VALUES (6, '系统是否', 'sys_yes_no', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '系统是否列表'); +INSERT INTO `sys_dict_type` VALUES (7, '通知类型', 'sys_notice_type', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '通知类型列表'); +INSERT INTO `sys_dict_type` VALUES (8, '通知状态', 'sys_notice_status', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '通知状态列表'); +INSERT INTO `sys_dict_type` VALUES (9, '操作类型', 'sys_oper_type', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '操作类型列表'); +INSERT INTO `sys_dict_type` VALUES (10, '系统状态', 'sys_common_status', '0', 'admin', '2025-05-26 17:20:07', '', NULL, '登录状态列表'); +INSERT INTO `sys_dict_type` VALUES (100, '请求方式', 'online_api_method', '0', 'admin', '2024-02-21 18:22:03', 'admin', '2024-02-21 18:22:13', NULL); +INSERT INTO `sys_dict_type` VALUES (101, '标签名', 'online_api_tag', '0', 'admin', '2024-02-21 18:22:29', '', NULL, NULL); +INSERT INTO `sys_dict_type` VALUES (102, '响应类型', 'online_api_result', '0', 'admin', '2024-02-21 18:22:46', '', NULL, NULL); +INSERT INTO `sys_dict_type` VALUES (103, '执行器', 'online_api_actuator', '0', 'admin', '2024-02-21 18:23:03', '', NULL, NULL); +INSERT INTO `sys_dict_type` VALUES (104, '表达式类型', 'exp_data_type', '0', 'admin', '2024-03-12 09:03:02', '', NULL, NULL); +INSERT INTO `sys_dict_type` VALUES (105, '监听类型', 'sys_listener_type', '0', 'admin', '2022-12-18 22:03:07', '', NULL, NULL); +INSERT INTO `sys_dict_type` VALUES (106, '监听值类型', 'sys_listener_value_type', '0', 'admin', '2022-12-18 22:03:39', '', NULL, NULL); +INSERT INTO `sys_dict_type` VALUES (107, '监听属性', 'sys_listener_event_type', '0', 'admin', '2022-12-18 22:04:29', '', NULL, NULL); +INSERT INTO `sys_dict_type` VALUES (108, '流程分类', 'sys_process_category', '0', 'admin', '2024-03-12 09:08:18', '', NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_expression +-- ---------------------------- +DROP TABLE IF EXISTS `sys_expression`; +CREATE TABLE `sys_expression` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '表单主键', + `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '表达式名称', + `expression` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '表达式内容', + `data_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '表达式类型', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人员', + `update_by` bigint NULL DEFAULT NULL COMMENT '更新人员', + `status` tinyint NULL DEFAULT 0 COMMENT '状态', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 69 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '流程表达式' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_expression +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_file_info +-- ---------------------------- +DROP TABLE IF EXISTS `sys_file_info`; +CREATE TABLE `sys_file_info` ( + `file_id` bigint NOT NULL AUTO_INCREMENT COMMENT '文件主键', + `file_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '原始文件名', + `file_path` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '统一逻辑路径(/开头)', + `storage_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '存储类型(local/minio/oss)', + `file_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '文件类型/后缀', + `file_size` bigint NULL DEFAULT NULL COMMENT '文件大小(字节)', + `md5` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '文件MD5', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + PRIMARY KEY (`file_id`) USING BTREE, + UNIQUE INDEX `uk_md5`(`md5` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_file_info +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_job +-- ---------------------------- +DROP TABLE IF EXISTS `sys_job`; +CREATE TABLE `sys_job` ( + `job_id` bigint NOT NULL AUTO_INCREMENT COMMENT '任务ID', + `job_name` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '任务名称', + `job_group` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'DEFAULT' COMMENT '任务组名', + `invoke_target` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '调用目标字符串', + `cron_expression` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT 'cron执行表达式', + `misfire_policy` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '3' COMMENT '计划执行错误策略(1立即执行 2执行一次 3放弃执行)', + `concurrent` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '1' COMMENT '是否并发执行(0允许 1禁止)', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '状态(0正常 1暂停)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '备注信息', + PRIMARY KEY (`job_id`, `job_name`, `job_group`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 100 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '定时任务调度表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_job +-- ---------------------------- +INSERT INTO `sys_job` VALUES (1, '系统默认(无参)', 'DEFAULT', 'ryTask.ryNoParams', '0/10 * * * * ?', '3', '1', '1', 'admin', '2025-05-26 17:20:07', '', NULL, ''); +INSERT INTO `sys_job` VALUES (2, '系统默认(有参)', 'DEFAULT', 'ryTask.ryParams(\'ry\')', '0/15 * * * * ?', '3', '1', '1', 'admin', '2025-05-26 17:20:07', '', NULL, ''); +INSERT INTO `sys_job` VALUES (3, '系统默认(多参)', 'DEFAULT', 'ryTask.ryMultipleParams(\'ry\', true, 2000L, 316.50D, 100)', '0/20 * * * * ?', '3', '1', '1', 'admin', '2025-05-26 17:20:07', '', NULL, ''); + +-- ---------------------------- +-- Table structure for sys_job_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_job_log`; +CREATE TABLE `sys_job_log` ( + `job_log_id` bigint NOT NULL AUTO_INCREMENT COMMENT '任务日志ID', + `job_name` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '任务名称', + `job_group` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '任务组名', + `invoke_target` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '调用目标字符串', + `job_message` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '日志信息', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '执行状态(0正常 1失败)', + `exception_info` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '异常信息', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`job_log_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '定时任务调度日志表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_job_log +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_listener +-- ---------------------------- +DROP TABLE IF EXISTS `sys_listener`; +CREATE TABLE `sys_listener` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '表单主键', + `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '名称', + `type` char(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '监听类型', + `event_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '事件类型', + `value_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '值类型', + `value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '执行内容', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人员', + `update_by` bigint NULL DEFAULT NULL COMMENT '更新人员', + `status` tinyint NULL DEFAULT 0 COMMENT '状态', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '流程监听' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_listener +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_logininfor +-- ---------------------------- +DROP TABLE IF EXISTS `sys_logininfor`; +CREATE TABLE `sys_logininfor` ( + `info_id` bigint NOT NULL AUTO_INCREMENT COMMENT '访问ID', + `user_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '用户账号', + `ipaddr` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '登录IP地址', + `login_location` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '登录地点', + `browser` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '浏览器类型', + `os` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '操作系统', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '登录状态(0成功 1失败)', + `msg` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '提示消息', + `login_time` datetime NULL DEFAULT NULL COMMENT '访问时间', + PRIMARY KEY (`info_id`) USING BTREE, + INDEX `idx_sys_logininfor_s`(`status` ASC) USING BTREE, + INDEX `idx_sys_logininfor_lt`(`login_time` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 133 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '系统访问记录' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_logininfor +-- ---------------------------- +INSERT INTO `sys_logininfor` VALUES (100, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-26 18:37:16'); +INSERT INTO `sys_logininfor` VALUES (101, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '1', '验证码错误', '2025-05-28 18:36:01'); +INSERT INTO `sys_logininfor` VALUES (102, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-28 18:36:05'); +INSERT INTO `sys_logininfor` VALUES (103, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '退出成功', '2025-05-28 19:33:38'); +INSERT INTO `sys_logininfor` VALUES (104, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-28 19:33:47'); +INSERT INTO `sys_logininfor` VALUES (105, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-28 20:46:43'); +INSERT INTO `sys_logininfor` VALUES (106, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-28 21:18:44'); +INSERT INTO `sys_logininfor` VALUES (107, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 06:59:57'); +INSERT INTO `sys_logininfor` VALUES (108, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 08:41:00'); +INSERT INTO `sys_logininfor` VALUES (109, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '退出成功', '2025-05-29 10:46:05'); +INSERT INTO `sys_logininfor` VALUES (110, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 10:46:17'); +INSERT INTO `sys_logininfor` VALUES (111, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 12:33:00'); +INSERT INTO `sys_logininfor` VALUES (112, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '退出成功', '2025-05-29 12:33:12'); +INSERT INTO `sys_logininfor` VALUES (113, 'hasfj', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 12:33:26'); +INSERT INTO `sys_logininfor` VALUES (114, 'hasfj', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '退出成功', '2025-05-29 12:33:50'); +INSERT INTO `sys_logininfor` VALUES (115, 'admin', '49.74.40.190', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 13:28:43'); +INSERT INTO `sys_logininfor` VALUES (116, 'admin', '49.74.40.190', 'XX XX', 'Chrome 13', 'Windows 10', '0', '退出成功', '2025-05-29 13:28:52'); +INSERT INTO `sys_logininfor` VALUES (117, 'admin', '49.74.40.190', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 14:55:02'); +INSERT INTO `sys_logininfor` VALUES (118, 'hasfj', '49.74.40.190', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-29 14:56:29'); +INSERT INTO `sys_logininfor` VALUES (119, 'hasfj', '114.238.34.181', 'XX XX', 'Safari', 'Mac OS X', '0', '登录成功', '2025-05-29 14:57:15'); +INSERT INTO `sys_logininfor` VALUES (120, 'admin', '49.82.111.128', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-30 13:39:02'); +INSERT INTO `sys_logininfor` VALUES (121, 'admin', '49.82.111.128', 'XX XX', 'Chrome 13', 'Windows 10', '0', '退出成功', '2025-05-30 13:49:58'); +INSERT INTO `sys_logininfor` VALUES (122, 'admin', '49.82.111.128', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-30 13:50:12'); +INSERT INTO `sys_logininfor` VALUES (123, 'admin', '180.125.41.129', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-31 08:54:48'); +INSERT INTO `sys_logininfor` VALUES (124, 'admin', '49.87.176.188', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-31 12:12:39'); +INSERT INTO `sys_logininfor` VALUES (125, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-31 14:44:08'); +INSERT INTO `sys_logininfor` VALUES (126, 'admin', '180.125.41.129', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-31 15:04:25'); +INSERT INTO `sys_logininfor` VALUES (127, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-05-31 19:26:24'); +INSERT INTO `sys_logininfor` VALUES (128, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-06-01 10:15:29'); +INSERT INTO `sys_logininfor` VALUES (129, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-06-01 11:03:00'); +INSERT INTO `sys_logininfor` VALUES (130, 'admin', '127.0.0.1', '内网IP', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-06-02 13:51:42'); +INSERT INTO `sys_logininfor` VALUES (131, 'admin', '218.2.75.254', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-06-02 19:18:18'); +INSERT INTO `sys_logininfor` VALUES (132, 'admin', '218.2.75.254', 'XX XX', 'Chrome 13', 'Windows 10', '0', '登录成功', '2025-06-02 19:33:32'); + +-- ---------------------------- +-- Table structure for sys_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_menu`; +CREATE TABLE `sys_menu` ( + `menu_id` bigint NOT NULL AUTO_INCREMENT COMMENT '菜单ID', + `menu_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '菜单名称', + `parent_id` bigint NULL DEFAULT 0 COMMENT '父菜单ID', + `order_num` int NULL DEFAULT 0 COMMENT '显示顺序', + `path` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '路由地址', + `component` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '组件路径', + `query` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '路由参数', + `route_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '路由名称', + `is_frame` int NULL DEFAULT 1 COMMENT '是否为外链(0是 1否)', + `is_cache` int NULL DEFAULT 0 COMMENT '是否缓存(0缓存 1不缓存)', + `menu_type` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '菜单类型(M目录 C菜单 F按钮)', + `visible` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '菜单状态(0显示 1隐藏)', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '菜单状态(0正常 1停用)', + `perms` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '权限标识', + `icon` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '#' COMMENT '菜单图标', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '备注', + PRIMARY KEY (`menu_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2105 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '菜单权限表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_menu +-- ---------------------------- +INSERT INTO `sys_menu` VALUES (1, '系统管理', 0, 1, 'system', NULL, '', '', 1, 0, 'M', '0', '0', '', 'system', 'admin', '2025-05-26 17:20:06', '', NULL, '系统管理目录'); +INSERT INTO `sys_menu` VALUES (2, '系统监控', 0, 2, 'monitor', NULL, '', '', 1, 0, 'M', '0', '0', '', 'monitor', 'admin', '2025-05-26 17:20:06', '', NULL, '系统监控目录'); +INSERT INTO `sys_menu` VALUES (3, '系统工具', 0, 3, 'tool', NULL, '', '', 1, 0, 'M', '0', '0', '', 'tool', 'admin', '2025-05-26 17:20:06', '', NULL, '系统工具目录'); +INSERT INTO `sys_menu` VALUES (100, '用户管理', 1, 1, 'user', 'system/user/index', '', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', '2025-05-26 17:20:06', '', NULL, '用户管理菜单'); +INSERT INTO `sys_menu` VALUES (101, '角色管理', 1, 2, 'role', 'system/role/index', '', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', '2025-05-26 17:20:06', '', NULL, '角色管理菜单'); +INSERT INTO `sys_menu` VALUES (102, '菜单管理', 1, 3, 'menu', 'system/menu/index', '', '', 1, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', 'admin', '2025-05-26 17:20:06', '', NULL, '菜单管理菜单'); +INSERT INTO `sys_menu` VALUES (103, '部门管理', 1, 4, 'dept', 'system/dept/index', '', '', 1, 0, 'C', '0', '0', 'system:dept:list', 'tree', 'admin', '2025-05-26 17:20:06', '', NULL, '部门管理菜单'); +INSERT INTO `sys_menu` VALUES (104, '岗位管理', 1, 5, 'post', 'system/post/index', '', '', 1, 0, 'C', '0', '0', 'system:post:list', 'post', 'admin', '2025-05-26 17:20:06', '', NULL, '岗位管理菜单'); +INSERT INTO `sys_menu` VALUES (105, '字典管理', 1, 6, 'dict', 'system/dict/index', '', '', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 'admin', '2025-05-26 17:20:06', '', NULL, '字典管理菜单'); +INSERT INTO `sys_menu` VALUES (106, '参数设置', 1, 7, 'config', 'system/config/index', '', '', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 'admin', '2025-05-26 17:20:06', '', NULL, '参数设置菜单'); +INSERT INTO `sys_menu` VALUES (107, '通知公告', 1, 8, 'notice', 'system/notice/index', '', '', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 'admin', '2025-05-26 17:20:06', '', NULL, '通知公告菜单'); +INSERT INTO `sys_menu` VALUES (108, '日志管理', 1, 9, 'log', '', '', '', 1, 0, 'M', '0', '0', '', 'log', 'admin', '2025-05-26 17:20:06', '', NULL, '日志管理菜单'); +INSERT INTO `sys_menu` VALUES (109, '在线用户', 2, 1, 'online', 'monitor/online/index', '', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 'admin', '2025-05-26 17:20:06', '', NULL, '在线用户菜单'); +INSERT INTO `sys_menu` VALUES (110, '定时任务', 2, 2, 'job', 'monitor/job/index', '', '', 1, 0, 'C', '0', '0', 'monitor:job:list', 'job', 'admin', '2025-05-26 17:20:06', '', NULL, '定时任务菜单'); +INSERT INTO `sys_menu` VALUES (111, '数据监控', 2, 3, 'druid', 'monitor/druid/index', '', '', 1, 0, 'C', '0', '0', 'monitor:druid:list', 'druid', 'admin', '2025-05-26 17:20:06', '', NULL, '数据监控菜单'); +INSERT INTO `sys_menu` VALUES (112, '服务监控', 2, 4, 'server', 'monitor/server/index', '', '', 1, 0, 'C', '0', '0', 'monitor:server:list', 'server', 'admin', '2025-05-26 17:20:06', '', NULL, '服务监控菜单'); +INSERT INTO `sys_menu` VALUES (113, '缓存监控', 2, 5, 'cache', 'monitor/cache/index', '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 'admin', '2025-05-26 17:20:06', '', NULL, '缓存监控菜单'); +INSERT INTO `sys_menu` VALUES (114, '缓存列表', 2, 6, 'cacheList', 'monitor/cache/list', '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis-list', 'admin', '2025-05-26 17:20:06', '', NULL, '缓存列表菜单'); +INSERT INTO `sys_menu` VALUES (115, '表单构建', 3, 1, 'build', 'tool/build/index', '', '', 1, 0, 'C', '0', '0', 'tool:build:list', 'build', 'admin', '2025-05-26 17:20:06', '', NULL, '表单构建菜单'); +INSERT INTO `sys_menu` VALUES (116, '代码生成', 3, 2, 'gen', 'tool/gen/index', '', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 'admin', '2025-05-26 18:42:26', '', NULL, '代码生成菜单'); +INSERT INTO `sys_menu` VALUES (117, '系统接口', 3, 3, 'swagger', 'tool/swagger/index', '', '', 1, 0, 'C', '0', '0', 'tool:swagger:list', 'swagger', 'admin', '2025-05-26 17:20:06', '', NULL, '系统接口菜单'); +INSERT INTO `sys_menu` VALUES (500, '操作日志', 108, 1, 'operlog', 'monitor/operlog/index', '', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 'admin', '2025-05-26 17:20:06', '', NULL, '操作日志菜单'); +INSERT INTO `sys_menu` VALUES (501, '登录日志', 108, 2, 'logininfor', 'monitor/logininfor/index', '', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 'admin', '2025-05-26 17:20:06', '', NULL, '登录日志菜单'); +INSERT INTO `sys_menu` VALUES (1000, '用户查询', 100, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1001, '用户新增', 100, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1002, '用户修改', 100, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1003, '用户删除', 100, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1004, '用户导出', 100, 5, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1005, '用户导入', 100, 6, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:import', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1006, '重置密码', 100, 7, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1007, '角色查询', 101, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1008, '角色新增', 101, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1009, '角色修改', 101, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1010, '角色删除', 101, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1011, '角色导出', 101, 5, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1012, '菜单查询', 102, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1013, '菜单新增', 102, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1014, '菜单修改', 102, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1015, '菜单删除', 102, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1016, '部门查询', 103, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1017, '部门新增', 103, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1018, '部门修改', 103, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1019, '部门删除', 103, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1020, '岗位查询', 104, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1021, '岗位新增', 104, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1022, '岗位修改', 104, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1023, '岗位删除', 104, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1024, '岗位导出', 104, 5, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1025, '字典查询', 105, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1026, '字典新增', 105, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1027, '字典修改', 105, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1028, '字典删除', 105, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1029, '字典导出', 105, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1030, '参数查询', 106, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1031, '参数新增', 106, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1032, '参数修改', 106, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1033, '参数删除', 106, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1034, '参数导出', 106, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1035, '公告查询', 107, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1036, '公告新增', 107, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1037, '公告修改', 107, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1038, '公告删除', 107, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1039, '操作查询', 500, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1040, '操作删除', 500, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1041, '日志导出', 500, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1042, '登录查询', 501, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1043, '登录删除', 501, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1044, '日志导出', 501, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1045, '账户解锁', 501, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1046, '在线查询', 109, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1047, '批量强退', 109, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1048, '单条强退', 109, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1049, '任务查询', 110, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:query', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1050, '任务新增', 110, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:add', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1051, '任务修改', 110, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:edit', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1052, '任务删除', 110, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:remove', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1053, '状态修改', 110, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:changeStatus', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1054, '任务导出', 110, 6, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:export', '#', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1055, '生成查询', 116, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 'admin', '2025-05-26 18:42:26', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1056, '生成修改', 116, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 'admin', '2025-05-26 18:42:26', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1057, '生成删除', 116, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 'admin', '2025-05-26 18:42:26', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1058, '导入代码', 116, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 'admin', '2025-05-26 18:42:26', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1059, '预览代码', 116, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', '2025-05-26 18:42:26', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1060, '生成代码', 116, 6, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', '2025-05-26 18:42:26', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2000, '支付管理', 0, 4, 'pay', NULL, NULL, '', 1, 0, 'M', '1', '1', '', 'money', 'admin', '2024-02-15 22:40:23', 'admin', '2025-05-28 18:37:31', ''); +INSERT INTO `sys_menu` VALUES (2001, '订单', 2000, 1, 'order', 'pay/order/index', NULL, '', 1, 0, 'C', '0', '0', 'pay:order:list', '#', 'admin', '2025-05-26 18:42:52', '', NULL, '订单菜单'); +INSERT INTO `sys_menu` VALUES (2002, '订单查询', 2001, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:order:query', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2003, '订单新增', 2001, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:order:add', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2004, '订单修改', 2001, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:order:edit', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2005, '订单删除', 2001, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:order:remove', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2006, '订单导出', 2001, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:order:export', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2007, '发票', 2000, 1, 'invoice', 'pay/invoice/index', NULL, '', 1, 0, 'C', '0', '0', 'pay:invoice:list', '#', 'admin', '2025-05-26 18:42:52', '', NULL, '发票菜单'); +INSERT INTO `sys_menu` VALUES (2008, '发票查询', 2007, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:invoice:query', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2009, '发票新增', 2007, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:invoice:add', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2010, '发票修改', 2007, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:invoice:edit', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2011, '发票删除', 2007, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:invoice:remove', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2012, '发票导出', 2007, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'pay:invoice:export', '#', 'admin', '2025-05-26 18:42:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2013, 'Online', 0, 5, 'onlinedev', NULL, NULL, '', 1, 0, 'M', '1', '1', '', 'international', 'admin', '2024-03-07 19:38:34', 'admin', '2025-05-28 18:37:18', ''); +INSERT INTO `sys_menu` VALUES (2014, 'mybatis在线接口', 2013, 1, 'mb', 'online/mb/index', NULL, '', 1, 0, 'C', '0', '0', 'online:mb:list', 'code', 'admin', '2025-05-26 18:42:57', '', NULL, 'mybatis在线接口菜单'); +INSERT INTO `sys_menu` VALUES (2015, '数据库', 2013, 1, 'db', 'online/db/index', NULL, '', 1, 0, 'C', '0', '0', 'admin', 'table', 'admin', '2024-03-07 19:48:24', 'admin', '2024-03-07 19:54:46', ''); +INSERT INTO `sys_menu` VALUES (2016, 'mybatis在线接口查询', 2015, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'online:mb:query', '#', 'admin', '2025-05-26 18:42:57', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2017, 'mybatis在线接口新增', 2015, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'online:mb:add', '#', 'admin', '2025-05-26 18:42:57', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2018, 'mybatis在线接口修改', 2015, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'online:mb:edit', '#', 'admin', '2025-05-26 18:42:57', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2019, 'mybatis在线接口删除', 2015, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'online:mb:remove', '#', 'admin', '2025-05-26 18:42:57', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2020, 'mybatis在线接口导出', 2015, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'online:mb:export', '#', 'admin', '2025-05-26 18:42:57', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2021, '消息系统', 0, 6, 'modelMessage', NULL, NULL, '', 1, 0, 'M', '1', '1', '', 'message', 'admin', '2024-12-31 11:57:29', 'admin', '2025-05-28 18:37:14', ''); +INSERT INTO `sys_menu` VALUES (2022, '消息管理', 2021, 0, 'messageSystem', 'modelMessage/messageSystem/index', NULL, '', 1, 0, 'C', '0', '0', 'modelMessage:messageSystem:list', '#', 'admin', '2024-12-21 15:00:31', 'admin', '2024-12-31 15:04:49', '消息管理菜单'); +INSERT INTO `sys_menu` VALUES (2023, '消息管理查询', 2022, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:messageSystem:query', '#', 'admin', '2024-12-21 15:00:31', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2024, '消息管理新增', 2022, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:messageSystem:add', '#', 'admin', '2024-12-21 15:00:31', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2025, '消息管理修改', 2022, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:messageSystem:edit', '#', 'admin', '2024-12-21 15:00:31', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2026, '消息管理删除', 2022, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:messageSystem:remove', '#', 'admin', '2024-12-21 15:00:31', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2027, '消息管理导出', 2022, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:messageSystem:export', '#', 'admin', '2024-12-21 15:00:31', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2028, '模版管理', 2021, 1, 'template', 'modelMessage/template/index', NULL, '', 1, 0, 'C', '0', '0', 'modelMessage:template:list', '#', 'admin', '2024-12-31 14:59:52', '', NULL, '模版管理菜单'); +INSERT INTO `sys_menu` VALUES (2029, '模版管理查询', 2028, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:template:query', '#', 'admin', '2024-12-31 14:59:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2030, '模版管理新增', 2028, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:template:add', '#', 'admin', '2024-12-31 14:59:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2031, '模版管理修改', 2028, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:template:edit', '#', 'admin', '2024-12-31 14:59:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2032, '模版管理删除', 2028, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:template:remove', '#', 'admin', '2024-12-31 14:59:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2033, '模版管理导出', 2028, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:template:export', '#', 'admin', '2024-12-31 14:59:52', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2034, '变量管理', 2021, 2, 'variable', 'modelMessage/variable/index', NULL, '', 1, 0, 'C', '0', '0', 'modelMessage:variable:list', '#', 'admin', '2024-12-31 15:01:50', 'admin', '2024-12-31 15:04:56', '变量管理菜单'); +INSERT INTO `sys_menu` VALUES (2035, '变量管理查询', 2034, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:variable:query', '#', 'admin', '2024-12-31 15:01:50', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2036, '变量管理新增', 2034, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:variable:add', '#', 'admin', '2024-12-31 15:01:50', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2037, '变量管理修改', 2034, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:variable:edit', '#', 'admin', '2024-12-31 15:01:50', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2038, '变量管理删除', 2034, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:variable:remove', '#', 'admin', '2024-12-31 15:01:50', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2039, '变量管理导出', 2034, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'modelMessage:variable:export', '#', 'admin', '2024-12-31 15:01:50', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2040, '表单管理', 0, 4, 'formManagement', NULL, NULL, '', 1, 0, 'M', '1', '1', '', 'form', 'admin', '2024-02-15 22:40:23', 'admin', '2025-05-28 18:37:27', ''); +INSERT INTO `sys_menu` VALUES (2041, '表单模板', 2040, 1, 'formtemplate', 'form/template/index', NULL, '', 1, 0, 'C', '0', '0', 'form:template:list', '#', 'admin', '2025-05-26 18:43:09', '', NULL, '表单模板菜单'); +INSERT INTO `sys_menu` VALUES (2042, '表单模板查询', 2041, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:template:query', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2043, '表单模板新增', 2041, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:template:add', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2044, '表单模板修改', 2041, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:template:edit', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2045, '表单模板删除', 2041, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:template:remove', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2046, '表单模板导出', 2041, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:template:export', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2047, '表单数据', 2040, 1, 'formdata', 'form/data/index', NULL, '', 1, 0, 'C', '0', '0', 'form:data:list', '#', 'admin', '2025-05-26 18:43:09', '', NULL, '表单数据菜单'); +INSERT INTO `sys_menu` VALUES (2048, '表单数据查询', 2047, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:data:query', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2049, '表单数据新增', 2047, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:data:add', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2050, '表单数据修改', 2047, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:data:edit', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2051, '表单数据删除', 2047, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:data:remove', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2052, '表单数据导出', 2047, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'form:data:export', '#', 'admin', '2025-05-26 18:43:09', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2053, '流程管理', 0, 6, 'flowable', NULL, NULL, NULL, 1, 0, 'M', '1', '1', '', 'cascader', 'tony', '2021-03-25 11:35:09', 'admin', '2025-05-28 18:37:09', ''); +INSERT INTO `sys_menu` VALUES (2054, '流程定义', 2053, 2, 'definition', 'flowable/definition/index', NULL, NULL, 1, 0, 'C', '0', '0', '', 'job', 'tony', '2021-03-25 13:53:55', 'admin', '2022-12-29 17:40:39', ''); +INSERT INTO `sys_menu` VALUES (2055, '任务管理', 0, 7, 'task', NULL, NULL, NULL, 1, 0, 'M', '1', '1', '', 'dict', 'tony', '2021-03-26 10:53:10', 'admin', '2025-05-28 18:37:05', ''); +INSERT INTO `sys_menu` VALUES (2056, '待办任务', 2055, 2, 'todo', 'flowable/task/todo/index', NULL, NULL, 1, 1, 'C', '0', '0', '', 'cascader', 'admin', '2021-03-26 10:55:52', 'admin', '2021-03-30 09:26:36', ''); +INSERT INTO `sys_menu` VALUES (2057, '已办任务', 2055, 3, 'finished', 'flowable/task/finished/index', NULL, NULL, 1, 1, 'C', '0', '0', '', 'time-range', 'admin', '2021-03-26 10:57:54', 'admin', '2021-03-30 09:26:50', ''); +INSERT INTO `sys_menu` VALUES (2058, '已发任务', 2055, 1, 'process', 'flowable/task/myProcess/index', NULL, NULL, 1, 1, 'C', '0', '0', '', 'guide', 'admin', '2021-03-30 09:26:23', 'admin', '2022-12-12 09:58:07', ''); +INSERT INTO `sys_menu` VALUES (2059, '新增', 2058, 1, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'system:deployment:add', '#', 'admin', '2021-07-07 14:25:22', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2060, '编辑', 2058, 2, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'system:deployment:edit', '#', 'admin', '2021-07-07 14:25:47', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2061, '删除', 2058, 3, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'system:deployment:remove', '#', 'admin', '2021-07-07 14:26:02', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2062, '流程表达式', 2053, 3, 'expression', 'flowable/expression/index', NULL, NULL, 1, 1, 'C', '0', '0', 'system:expression:list', 'list', 'admin', '2022-12-12 17:12:19', 'admin', '2022-12-12 17:13:44', '流程达式菜单'); +INSERT INTO `sys_menu` VALUES (2063, '流程达式查询', 2062, 1, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:expression:query', '#', 'admin', '2022-12-12 17:12:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2064, '流程达式新增', 2062, 2, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:expression:add', '#', 'admin', '2022-12-12 17:12:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2065, '流程达式修改', 2062, 3, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:expression:edit', '#', 'admin', '2022-12-12 17:12:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2066, '流程达式删除', 2062, 4, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:expression:remove', '#', 'admin', '2022-12-12 17:12:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2067, '流程达式导出', 2062, 5, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:expression:export', '#', 'admin', '2022-12-12 17:12:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2068, '流程监听', 2053, 4, 'listener', 'flowable/listener/index', NULL, NULL, 1, 0, 'C', '0', '0', 'system:listener:list', 'monitor', 'admin', '2022-12-25 11:44:16', 'admin', '2022-12-29 08:59:21', '流程监听菜单'); +INSERT INTO `sys_menu` VALUES (2069, '流程监听查询', 2068, 1, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:listener:query', '#', 'admin', '2022-12-25 11:44:16', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2070, '流程监听新增', 2068, 2, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:listener:add', '#', 'admin', '2022-12-25 11:44:16', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2071, '流程监听修改', 2068, 3, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:listener:edit', '#', 'admin', '2022-12-25 11:44:16', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2072, '流程监听删除', 2068, 4, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:listener:remove', '#', 'admin', '2022-12-25 11:44:16', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2073, '流程监听导出', 2068, 5, '#', '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:listener:export', '#', 'admin', '2022-12-25 11:44:16', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2074, '文件管理', 0, 4, 'file', NULL, NULL, '', 1, 0, 'M', '1', '1', '', 'excel', 'admin', '2024-02-15 22:40:23', 'admin', '2025-05-28 18:37:23', ''); +INSERT INTO `sys_menu` VALUES (2075, '文件信息', 2074, 1, 'info', 'file/info/index', NULL, '', 1, 0, 'C', '0', '0', 'file:info:list', 'excel', 'admin', '2025-05-26 18:43:20', '', NULL, '文件信息菜单'); +INSERT INTO `sys_menu` VALUES (2076, '文件信息查询', 2075, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'file:info:query', '#', 'admin', '2025-05-26 18:43:20', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2077, '文件信息新增', 2075, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'file:info:add', '#', 'admin', '2025-05-26 18:43:20', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2078, '文件信息修改', 2075, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'file:info:edit', '#', 'admin', '2025-05-26 18:43:20', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2079, '文件信息删除', 2075, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'file:info:remove', '#', 'admin', '2025-05-26 18:43:20', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2080, '文件信息导出', 2075, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'file:info:export', '#', 'admin', '2025-05-26 18:43:20', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2081, '第三方认证', 1, 1, 'oauth', 'system/oauth/index', NULL, '', 1, 0, 'C', '0', '0', 'system:oauth:list', 'checkbox', 'admin', '2025-05-26 18:43:24', '', NULL, '第三方认证菜单'); +INSERT INTO `sys_menu` VALUES (2082, '第三方认证查询', 2081, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'system:oauth:query', '#', 'admin', '2025-05-26 18:43:24', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2083, '第三方认证新增', 2081, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'system:oauth:add', '#', 'admin', '2025-05-26 18:43:24', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2084, '第三方认证修改', 2081, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'system:oauth:edit', '#', 'admin', '2025-05-26 18:43:24', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2085, '第三方认证删除', 2081, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'system:oauth:remove', '#', 'admin', '2025-05-26 18:43:24', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2086, '第三方认证导出', 2081, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'system:oauth:export', '#', 'admin', '2025-05-26 18:43:24', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2097, '淮安市司法局网站', 0, 40, 'hasfj', NULL, NULL, '', 1, 0, 'M', '0', '0', '', 'peoples', 'admin', '2025-05-28 21:46:52', '', NULL, '淮安市司法局网站管理'); +INSERT INTO `sys_menu` VALUES (2099, '页面内容管理', 2097, 1, 'hasfjpages', 'hasfj/hasfjpages/index', NULL, '', 1, 0, 'C', '0', '0', 'hasfj:hasfjpages:list', 'documentation', 'admin', '2025-05-28 21:48:22', '', NULL, '司法局法律规定、典型案例、单下载菜单'); +INSERT INTO `sys_menu` VALUES (2100, '页面内容查询', 2099, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'hasfj:hasfjpages:query', '#', 'admin', '2025-05-28 21:48:22', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2101, '页面内容新增', 2099, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'hasfj:hasfjpages:add', '#', 'admin', '2025-05-28 21:48:22', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2102, '页面内容修改', 2099, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'hasfj:hasfjpages:edit', '#', 'admin', '2025-05-28 21:48:22', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2103, '页面内容删除', 2099, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'hasfj:hasfjpages:remove', '#', 'admin', '2025-05-28 21:48:22', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (2104, '页面内容导出', 2099, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'hasfj:hasfjpages:export', '#', 'admin', '2025-05-28 21:48:22', '', NULL, ''); + +-- ---------------------------- +-- Table structure for sys_notice +-- ---------------------------- +DROP TABLE IF EXISTS `sys_notice`; +CREATE TABLE `sys_notice` ( + `notice_id` int NOT NULL AUTO_INCREMENT COMMENT '公告ID', + `notice_title` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '公告标题', + `notice_type` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '公告类型(1通知 2公告)', + `notice_content` longblob NULL COMMENT '公告内容', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '公告状态(0正常 1关闭)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`notice_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '通知公告表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_notice +-- ---------------------------- +INSERT INTO `sys_notice` VALUES (1, '温馨提醒:2018-07-01 若依新版本发布啦', '2', 0xE696B0E78988E69CACE58685E5AEB9, '0', 'admin', '2025-05-26 17:20:07', '', NULL, '管理员'); +INSERT INTO `sys_notice` VALUES (2, '维护通知:2018-07-01 若依系统凌晨维护', '1', 0xE7BBB4E68AA4E58685E5AEB9, '0', 'admin', '2025-05-26 17:20:07', '', NULL, '管理员'); + +-- ---------------------------- +-- Table structure for sys_oper_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_oper_log`; +CREATE TABLE `sys_oper_log` ( + `oper_id` bigint NOT NULL AUTO_INCREMENT COMMENT '日志主键', + `title` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '模块标题', + `business_type` int NULL DEFAULT 0 COMMENT '业务类型(0其它 1新增 2修改 3删除)', + `method` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '方法名称', + `request_method` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '请求方式', + `operator_type` int NULL DEFAULT 0 COMMENT '操作类别(0其它 1后台用户 2手机端用户)', + `oper_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '操作人员', + `dept_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '部门名称', + `oper_url` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '请求URL', + `oper_ip` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '主机地址', + `oper_location` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '操作地点', + `oper_param` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '请求参数', + `json_result` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '返回参数', + `status` int NULL DEFAULT 0 COMMENT '操作状态(0正常 1异常)', + `error_msg` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '错误消息', + `oper_time` datetime NULL DEFAULT NULL COMMENT '操作时间', + `cost_time` bigint NULL DEFAULT 0 COMMENT '消耗时间', + PRIMARY KEY (`oper_id`) USING BTREE, + INDEX `idx_sys_oper_log_bt`(`business_type` ASC) USING BTREE, + INDEX `idx_sys_oper_log_s`(`status` ASC) USING BTREE, + INDEX `idx_sys_oper_log_ot`(`oper_time` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 231 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '操作日志记录' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_oper_log +-- ---------------------------- +INSERT INTO `sys_oper_log` VALUES (100, '用户头像', 2, 'com.boyue.web.controller.system.SysProfileController.avatar()', 'POST', 1, 'admin', '研发部门', '/system/user/profile/avatar', '127.0.0.1', '内网IP', '', '{\"msg\":\"操作成功\",\"imgUrl\":\"http://localhost:8080/profile/files/master/avatar/admin/1/20250526183841-avatar.png\",\"code\":200}', 0, NULL, '2025-05-26 18:38:41', 103); +INSERT INTO `sys_oper_log` VALUES (101, '菜单管理', 3, 'com.boyue.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/menu/4', '127.0.0.1', '内网IP', '4', '{\"msg\":\"菜单已分配,不允许删除\",\"code\":601}', 0, NULL, '2025-05-28 18:36:42', 16); +INSERT INTO `sys_oper_log` VALUES (102, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2025-05-26 17:20:06\",\"icon\":\"guide\",\"isCache\":\"0\",\"isFrame\":\"0\",\"menuId\":4,\"menuName\":\"若依官网\",\"menuType\":\"M\",\"orderNum\":4,\"params\":{},\"parentId\":0,\"path\":\"http://boyue.vip\",\"perms\":\"\",\"query\":\"\",\"routeName\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:36:51', 31); +INSERT INTO `sys_oper_log` VALUES (103, '菜单管理', 3, 'com.boyue.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/menu/4', '127.0.0.1', '内网IP', '4', '{\"msg\":\"菜单已分配,不允许删除\",\"code\":601}', 0, NULL, '2025-05-28 18:36:54', 6); +INSERT INTO `sys_oper_log` VALUES (104, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2021-03-26 10:53:10\",\"icon\":\"dict\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2055,\"menuName\":\"任务管理\",\"menuType\":\"M\",\"orderNum\":7,\"params\":{},\"parentId\":0,\"path\":\"task\",\"perms\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:37:05', 62); +INSERT INTO `sys_oper_log` VALUES (105, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2021-03-25 11:35:09\",\"icon\":\"cascader\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2053,\"menuName\":\"流程管理\",\"menuType\":\"M\",\"orderNum\":6,\"params\":{},\"parentId\":0,\"path\":\"flowable\",\"perms\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:37:09', 27); +INSERT INTO `sys_oper_log` VALUES (106, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2024-12-31 11:57:29\",\"icon\":\"message\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2021,\"menuName\":\"消息系统\",\"menuType\":\"M\",\"orderNum\":6,\"params\":{},\"parentId\":0,\"path\":\"modelMessage\",\"perms\":\"\",\"routeName\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:37:14', 17); +INSERT INTO `sys_oper_log` VALUES (107, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2024-03-07 19:38:34\",\"icon\":\"international\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2013,\"menuName\":\"Online\",\"menuType\":\"M\",\"orderNum\":5,\"params\":{},\"parentId\":0,\"path\":\"onlinedev\",\"perms\":\"\",\"routeName\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:37:18', 23); +INSERT INTO `sys_oper_log` VALUES (108, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2024-02-15 22:40:23\",\"icon\":\"excel\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2074,\"menuName\":\"文件管理\",\"menuType\":\"M\",\"orderNum\":4,\"params\":{},\"parentId\":0,\"path\":\"file\",\"perms\":\"\",\"routeName\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:37:23', 29); +INSERT INTO `sys_oper_log` VALUES (109, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2024-02-15 22:40:23\",\"icon\":\"form\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2040,\"menuName\":\"表单管理\",\"menuType\":\"M\",\"orderNum\":4,\"params\":{},\"parentId\":0,\"path\":\"formManagement\",\"perms\":\"\",\"routeName\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:37:27', 26); +INSERT INTO `sys_oper_log` VALUES (110, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2024-02-15 22:40:23\",\"icon\":\"money\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2000,\"menuName\":\"支付管理\",\"menuType\":\"M\",\"orderNum\":4,\"params\":{},\"parentId\":0,\"path\":\"pay\",\"perms\":\"\",\"routeName\":\"\",\"status\":\"1\",\"updateBy\":\"admin\",\"visible\":\"1\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:37:31', 20); +INSERT INTO `sys_oper_log` VALUES (111, '代码生成', 6, 'com.boyue.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '研发部门', '/tool/gen/importTable', '127.0.0.1', '内网IP', '{\"tables\":\"html_pages\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 18:57:49', 51); +INSERT INTO `sys_oper_log` VALUES (112, '代码生成', 2, 'com.boyue.generator.controller.GenController.synchDb()', 'GET', 1, 'admin', '研发部门', '/tool/gen/synchDb/html_pages', '127.0.0.1', '内网IP', '{}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 19:04:38', 48); +INSERT INTO `sys_oper_log` VALUES (113, '代码生成', 2, 'com.boyue.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '研发部门', '/tool/gen', '127.0.0.1', '内网IP', '{\"allGenTableColumns\":[{\"capJavaField\":\"Id\",\"columnComment\":\"序号\",\"columnId\":1,\"columnName\":\"id\",\"columnType\":\"int(11)\",\"dictType\":\"\",\"edit\":false,\"htmlType\":\"input\",\"increment\":false,\"insert\":false,\"isIncrement\":\"0\",\"isInsert\":\"0\",\"isList\":\"1\",\"isPk\":\"1\",\"isRequired\":\"0\",\"javaField\":\"id\",\"javaType\":\"Long\",\"list\":true,\"params\":{},\"pk\":true,\"query\":false,\"queryType\":\"EQ\",\"required\":false,\"sort\":1,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"FormatId\",\"columnComment\":\"访问id\",\"columnId\":2,\"columnName\":\"format_id\",\"columnType\":\"varchar(6)\",\"dictType\":\"\",\"edit\":true,\"htmlType\":\"input\",\"increment\":false,\"insert\":true,\"isEdit\":\"1\",\"isIncrement\":\"0\",\"isInsert\":\"1\",\"isList\":\"1\",\"isPk\":\"0\",\"isQuery\":\"1\",\"isRequired\":\"1\",\"javaField\":\"formatId\",\"javaType\":\"String\",\"list\":true,\"params\":{},\"pk\":false,\"query\":true,\"queryType\":\"EQ\",\"required\":true,\"sort\":2,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"Title\",\"columnComment\":\"页面标题\",\"columnId\":3,\"columnName\":\"title\",\"columnType\":\"varchar(200)\",\"dictType\":\"\",\"edit\":true,\"htmlType\":\"input\",\"increment\":false,\"insert\":true,\"isEdit\":\"1\",\"isIncrement\":\"0\",\"isInsert\":\"1\",\"isList\":\"1\",\"isPk\":\"0\",\"isQuery\":\"1\",\"isRequired\":\"1\",\"javaField\":\"title\",\"javaType\":\"String\",\"list\":true,\"params\":{},\"pk\":false,\"query\":true,\"queryType\":\"EQ\",\"required\":true,\"sort\":3,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"Content\",\"columnComment\":\"HTML内容\",\"columnId\":4,\"columnName\":\"content\",\"columnType\":\"text\",\"dictType\":\"\",\"edit\":true,\"htmlType\":\"editor\",\"increment\":false,\"insert\":true,\"isEdit\":\"1\",\"isIncrement\":\"0\",\"isInsert\":\"1\",\"isList\":\"1\",\"isPk\":\"0\",\"isQuery\":\"1\",\"isRequired\":\"1\",\"javaField\":\"content\",\"javaType\":\"String\",\"list\":true,\"params\":{},\"pk\":false,\"query\":true,\"queryType\":\"EQ\",\"required\":true,\"sort\":4,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"PageType\",\"columnComment\":\"页面类型:法律规定 law、典型案例 case、表单下载from\",\"columnId\":5,\"columnName\":\"page_type\",\"columnTyp', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 19:06:45', 105); +INSERT INTO `sys_oper_log` VALUES (114, '代码生成', 8, 'com.boyue.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '研发部门', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"html_pages\"}', NULL, 0, NULL, '2025-05-28 19:06:51', 29); +INSERT INTO `sys_oper_log` VALUES (115, '菜单管理', 1, 'com.boyue.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createBy\":\"admin\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuName\":\"司法局\",\"menuType\":\"M\",\"orderNum\":4,\"params\":{},\"parentId\":0,\"path\":\"hasfj\",\"status\":\"0\",\"visible\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 19:08:03', 28); +INSERT INTO `sys_oper_log` VALUES (116, '代码生成', 2, 'com.boyue.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '研发部门', '/tool/gen', '127.0.0.1', '内网IP', '{\"allGenTableColumns\":[{\"capJavaField\":\"Id\",\"columnComment\":\"序号\",\"columnId\":1,\"columnName\":\"id\",\"columnType\":\"int(11)\",\"dictType\":\"\",\"edit\":false,\"htmlType\":\"input\",\"increment\":false,\"insert\":false,\"isIncrement\":\"0\",\"isInsert\":\"0\",\"isList\":\"1\",\"isPk\":\"1\",\"isRequired\":\"0\",\"javaField\":\"id\",\"javaType\":\"Long\",\"list\":true,\"params\":{},\"pk\":true,\"query\":false,\"queryType\":\"EQ\",\"required\":false,\"sort\":1,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"FormatId\",\"columnComment\":\"访问id\",\"columnId\":2,\"columnName\":\"format_id\",\"columnType\":\"varchar(6)\",\"dictType\":\"\",\"edit\":true,\"htmlType\":\"input\",\"increment\":false,\"insert\":true,\"isEdit\":\"1\",\"isIncrement\":\"0\",\"isInsert\":\"1\",\"isList\":\"1\",\"isPk\":\"0\",\"isQuery\":\"1\",\"isRequired\":\"1\",\"javaField\":\"formatId\",\"javaType\":\"String\",\"list\":true,\"params\":{},\"pk\":false,\"query\":true,\"queryType\":\"EQ\",\"required\":true,\"sort\":2,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"Title\",\"columnComment\":\"页面标题\",\"columnId\":3,\"columnName\":\"title\",\"columnType\":\"varchar(200)\",\"dictType\":\"\",\"edit\":true,\"htmlType\":\"input\",\"increment\":false,\"insert\":true,\"isEdit\":\"1\",\"isIncrement\":\"0\",\"isInsert\":\"1\",\"isList\":\"1\",\"isPk\":\"0\",\"isQuery\":\"1\",\"isRequired\":\"1\",\"javaField\":\"title\",\"javaType\":\"String\",\"list\":true,\"params\":{},\"pk\":false,\"query\":true,\"queryType\":\"EQ\",\"required\":true,\"sort\":3,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"Content\",\"columnComment\":\"HTML内容\",\"columnId\":4,\"columnName\":\"content\",\"columnType\":\"text\",\"dictType\":\"\",\"edit\":true,\"htmlType\":\"editor\",\"increment\":false,\"insert\":true,\"isEdit\":\"1\",\"isIncrement\":\"0\",\"isInsert\":\"1\",\"isList\":\"1\",\"isPk\":\"0\",\"isQuery\":\"1\",\"isRequired\":\"1\",\"javaField\":\"content\",\"javaType\":\"String\",\"list\":true,\"params\":{},\"pk\":false,\"query\":true,\"queryType\":\"EQ\",\"required\":true,\"sort\":4,\"superColumn\":false,\"tableId\":1,\"usableColumn\":false},{\"capJavaField\":\"PageType\",\"columnComment\":\"页面类型:法律规定 law、典型案例 case、表单下载from\",\"columnId\":5,\"columnName\":\"page_type\",\"columnTyp', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 19:09:02', 55); +INSERT INTO `sys_oper_log` VALUES (117, '代码生成', 8, 'com.boyue.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '研发部门', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"html_pages\"}', NULL, 0, NULL, '2025-05-28 19:09:04', 24); +INSERT INTO `sys_oper_log` VALUES (118, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"content\":\"
表单下载内容...
\",\"createTime\":\"2025-05-28 18:55:57\",\"formatId\":\"000001\",\"id\":7,\"pageType\":\"from\",\"pageUrl\":\"http://localhost/table.html?Id=000001\",\"params\":{},\"sortOrder\":30,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-28 20:23:58\",\"viewCount\":0}', NULL, 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Data truncated for column \'page_type\' at row 1\r\n### The error may exist in file [E:\\WORK\\boyue-kfcode\\boyue-java\\boyue-models\\boyue-hasfj\\target\\classes\\mapper\\hasfj\\HtmlPagesMapper.xml]\r\n### The error may involve com.boyue.hasfj.mapper.HtmlPagesMapper.updateHtmlPages-Inline\r\n### The error occurred while setting parameters\r\n### SQL: update html_pages SET format_id = ?, title = ?, content = ?, page_type = ?, page_url = ?, create_time = ?, update_time = ?, status = ?, sort_order = ?, view_count = ? where id = ?\r\n### Cause: java.sql.SQLException: Data truncated for column \'page_type\' at row 1\n; Data truncated for column \'page_type\' at row 1', '2025-05-28 20:23:58', 144); +INSERT INTO `sys_oper_log` VALUES (119, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"content\":\"
劳动法第四十条内容及解读...
\",\"createTime\":\"2025-05-28 18:55:57\",\"formatId\":\"000001\",\"id\":1,\"pageType\":\"law\",\"pageUrl\":\"http://localhost/show.html?Id=000001\",\"params\":{},\"sortOrder\":10,\"status\":1,\"title\":\"劳动法第四十条解读\",\"updateTime\":\"2025-05-28 20:53:47\",\"viewCount\":26}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 20:53:47', 12); +INSERT INTO `sys_oper_log` VALUES (120, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"content\":\"
表单下载内容...
\",\"createTime\":\"2025-05-28 18:55:57\",\"formatId\":\"000002\",\"id\":8,\"pageType\":\"from\",\"pageUrl\":\"http://localhost/table.html?Id=000002\",\"params\":{},\"sortOrder\":31,\"status\":1,\"title\":\"劳动合同模板\",\"updateTime\":\"2025-05-28 20:54:06\",\"viewCount\":0}', NULL, 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Data truncated for column \'page_type\' at row 1\r\n### The error may exist in file [E:\\WORK\\boyue-kfcode\\boyue-java\\boyue-models\\boyue-hasfj\\target\\classes\\mapper\\hasfj\\HtmlPagesMapper.xml]\r\n### The error may involve com.boyue.hasfj.mapper.HtmlPagesMapper.updateHtmlPages-Inline\r\n### The error occurred while setting parameters\r\n### SQL: update html_pages SET format_id = ?, title = ?, content = ?, page_type = ?, page_url = ?, create_time = ?, update_time = ?, status = ?, sort_order = ?, view_count = ? where id = ?\r\n### Cause: java.sql.SQLException: Data truncated for column \'page_type\' at row 1\n; Data truncated for column \'page_type\' at row 1', '2025-05-28 20:54:06', 5); +INSERT INTO `sys_oper_log` VALUES (121, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2025-05-28 19:08:03\",\"icon\":\"#\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2087,\"menuName\":\"司法局百问百答\",\"menuType\":\"M\",\"orderNum\":4,\"params\":{},\"parentId\":0,\"path\":\"hasfj\",\"perms\":\"\",\"routeName\":\"\",\"status\":\"0\",\"updateBy\":\"admin\",\"visible\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:19:06', 26); +INSERT INTO `sys_oper_log` VALUES (122, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"createTime\":\"2025-05-28 19:08:03\",\"icon\":\"example\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2087,\"menuName\":\"司法局百问百答\",\"menuType\":\"M\",\"orderNum\":4,\"params\":{},\"parentId\":0,\"path\":\"hasfj\",\"perms\":\"\",\"routeName\":\"\",\"status\":\"0\",\"updateBy\":\"admin\",\"visible\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:19:27', 13); +INSERT INTO `sys_oper_log` VALUES (123, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"component\":\"hasfj/hasfjpages/index\",\"createTime\":\"2025-05-28 19:09:34\",\"icon\":\"#\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2088,\"menuName\":\"司法局百问百答内容配置\",\"menuType\":\"C\",\"orderNum\":1,\"params\":{},\"parentId\":2087,\"path\":\"hasfjpages\",\"perms\":\"hasfj:hasfjpages:list\",\"routeName\":\"\",\"status\":\"0\",\"updateBy\":\"admin\",\"visible\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:21:31', 100); +INSERT INTO `sys_oper_log` VALUES (124, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"component\":\"hasfj/hasfjpages/index\",\"createTime\":\"2025-05-28 19:09:34\",\"icon\":\"#\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2088,\"menuName\":\"内容配置\",\"menuType\":\"C\",\"orderNum\":1,\"params\":{},\"parentId\":2087,\"path\":\"hasfjpages\",\"perms\":\"hasfj:hasfjpages:list\",\"routeName\":\"\",\"status\":\"0\",\"updateBy\":\"admin\",\"visible\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:22:07', 26); +INSERT INTO `sys_oper_log` VALUES (125, '菜单管理', 2, 'com.boyue.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/menu', '127.0.0.1', '内网IP', '{\"children\":[],\"component\":\"hasfj/hasfjpages/index\",\"createTime\":\"2025-05-28 19:09:34\",\"icon\":\"edit\",\"isCache\":\"0\",\"isFrame\":\"1\",\"menuId\":2088,\"menuName\":\"内容配置\",\"menuType\":\"C\",\"orderNum\":1,\"params\":{},\"parentId\":2087,\"path\":\"hasfjpages\",\"perms\":\"hasfj:hasfjpages:list\",\"routeName\":\"\",\"status\":\"0\",\"updateBy\":\"admin\",\"visible\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:22:15', 10); +INSERT INTO `sys_oper_log` VALUES (126, '司法局法律规定、典型案例、单下载', 1, 'com.boyue.hasfj.controller.HtmlPagesController.add()', 'POST', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"content\":\"

000004

\",\"createTime\":\"2025-05-28 21:31:01\",\"formatId\":\"000004\",\"pageType\":\"law\",\"pageUrl\":\"000004\",\"params\":{},\"sortOrder\":10,\"status\":1,\"title\":\"000004\",\"viewCount\":0}', NULL, 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'update_time\' doesn\'t have a default value\r\n### The error may exist in file [E:\\WORK\\boyue-kfcode\\boyue-java\\boyue-models\\boyue-hasfj\\target\\classes\\mapper\\hasfj\\HtmlPagesMapper.xml]\r\n### The error may involve com.boyue.hasfj.mapper.HtmlPagesMapper.insertHtmlPages-Inline\r\n### The error occurred while setting parameters\r\n### SQL: insert into html_pages ( format_id, title, content, page_type, page_url, create_time, status, sort_order, view_count ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'update_time\' doesn\'t have a default value\n; Field \'update_time\' doesn\'t have a default value', '2025-05-28 21:31:01', 4); +INSERT INTO `sys_oper_log` VALUES (127, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"1\",\"content\":\"
劳动法第四十条内容及解读...
\",\"createTime\":\"2025-05-28 18:55:57\",\"formatId\":\"000001\",\"id\":1,\"pageType\":\"law\",\"pageUrl\":\"http://localhost/show.html?Id=000001\",\"params\":{},\"sortOrder\":10,\"status\":1,\"title\":\"劳动法第四十条解读\",\"updateTime\":\"2025-05-28 21:32:08\",\"viewCount\":35}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:32:08', 7); +INSERT INTO `sys_oper_log` VALUES (128, '菜单管理', 3, 'com.boyue.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/menu/2098', '127.0.0.1', '内网IP', '2098', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:48:55', 128); +INSERT INTO `sys_oper_log` VALUES (129, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 21:43:55\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-28 21:49:48\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:49:48', 122); +INSERT INTO `sys_oper_log` VALUES (130, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"案例分析组\",\"content\":\"

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

\",\"createTime\":\"2025-05-28 21:43:55\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"某公司劳资纠纷典型案例\",\"updateTime\":\"2025-05-28 21:50:00\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:50:00', 52); +INSERT INTO `sys_oper_log` VALUES (131, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 21:43:55\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":4,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-28 21:50:07\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:50:07', 18); +INSERT INTO `sys_oper_log` VALUES (132, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"法律法规编辑部\",\"content\":\"

合同法关于订立合同的规定

合同是平等主体的自然人、法人、其他组织之间设立、变更、终止民事权利义务关系的协议。婚姻、收养、监护等有关身份关系的协议,适用其他法律的规定。

\",\"createTime\":\"2025-05-28 21:43:55\",\"description\":\"合同法对于订立合同的基本规定和解释\",\"formatId\":\"000002\",\"id\":2,\"keywords\":\"合同法,合同订立,民事权利\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000002\",\"params\":{},\"sortOrder\":2,\"status\":1,\"title\":\"合同法关于订立合同的规定\",\"updateTime\":\"2025-05-28 21:50:19\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 21:50:19', 84); +INSERT INTO `sys_oper_log` VALUES (133, '司法局法律规定、典型案例、单下载', 5, 'com.boyue.hasfj.controller.HtmlPagesController.export()', 'POST', 1, 'admin', '研发部门', '/hasfj/hasfjpages/export', '127.0.0.1', '内网IP', '{\"pageSize\":\"10\",\"pageNum\":\"1\"}', NULL, 0, NULL, '2025-05-28 22:14:32', 617); +INSERT INTO `sys_oper_log` VALUES (134, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-28 22:19:39\",\"viewCount\":3}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-28 22:19:39', 82); +INSERT INTO `sys_oper_log` VALUES (135, '角色管理', 1, 'com.boyue.web.controller.system.SysRoleController.add()', 'POST', 1, 'admin', '研发部门', '/system/role', '127.0.0.1', '内网IP', '{\"admin\":false,\"createBy\":\"admin\",\"deptCheckStrictly\":true,\"deptIds\":[],\"flag\":false,\"menuCheckStrictly\":true,\"menuIds\":[1,100,1000,1001,1002,1003,1004,1005,1006,2097,2099,2100,2101,2102,2103,2104],\"params\":{},\"roleId\":100,\"roleKey\":\"sfj\",\"roleName\":\"司法局\",\"roleSort\":3,\"status\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:41:41', 74); +INSERT INTO `sys_oper_log` VALUES (136, '用户管理', 3, 'com.boyue.web.controller.system.SysUserController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/user/2', '127.0.0.1', '内网IP', '[2]', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:41:50', 49); +INSERT INTO `sys_oper_log` VALUES (137, '部门管理', 2, 'com.boyue.web.controller.system.SysDeptController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/dept', '127.0.0.1', '内网IP', '{\"ancestors\":\"0\",\"children\":[],\"deptId\":100,\"deptName\":\"博越科技\",\"email\":\"boyue@qq.com\",\"leader\":\"博越\",\"orderNum\":0,\"params\":{},\"parentId\":0,\"phone\":\"15888888888\",\"status\":\"0\",\"updateBy\":\"admin\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:42:28', 120); +INSERT INTO `sys_oper_log` VALUES (138, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/102', '127.0.0.1', '内网IP', '102', '{\"msg\":\"存在下级部门,不允许删除\",\"code\":601}', 0, NULL, '2025-05-29 08:42:32', 4); +INSERT INTO `sys_oper_log` VALUES (139, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/109', '127.0.0.1', '内网IP', '109', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:42:34', 25); +INSERT INTO `sys_oper_log` VALUES (140, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/108', '127.0.0.1', '内网IP', '108', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:42:36', 91); +INSERT INTO `sys_oper_log` VALUES (141, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/102', '127.0.0.1', '内网IP', '102', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:42:38', 22); +INSERT INTO `sys_oper_log` VALUES (142, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/107', '127.0.0.1', '内网IP', '107', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:42:43', 29); +INSERT INTO `sys_oper_log` VALUES (143, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/106', '127.0.0.1', '内网IP', '106', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:42:44', 30); +INSERT INTO `sys_oper_log` VALUES (144, '部门管理', 2, 'com.boyue.web.controller.system.SysDeptController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/dept', '127.0.0.1', '内网IP', '{\"ancestors\":\"0,100\",\"children\":[],\"deptId\":101,\"deptName\":\"淮安市\",\"email\":\"boyue@qq.com\",\"leader\":\"博越\",\"orderNum\":1,\"params\":{},\"parentId\":100,\"parentName\":\"博越科技\",\"phone\":\"15888888888\",\"status\":\"0\",\"updateBy\":\"admin\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:42:59', 76); +INSERT INTO `sys_oper_log` VALUES (145, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/105', '127.0.0.1', '内网IP', '105', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:43:02', 16); +INSERT INTO `sys_oper_log` VALUES (146, '部门管理', 3, 'com.boyue.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '研发部门', '/system/dept/104', '127.0.0.1', '内网IP', '104', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:43:04', 20); +INSERT INTO `sys_oper_log` VALUES (147, '部门管理', 2, 'com.boyue.web.controller.system.SysDeptController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/dept', '127.0.0.1', '内网IP', '{\"ancestors\":\"0,100,101\",\"children\":[],\"deptId\":103,\"deptName\":\"司法局部门\",\"email\":\"sfj@qq.com\",\"leader\":\"司法局\",\"orderNum\":1,\"params\":{},\"parentId\":101,\"parentName\":\"淮安市\",\"phone\":\"15888888888\",\"status\":\"0\",\"updateBy\":\"admin\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:43:41', 130); +INSERT INTO `sys_oper_log` VALUES (148, '部门管理', 2, 'com.boyue.web.controller.system.SysDeptController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/dept', '127.0.0.1', '内网IP', '{\"ancestors\":\"0,100,101\",\"children\":[],\"deptId\":103,\"deptName\":\"司法局部门\",\"email\":\"sfj@qq.com\",\"leader\":\"司法局\",\"orderNum\":2,\"params\":{},\"parentId\":101,\"parentName\":\"淮安市\",\"phone\":\"15888888888\",\"status\":\"0\",\"updateBy\":\"admin\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:43:46', 29); +INSERT INTO `sys_oper_log` VALUES (149, '部门管理', 2, 'com.boyue.web.controller.system.SysDeptController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/dept', '127.0.0.1', '内网IP', '{\"ancestors\":\"0,100,101\",\"children\":[],\"deptId\":103,\"deptName\":\"管理\",\"email\":\"sfj@qq.com\",\"leader\":\"管理\",\"orderNum\":2,\"params\":{},\"parentId\":101,\"parentName\":\"淮安市\",\"phone\":\"15888888888\",\"status\":\"0\",\"updateBy\":\"admin\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:44:34', 66); +INSERT INTO `sys_oper_log` VALUES (150, '部门管理', 1, 'com.boyue.web.controller.system.SysDeptController.add()', 'POST', 1, 'admin', '研发部门', '/system/dept', '127.0.0.1', '内网IP', '{\"ancestors\":\"0,100,101\",\"children\":[],\"createBy\":\"admin\",\"deptName\":\"司法局\",\"orderNum\":3,\"params\":{},\"parentId\":101,\"status\":\"0\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:44:51', 109); +INSERT INTO `sys_oper_log` VALUES (151, '用户管理', 1, 'com.boyue.web.controller.system.SysUserController.add()', 'POST', 1, 'admin', '研发部门', '/system/user', '127.0.0.1', '内网IP', '{\"admin\":false,\"createBy\":\"admin\",\"deptId\":103,\"nickName\":\"淮安市司法局\",\"params\":{},\"postIds\":[],\"roleIds\":[100],\"status\":\"0\",\"userId\":100,\"userName\":\"hasfj\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:45:27', 97); +INSERT INTO `sys_oper_log` VALUES (152, '用户管理', 2, 'com.boyue.web.controller.system.SysUserController.edit()', 'PUT', 1, 'admin', '研发部门', '/system/user', '127.0.0.1', '内网IP', '{\"admin\":false,\"avatar\":\"\",\"createBy\":\"admin\",\"createTime\":\"2025-05-29 08:45:27\",\"delFlag\":\"0\",\"dept\":{\"ancestors\":\"0,100,101\",\"children\":[],\"deptId\":103,\"deptName\":\"管理\",\"leader\":\"管理\",\"orderNum\":2,\"params\":{},\"parentId\":101,\"status\":\"0\"},\"deptId\":200,\"email\":\"\",\"loginIp\":\"\",\"nickName\":\"淮安市司法局\",\"params\":{},\"phonenumber\":\"\",\"postIds\":[],\"roleIds\":[100],\"roles\":[{\"admin\":false,\"dataScope\":\"1\",\"deptCheckStrictly\":false,\"flag\":false,\"menuCheckStrictly\":false,\"params\":{},\"roleId\":100,\"roleKey\":\"sfj\",\"roleName\":\"司法局\",\"roleSort\":3,\"status\":\"0\"}],\"sex\":\"0\",\"status\":\"0\",\"updateBy\":\"admin\",\"userId\":100,\"userName\":\"hasfj\"}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 08:45:53', 101); +INSERT INTO `sys_oper_log` VALUES (153, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090531_b976.png\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:05:34\",\"viewCount\":6}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:05:34', 98); +INSERT INTO `sys_oper_log` VALUES (154, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090601_37f6.xls\",\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-29 09:06:03\",\"viewCount\":2}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:06:03', 50); +INSERT INTO `sys_oper_log` VALUES (155, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090531_b976.png\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:06:36\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:06:36', 33); +INSERT INTO `sys_oper_log` VALUES (156, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090531_b976.png\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:06:55\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:06:56', 114); +INSERT INTO `sys_oper_log` VALUES (157, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090531_b976.png\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:09:59\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:09:59', 118); +INSERT INTO `sys_oper_log` VALUES (158, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090531_b976.png\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:10:41\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:10:41', 130); +INSERT INTO `sys_oper_log` VALUES (159, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:17:00\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:17:00', 144); +INSERT INTO `sys_oper_log` VALUES (160, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[{\\\"name\\\":\\\"hasfjpages_1748441672046.xlsx\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529091727_6301.xlsx\\\"},{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\\\"}]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:20:57\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:20:58', 187); +INSERT INTO `sys_oper_log` VALUES (161, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090531_b976.png\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[{\\\"name\\\":\\\"hasfjpages_1748441672046.xlsx\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529091727_6301.xlsx\\\"}]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:21:13\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:21:13', 51); +INSERT INTO `sys_oper_log` VALUES (162, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[{\\\"name\\\":\\\"hasfjpages_1748441672046.xlsx\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529091727_6301.xlsx\\\"}]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:21:22\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:21:22', 44); +INSERT INTO `sys_oper_log` VALUES (163, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529090531_b976.png\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[{\\\"name\\\":\\\"hasfjpages_1748441672046.xlsx\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529091727_6301.xlsx\\\"},{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\\\"}]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:23:39\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:23:39', 122); +INSERT INTO `sys_oper_log` VALUES (164, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"\",\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:24:17\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:24:17', 91); +INSERT INTO `sys_oper_log` VALUES (165, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"hasfjpages_1748441672046.xlsx\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529091727_6301.xlsx\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-29 09:28:48\",\"viewCount\":4}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:28:48', 31); +INSERT INTO `sys_oper_log` VALUES (166, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"hasfjpages_1748441672046.xlsx\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529091727_6301.xlsx\\\"},{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-29 09:29:02\",\"viewCount\":5}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:29:02', 95); +INSERT INTO `sys_oper_log` VALUES (167, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-29 09:29:19\",\"viewCount\":6}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:29:19', 23); +INSERT INTO `sys_oper_log` VALUES (168, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '研发部门', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"法律法规编辑部\",\"content\":\"

测试

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 09:38:39\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 09:38:39', 64); +INSERT INTO `sys_oper_log` VALUES (169, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-29 11:30:45\",\"viewCount\":9}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 11:30:45', 23); +INSERT INTO `sys_oper_log` VALUES (170, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《公司法》《个人独资企业法》《合伙企业法》

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"劳动法第四十一条解释\",\"updateTime\":\"2025-05-29 07:02:45\",\"viewCount\":215}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:02:45', 104); +INSERT INTO `sys_oper_log` VALUES (171, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

李某与王某成立“普通合伙企业”经营餐饮,后因亏损负债100万元,法院判令李某、王某承担无限连带责任。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000001\",\"id\":2,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000001\",\"params\":{},\"sortOrder\":2,\"status\":1,\"title\":\"某公司劳资纠纷典型案例\",\"updateTime\":\"2025-05-29 07:03:38\",\"viewCount\":4}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:03:38', 115); +INSERT INTO `sys_oper_log` VALUES (172, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\\\"},{\\\"name\\\":\\\"淮安市“七五”普法调查问卷.doc\\\",\\\"url\\\":\\\"http://hj.haxy.com.cn/profile/files/master/2025/05/29/20250529070442_e2a0.doc\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"劳动仲裁申请表\",\"updateTime\":\"2025-05-29 07:04:51\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:04:51', 60); +INSERT INTO `sys_oper_log` VALUES (173, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《公司法》《个人独资企业法》《合伙企业法》

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000001\",\"id\":1,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000001\",\"params\":{},\"sortOrder\":1,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-29 07:07:55\",\"viewCount\":215}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:07:55', 82); +INSERT INTO `sys_oper_log` VALUES (174, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

李某与王某成立“普通合伙企业”经营餐饮,后因亏损负债100万元,法院判令李某、王某承担无限连带责任。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000001\",\"id\":2,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000001\",\"params\":{},\"sortOrder\":2,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-29 07:08:06\",\"viewCount\":4}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:08:06', 46); +INSERT INTO `sys_oper_log` VALUES (175, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\\\"},{\\\"name\\\":\\\"淮安市“七五”普法调查问卷.doc\\\",\\\"url\\\":\\\"http://hj.haxy.com.cn/profile/files/master/2025/05/29/20250529070442_e2a0.doc\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-29 07:08:16\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:08:16', 38); +INSERT INTO `sys_oper_log` VALUES (176, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000002\",\"id\":4,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000002\",\"params\":{},\"sortOrder\":4,\"status\":1,\"title\":\"有限责任公司和股份有限公司的区别是什么?\",\"updateTime\":\"2025-05-29 07:08:49\",\"viewCount\":17}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:08:49', 56); +INSERT INTO `sys_oper_log` VALUES (177, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000002\",\"id\":5,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000002\",\"params\":{},\"sortOrder\":5,\"status\":1,\"title\":\"有限责任公司和股份有限公司的区别是什么?\",\"updateTime\":\"2025-05-29 07:08:59\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:08:59', 52); +INSERT INTO `sys_oper_log` VALUES (178, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000002\",\"id\":6,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000002\",\"params\":{},\"sortOrder\":6,\"status\":1,\"title\":\"有限责任公司和股份有限公司的区别是什么?\",\"updateTime\":\"2025-05-29 07:09:10\",\"viewCount\":1}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:09:11', 41); +INSERT INTO `sys_oper_log` VALUES (179, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

劳动法第四十一条解释

用人单位由于生产经营需要,经与工会和劳动者协商后可以延长工作时间,一般每日不得超过一小时;因特殊原因需要延长工作时间的,在保障劳动者身体健康的条件下延长工作时间每日不得超过三小时,但是每月不得超过三十六小时。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000003\",\"id\":7,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000003\",\"params\":{},\"sortOrder\":7,\"status\":1,\"title\":\"如何确定企业名称?\",\"updateTime\":\"2025-05-29 07:09:30\",\"viewCount\":15}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:09:30', 36); +INSERT INTO `sys_oper_log` VALUES (180, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

某公司劳资纠纷典型案例

本案例涉及员工加班费纠纷,公司未按照劳动法规定支付加班工资,经劳动仲裁委员会调解后,公司补发了加班工资并进行了赔偿。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000003\",\"id\":8,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000003\",\"params\":{},\"sortOrder\":8,\"status\":1,\"title\":\"如何确定企业名称?\",\"updateTime\":\"2025-05-29 07:09:40\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:09:40', 27); +INSERT INTO `sys_oper_log` VALUES (181, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000003\",\"id\":9,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000003\",\"params\":{},\"sortOrder\":9,\"status\":1,\"title\":\"如何确定企业名称?\",\"updateTime\":\"2025-05-29 07:09:50\",\"viewCount\":2}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:09:50', 17); +INSERT INTO `sys_oper_log` VALUES (182, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《证券法》第七十八条,发行人及法律、行政法规和国务院证券监督管理机构规定的其他信息披露义务人,应当及时依法履行信息披露义务。信息披露义务人披露的信息,应当真实、准确、完整,简明清晰,通俗易懂,不得有虚假记载、误导性陈述或者重大遗漏。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000002\",\"id\":4,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000002\",\"params\":{},\"sortOrder\":4,\"status\":1,\"title\":\"有限责任公司和股份有限公司的区别是什么?\",\"updateTime\":\"2025-05-29 07:11:12\",\"viewCount\":17}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:11:12', 92); +INSERT INTO `sys_oper_log` VALUES (183, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

某科技创业团队初期仅3名股东,误以为股份公司“更规范易融资”,直接注册为股份公司。因股份公司需设股东大会、董事会、监事会,团队人数不足,决策效率低下;同时需定期披露年报、重大事项,合规成本高。天使投资机构因其结构复杂、股权转让受限(需股东大会批准)放弃投资,最终公司因资金链断裂解散清算。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000002\",\"id\":5,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000002\",\"params\":{},\"sortOrder\":5,\"status\":1,\"title\":\"有限责任公司和股份有限公司的区别是什么?\",\"updateTime\":\"2025-05-29 07:11:33\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:11:33', 65); +INSERT INTO `sys_oper_log` VALUES (184, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《企业名称登记管理规定》《企业名称登记管理规定实施办法》。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000003\",\"id\":7,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000003\",\"params\":{},\"sortOrder\":7,\"status\":1,\"title\":\"如何确定企业名称?\",\"updateTime\":\"2025-05-29 07:11:54\",\"viewCount\":15}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:11:54', 41); +INSERT INTO `sys_oper_log` VALUES (185, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

甲公司注册名称为“上海特斯拉新能源科技有限公司”,未经特斯拉公司授权。法院认定其名称攀附知名品牌商誉,构成不正当竞争,判令更名并赔偿20万元。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000003\",\"id\":8,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000003\",\"params\":{},\"sortOrder\":8,\"status\":1,\"title\":\"如何确定企业名称?\",\"updateTime\":\"2025-05-29 07:12:11\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:12:11', 44); +INSERT INTO `sys_oper_log` VALUES (186, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《公司法》第十条,公司的法定代表人按照公司章程的规定,由代表公司执行公司事务的董事或者经理担任。担任法定代表人的董事或者经理辞任的,视为同时辞去法定代表人。法定代表人辞任的,公司应当在法定代表人辞任之日起三十日内确定新的法定代表人。第十一条:法定代表人以公司名义从事的民事活动,其法律后果由公司承受。公司章程或者股东会对法定代表人职权的限制,不得对抗善意相对人。法定代表人因执行职务造成他人损害的,由公司承担民事责任。公司承担民事责任后,依照法律或者公司章程的规定,可以向有过错的法定代表人追偿。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000004\",\"id\":10,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000004\",\"params\":{},\"sortOrder\":10,\"status\":1,\"title\":\"法定代表人的要求有哪些?\",\"updateTime\":\"2025-05-29 07:12:43\",\"viewCount\":7}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:12:43', 51); +INSERT INTO `sys_oper_log` VALUES (187, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

某公司法定代表人李某因个人债务被列为失信被执行人,法院限制其高消费。公司向银行申请贷款时,因李某信用瑕疵遭拒,资金链断裂导致停产。市场监管部门责令更换法定代表人,但因股东争议拖延,最终公司破产清算。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000004\",\"id\":11,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000004\",\"params\":{},\"sortOrder\":11,\"status\":1,\"title\":\"法定代表人的要求有哪些?\",\"updateTime\":\"2025-05-29 07:13:16\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:13:16', 75); +INSERT INTO `sys_oper_log` VALUES (188, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000004\",\"id\":12,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000004\",\"params\":{},\"sortOrder\":12,\"status\":1,\"title\":\"法定代表人的要求有哪些?\",\"updateTime\":\"2025-05-29 07:13:34\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:13:35', 75); +INSERT INTO `sys_oper_log` VALUES (189, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《公司法》第一百七十八条,有下列情形之一的,不得担任公司的董事、监事、高级管理人员:(一)无民事行为能力或者限制民事行为能力;(二)因贪污、贿赂、侵占财产、挪用财产或者破坏社会主义市场经济秩序,被判处刑罚,或者因犯罪被剥夺政治权利,执行期满未逾五年,被宣告缓刑的,自缓刑考验期满之日起未逾二年;(三)担任破产清算的公司、企业的董事或者厂长、经理,对该公司、企业的破产负有个人责任的,自该公司、企业破产清算完结之日起未逾三年;(四)担任因违法被吊销营业执照、责令关闭的公司、企业的法定代表人,并负有个人责任的,自该公司、企业被吊销营业执照、责令关闭之日起未逾三年;(五)个人因所负数额较大债务到期未清偿被人民法院列为失信被执行人。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000005\",\"id\":13,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000005\",\"params\":{},\"sortOrder\":13,\"status\":1,\"title\":\"董事、监事、高级管理人员的资格限制有哪些?\",\"updateTime\":\"2025-05-29 07:14:05\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:14:05', 56); +INSERT INTO `sys_oper_log` VALUES (190, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

某公司股东李某(公务员)通过亲属代持股权,后因公司债务纠纷被债权人揭发。法院认定代持协议无效,李某需退还全部股权收益,公司被处罚款10万元。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000005\",\"id\":14,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000005\",\"params\":{},\"sortOrder\":14,\"status\":1,\"title\":\"董事、监事、高级管理人员的资格限制有哪些?\",\"updateTime\":\"2025-05-29 07:14:42\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:14:42', 51); +INSERT INTO `sys_oper_log` VALUES (191, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000005\",\"id\":15,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000005\",\"params\":{},\"sortOrder\":15,\"status\":1,\"title\":\"董事、监事、高级管理人员的资格限制有哪些?\",\"updateTime\":\"2025-05-29 07:14:52\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:14:52', 39); +INSERT INTO `sys_oper_log` VALUES (192, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

最高人民法院关于适用《中华人民共和国公司法》若干问题的规定(三)第二十四条,有限责任公司的实际出资人与名义出资人订立合同,约定由实际出资人出资并享有投资权益,以名义出资人为名义股东,实际出资人与名义股东对该合同效力发生争议的,如无法律规定的无效情形,人民法院应当认定该合同有效。前款规定的实际出资人与名义股东因投资权益的归属发生争议,实际出资人以其实际履行了出资义务为由向名义股东主张权利的,人民法院应予支持。名义股东以公司股东名册记载、公司登记机关登记为由否认实际出资人权利的,人民法院不予支持。实际出资人未经公司其他股东半数以上同意,请求公司变更股东、签发出资证明书、记载于股东名册、记载于公司章程并办理公司登记机关登记的,人民法院不予支持。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000006\",\"id\":16,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000006\",\"params\":{},\"sortOrder\":16,\"status\":1,\"title\":\"隐名股东有哪些常见法律风险?\",\"updateTime\":\"2025-05-29 07:15:42\",\"viewCount\":1}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:15:42', 48); +INSERT INTO `sys_oper_log` VALUES (193, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

隐名股东李某委托张某代持某公司10%股权,张某未经同意将股权转让给王某,王某不知情且支付合理价款。王某善意取得股权,李某仅能要求张某赔偿损失。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000006\",\"id\":17,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000006\",\"params\":{},\"sortOrder\":17,\"status\":1,\"title\":\"隐名股东有哪些常见法律风险?\",\"updateTime\":\"2025-05-29 07:16:04\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:16:04', 57); +INSERT INTO `sys_oper_log` VALUES (194, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000006\",\"id\":18,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000006\",\"params\":{},\"sortOrder\":18,\"status\":1,\"title\":\"隐名股东有哪些常见法律风险?\",\"updateTime\":\"2025-05-29 07:16:18\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:16:18', 72); +INSERT INTO `sys_oper_log` VALUES (195, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《公司法》第六十五条,股东会会议由股东按照出资比例行使表决权;但是,公司章程另有规定的除外。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000007\",\"id\":19,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000007\",\"params\":{},\"sortOrder\":19,\"status\":1,\"title\":\"如何保持创始人在公司的控制权?\",\"updateTime\":\"2025-05-29 07:16:51\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:16:51', 74); +INSERT INTO `sys_oper_log` VALUES (196, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

某公司创始人通过“AB股”架构(1股10票投票权),即使持股比例仅15%,仍掌控董事会80%席位。公司上市后,其投票权超80%,确保战略决策权。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000007\",\"id\":20,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000007\",\"params\":{},\"sortOrder\":20,\"status\":1,\"title\":\"如何保持创始人在公司的控制权?\",\"updateTime\":\"2025-05-29 07:17:15\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:17:15', 54); +INSERT INTO `sys_oper_log` VALUES (197, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000007\",\"id\":21,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000007\",\"params\":{},\"sortOrder\":21,\"status\":1,\"title\":\"如何保持创始人在公司的控制权?\",\"updateTime\":\"2025-05-29 07:17:28\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:17:28', 49); +INSERT INTO `sys_oper_log` VALUES (198, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

\\t《公司法》第二百三十一条,公司经营管理发生严重困难,继续存续会使股东利益受到重大损失,通过其他途径不能解决的,持有公司百分之十以上表决权的股东,可以请求人民法院解散公司。

\\t最高人民法院关于适用《中华人民共和国公司法》若干问题的规定(二)第一条,单独或者合计持有公司全部股东表决权百分之十以上的股东,以下列事由之一提起解散公司诉讼,并符合公司法第一百八十二条规定的,人民法院应予受理:(一)公司持续两年以上无法召开股东会或者股东大会,公司经营管理发生严重困难的;(二)股东表决时无法达到法定或者公司章程规定的比例,持续两年以上不能做出有效的股东会或者股东大会决议,公司经营管理发生严重困难的;(三)公司董事长期冲突,且无法通过股东会或者股东大会解决,公司经营管理发生严重困难的;


\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000008\",\"id\":22,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000008\",\"params\":{},\"sortOrder\":22,\"status\":1,\"title\":\"如何防止出现公司僵局?\",\"updateTime\":\"2025-05-29 07:17:59\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:17:59', 68); +INSERT INTO `sys_oper_log` VALUES (199, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

某零售企业两位股东各持50%股权,因经营理念严重冲突,股东会无法通过重大决策(如拓展新店、引入投资),公司现金流枯竭,员工离职,被法院裁定解散。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000008\",\"id\":23,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000008\",\"params\":{},\"sortOrder\":23,\"status\":1,\"title\":\"如何防止出现公司僵局?\",\"updateTime\":\"2025-05-29 07:18:27\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:18:27', 61); +INSERT INTO `sys_oper_log` VALUES (200, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000008\",\"id\":24,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000008\",\"params\":{},\"sortOrder\":24,\"status\":1,\"title\":\"如何防止出现公司僵局?\",\"updateTime\":\"2025-05-29 07:18:40\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:18:40', 48); +INSERT INTO `sys_oper_log` VALUES (201, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"法律法规编辑部\",\"content\":\"

《公司法》第四条,有限责任公司的股东以其认缴的出资额为限对公司承担责任;股份有限公司的股东以其认购的股份为限对公司承担责任。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"本文解释了《中华人民共和国劳动法》第四十一条关于加班时间的规定\",\"formatId\":\"000009\",\"id\":25,\"keywords\":\"劳动法,工作时间,加班\",\"multiAttachments\":\"[]\",\"pageType\":\"law\",\"pageUrl\":\"/show.html?Id=000009\",\"params\":{},\"sortOrder\":25,\"status\":1,\"title\":\"如何合理确定注册资本?\",\"updateTime\":\"2025-05-29 07:19:12\",\"viewCount\":1}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:19:12', 51); +INSERT INTO `sys_oper_log` VALUES (202, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"案例分析组\",\"content\":\"

\\t某公司注册资本8000万元(认缴期30年),实际运营资金仅200万元。后因合同纠纷负债500万元,法院认定股东恶意设置超长认缴期,判令股东立即补缴。


\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"典型劳资纠纷案例分析及处理结果\",\"formatId\":\"000009\",\"id\":26,\"keywords\":\"劳资纠纷,加班费,劳动仲裁\",\"multiAttachments\":\"[]\",\"pageType\":\"case\",\"pageUrl\":\"/showcase.html?Id=000009\",\"params\":{},\"sortOrder\":26,\"status\":1,\"title\":\"如何合理确定注册资本?\",\"updateTime\":\"2025-05-29 07:19:32\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:19:32', 69); +INSERT INTO `sys_oper_log` VALUES (203, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'hasfj', '司法局', '/hasfj/hasfjpages', '114.238.34.181', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000009\",\"id\":27,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000009\",\"params\":{},\"sortOrder\":27,\"status\":1,\"title\":\"如何合理确定注册资本?\",\"updateTime\":\"2025-05-29 07:19:44\",\"viewCount\":0}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-29 15:19:44', 117); +INSERT INTO `sys_oper_log` VALUES (204, '司法局法律规定、典型案例、单下载-删除附件', 3, 'com.boyue.hasfj.controller.HtmlPagesController.deleteAttachment()', 'POST', 1, 'admin', '管理', '/hasfj/hasfjpages/deleteAttachment', '49.87.176.188', 'XX XX', '{\"attachmentUrl\":\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\"}', '{\"msg\":\"删除附件失败\",\"code\":500}', 0, NULL, '2025-05-31 12:12:52', 47); +INSERT INTO `sys_oper_log` VALUES (205, '司法局法律规定、典型案例、单下载-删除附件', 3, 'com.boyue.hasfj.controller.HtmlPagesController.deleteAttachment()', 'POST', 1, 'admin', '管理', '/hasfj/hasfjpages/deleteAttachment', '49.87.176.188', 'XX XX', '{\"attachmentUrl\":\"http://hj.haxy.com.cn/profile/files/master/2025/05/29/20250529070442_e2a0.doc\"}', '{\"msg\":\"删除附件失败\",\"code\":500}', 0, NULL, '2025-05-31 12:12:56', 0); +INSERT INTO `sys_oper_log` VALUES (206, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '49.87.176.188', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://localhost:9799/profile/files/master/2025/05/29/20250529092056_cc9b.zip\\\"},{\\\"name\\\":\\\"淮安市“七五”普法调查问卷.doc\\\",\\\"url\\\":\\\"http://hj.haxy.com.cn/profile/files/master/2025/05/29/20250529070442_e2a0.doc\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 04:12:58\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 12:12:58', 41); +INSERT INTO `sys_oper_log` VALUES (207, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '49.87.176.188', 'XX XX', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 14:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"01应某某不服市城管局行政处罚行政复议决定书.docx\\\",\\\"url\\\":\\\"http://hj.haxy.com.cn/profile/files/master/2025/05/31/20250531041536_0786.docx\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 04:15:40\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 12:15:40', 74); +INSERT INTO `sys_oper_log` VALUES (208, '司法局法律规定、典型案例、单下载-删除附件', 3, 'com.boyue.hasfj.controller.HtmlPagesController.deleteAttachment()', 'POST', 1, 'admin', '管理', '/hasfj/hasfjpages/deleteAttachment', '127.0.0.1', '内网IP', '{\"attachmentUrl\":\"http://hj.haxy.com.cn/profile/files/master/2025/05/31/20250531041536_0786.docx\"}', '{\"msg\":\"删除附件失败\",\"code\":500}', 0, NULL, '2025-05-31 14:50:57', 10); +INSERT INTO `sys_oper_log` VALUES (209, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"01应某某不服市城管局行政处罚行政复议决定书.docx\\\",\\\"url\\\":\\\"http://hj.haxy.com.cn/profile/files/master/2025/05/31/20250531041536_0786.docx\\\"},{\\\"name\\\":\\\"2025-05-28会议室预约记录 (2).xls\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531145236_2193.xls\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 14:52:38\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 14:52:39', 69); +INSERT INTO `sys_oper_log` VALUES (210, '司法局法律规定、典型案例、单下载-删除附件', 3, 'com.boyue.hasfj.controller.HtmlPagesController.deleteAttachment()', 'POST', 1, 'admin', '管理', '/hasfj/hasfjpages/deleteAttachment', '180.125.41.129', 'XX XX', '{\"attachmentUrl\":\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531145236_2193.xls\"}', '{\"msg\":\"删除附件失败\",\"code\":500}', 0, NULL, '2025-05-31 15:04:35', 19); +INSERT INTO `sys_oper_log` VALUES (211, '司法局法律规定、典型案例、单下载-删除附件', 3, 'com.boyue.hasfj.controller.HtmlPagesController.deleteAttachment()', 'POST', 1, 'admin', '管理', '/hasfj/hasfjpages/deleteAttachment', '180.125.41.129', 'XX XX', '{\"attachmentUrl\":\"http://hj.haxy.com.cn/profile/files/master/2025/05/31/20250531041536_0786.docx\"}', '{\"msg\":\"删除附件失败\",\"code\":500}', 0, NULL, '2025-05-31 15:04:37', 0); +INSERT INTO `sys_oper_log` VALUES (212, '司法局法律规定、典型案例、单下载-删除附件', 3, 'com.boyue.hasfj.controller.HtmlPagesController.deleteAttachment()', 'POST', 1, 'admin', '管理', '/hasfj/hasfjpages/deleteAttachment', '218.2.75.254', 'XX XX', '{\"attachmentUrl\":\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531145236_2193.xls\"}', '{\"msg\":\"删除附件失败\",\"code\":500}', 0, NULL, '2025-05-31 15:05:18', 0); +INSERT INTO `sys_oper_log` VALUES (213, '司法局法律规定、典型案例、单下载-删除附件', 3, 'com.boyue.hasfj.controller.HtmlPagesController.deleteAttachment()', 'POST', 1, 'admin', '管理', '/hasfj/hasfjpages/deleteAttachment', '218.2.75.254', 'XX XX', '{\"attachmentUrl\":\"http://hj.haxy.com.cn/profile/files/master/2025/05/31/20250531041536_0786.docx\"}', '{\"msg\":\"删除附件失败\",\"code\":500}', 0, NULL, '2025-05-31 15:05:20', 1); +INSERT INTO `sys_oper_log` VALUES (214, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:08:12\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:08:14', 569); +INSERT INTO `sys_oper_log` VALUES (215, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025创新大赛提交.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531150820_1da0.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:08:22\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:08:22', 38); +INSERT INTO `sys_oper_log` VALUES (216, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531151028_e27c.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:10:30\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:10:31', 73); +INSERT INTO `sys_oper_log` VALUES (217, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531151028_e27c.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:13:20\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:13:21', 301); +INSERT INTO `sys_oper_log` VALUES (218, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025-05-28至2025-05-28会议室预约记录 (1).xls\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531151741_e50b.xls\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:17:43\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:17:43', 109); +INSERT INTO `sys_oper_log` VALUES (219, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531151028_e27c.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:18:59\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:19:00', 71); +INSERT INTO `sys_oper_log` VALUES (220, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025-05-28至2025-05-28会议室预约记录.xls\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531152447_76e9.xls\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:24:49\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:24:49', 104); +INSERT INTO `sys_oper_log` VALUES (221, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025-05-28至2025-05-28会议室预约记录.xls\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531152447_76e9.xls\\\"},{\\\"name\\\":\\\"2025创新大赛提交.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531150820_1da0.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:25:50\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:25:51', 81); +INSERT INTO `sys_oper_log` VALUES (222, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:32:04\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:32:05', 81); +INSERT INTO `sys_oper_log` VALUES (223, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025创新大赛提交.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531150820_1da0.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 15:32:16\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 15:32:18', 641); +INSERT INTO `sys_oper_log` VALUES (224, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 19:33:31\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 19:33:32', 151); +INSERT INTO `sys_oper_log` VALUES (225, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531151028_e27c.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 19:33:52\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 19:33:53', 104); +INSERT INTO `sys_oper_log` VALUES (226, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025创新大赛提交.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531150820_1da0.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 19:46:19\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 19:46:20', 112); +INSERT INTO `sys_oper_log` VALUES (227, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025创新大赛提交.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531150820_1da0.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 20:04:39\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 20:04:40', 83); +INSERT INTO `sys_oper_log` VALUES (228, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025创新大赛提交.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531150820_1da0.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 20:14:42\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 20:14:43', 84); +INSERT INTO `sys_oper_log` VALUES (229, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"2025-05-23至2025-05-23会议室预约记录.xls\\\",\\\"url\\\":\\\"/profile/2025/05/31\\\\\\\\20250531203546_d135.xls\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-05-31 20:35:48\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-05-31 20:35:49', 100); +INSERT INTO `sys_oper_log` VALUES (230, '司法局法律规定、典型案例、单下载', 2, 'com.boyue.hasfj.controller.HtmlPagesController.edit()', 'PUT', 1, 'admin', '管理', '/hasfj/hasfjpages', '127.0.0.1', '内网IP', '{\"author\":\"表单管理员\",\"content\":\"

劳动仲裁申请表

劳动者在与用人单位发生劳动争议时,可填写此表申请劳动仲裁。

\",\"createTime\":\"2025-05-28 22:07:28\",\"description\":\"劳动争议仲裁申请表格及填写说明\",\"formatId\":\"000001\",\"id\":3,\"keywords\":\"劳动仲裁,申请表,劳动争议\",\"multiAttachments\":\"[{\\\"name\\\":\\\"boyue.zip\\\",\\\"url\\\":\\\"http://127.0.0.1:9799/profile/files/master/2025/05/31/20250531151028_e27c.zip\\\"}]\",\"pageType\":\"form\",\"pageUrl\":\"/table.html?Id=000001\",\"params\":{},\"sortOrder\":3,\"status\":1,\"title\":\"如何确定企业形式\",\"updateTime\":\"2025-06-01 11:03:48\",\"viewCount\":11}', '{\"msg\":\"操作成功\",\"code\":200}', 0, NULL, '2025-06-01 11:03:49', 346); + +-- ---------------------------- +-- Table structure for sys_post +-- ---------------------------- +DROP TABLE IF EXISTS `sys_post`; +CREATE TABLE `sys_post` ( + `post_id` bigint NOT NULL AUTO_INCREMENT COMMENT '岗位ID', + `post_code` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '岗位编码', + `post_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '岗位名称', + `post_sort` int NOT NULL COMMENT '显示顺序', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '状态(0正常 1停用)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`post_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '岗位信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_post +-- ---------------------------- +INSERT INTO `sys_post` VALUES (1, 'ceo', '董事长', 1, '0', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_post` VALUES (2, 'se', '项目经理', 2, '0', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_post` VALUES (3, 'hr', '人力资源', 3, '0', 'admin', '2025-05-26 17:20:06', '', NULL, ''); +INSERT INTO `sys_post` VALUES (4, 'user', '普通员工', 4, '0', 'admin', '2025-05-26 17:20:06', '', NULL, ''); + +-- ---------------------------- +-- Table structure for sys_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role`; +CREATE TABLE `sys_role` ( + `role_id` bigint NOT NULL AUTO_INCREMENT COMMENT '角色ID', + `role_name` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '角色名称', + `role_key` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '角色权限字符串', + `role_sort` int NOT NULL COMMENT '显示顺序', + `data_scope` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '1' COMMENT '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)', + `menu_check_strictly` tinyint(1) NULL DEFAULT 1 COMMENT '菜单树选择项是否关联显示', + `dept_check_strictly` tinyint(1) NULL DEFAULT 1 COMMENT '部门树选择项是否关联显示', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '角色状态(0正常 1停用)', + `del_flag` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`role_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 101 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '角色信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role +-- ---------------------------- +INSERT INTO `sys_role` VALUES (1, '超级管理员', 'admin', 1, '1', 1, 1, '0', '0', 'admin', '2025-05-26 17:20:06', '', NULL, '超级管理员'); +INSERT INTO `sys_role` VALUES (2, '普通角色', 'common', 2, '2', 1, 1, '0', '0', 'admin', '2025-05-26 17:20:06', '', NULL, '普通角色'); +INSERT INTO `sys_role` VALUES (100, '司法局', 'sfj', 3, '1', 1, 1, '0', '0', 'admin', '2025-05-29 08:41:41', '', NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_role_dept +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role_dept`; +CREATE TABLE `sys_role_dept` ( + `role_id` bigint NOT NULL COMMENT '角色ID', + `dept_id` bigint NOT NULL COMMENT '部门ID', + PRIMARY KEY (`role_id`, `dept_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '角色和部门关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role_dept +-- ---------------------------- +INSERT INTO `sys_role_dept` VALUES (2, 100); +INSERT INTO `sys_role_dept` VALUES (2, 101); +INSERT INTO `sys_role_dept` VALUES (2, 105); + +-- ---------------------------- +-- Table structure for sys_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role_menu`; +CREATE TABLE `sys_role_menu` ( + `role_id` bigint NOT NULL COMMENT '角色ID', + `menu_id` bigint NOT NULL COMMENT '菜单ID', + PRIMARY KEY (`role_id`, `menu_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '角色和菜单关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role_menu +-- ---------------------------- +INSERT INTO `sys_role_menu` VALUES (2, 1); +INSERT INTO `sys_role_menu` VALUES (2, 2); +INSERT INTO `sys_role_menu` VALUES (2, 3); +INSERT INTO `sys_role_menu` VALUES (2, 4); +INSERT INTO `sys_role_menu` VALUES (2, 100); +INSERT INTO `sys_role_menu` VALUES (2, 101); +INSERT INTO `sys_role_menu` VALUES (2, 102); +INSERT INTO `sys_role_menu` VALUES (2, 103); +INSERT INTO `sys_role_menu` VALUES (2, 104); +INSERT INTO `sys_role_menu` VALUES (2, 105); +INSERT INTO `sys_role_menu` VALUES (2, 106); +INSERT INTO `sys_role_menu` VALUES (2, 107); +INSERT INTO `sys_role_menu` VALUES (2, 108); +INSERT INTO `sys_role_menu` VALUES (2, 109); +INSERT INTO `sys_role_menu` VALUES (2, 110); +INSERT INTO `sys_role_menu` VALUES (2, 111); +INSERT INTO `sys_role_menu` VALUES (2, 112); +INSERT INTO `sys_role_menu` VALUES (2, 113); +INSERT INTO `sys_role_menu` VALUES (2, 114); +INSERT INTO `sys_role_menu` VALUES (2, 115); +INSERT INTO `sys_role_menu` VALUES (2, 116); +INSERT INTO `sys_role_menu` VALUES (2, 117); +INSERT INTO `sys_role_menu` VALUES (2, 500); +INSERT INTO `sys_role_menu` VALUES (2, 501); +INSERT INTO `sys_role_menu` VALUES (2, 1000); +INSERT INTO `sys_role_menu` VALUES (2, 1001); +INSERT INTO `sys_role_menu` VALUES (2, 1002); +INSERT INTO `sys_role_menu` VALUES (2, 1003); +INSERT INTO `sys_role_menu` VALUES (2, 1004); +INSERT INTO `sys_role_menu` VALUES (2, 1005); +INSERT INTO `sys_role_menu` VALUES (2, 1006); +INSERT INTO `sys_role_menu` VALUES (2, 1007); +INSERT INTO `sys_role_menu` VALUES (2, 1008); +INSERT INTO `sys_role_menu` VALUES (2, 1009); +INSERT INTO `sys_role_menu` VALUES (2, 1010); +INSERT INTO `sys_role_menu` VALUES (2, 1011); +INSERT INTO `sys_role_menu` VALUES (2, 1012); +INSERT INTO `sys_role_menu` VALUES (2, 1013); +INSERT INTO `sys_role_menu` VALUES (2, 1014); +INSERT INTO `sys_role_menu` VALUES (2, 1015); +INSERT INTO `sys_role_menu` VALUES (2, 1016); +INSERT INTO `sys_role_menu` VALUES (2, 1017); +INSERT INTO `sys_role_menu` VALUES (2, 1018); +INSERT INTO `sys_role_menu` VALUES (2, 1019); +INSERT INTO `sys_role_menu` VALUES (2, 1020); +INSERT INTO `sys_role_menu` VALUES (2, 1021); +INSERT INTO `sys_role_menu` VALUES (2, 1022); +INSERT INTO `sys_role_menu` VALUES (2, 1023); +INSERT INTO `sys_role_menu` VALUES (2, 1024); +INSERT INTO `sys_role_menu` VALUES (2, 1025); +INSERT INTO `sys_role_menu` VALUES (2, 1026); +INSERT INTO `sys_role_menu` VALUES (2, 1027); +INSERT INTO `sys_role_menu` VALUES (2, 1028); +INSERT INTO `sys_role_menu` VALUES (2, 1029); +INSERT INTO `sys_role_menu` VALUES (2, 1030); +INSERT INTO `sys_role_menu` VALUES (2, 1031); +INSERT INTO `sys_role_menu` VALUES (2, 1032); +INSERT INTO `sys_role_menu` VALUES (2, 1033); +INSERT INTO `sys_role_menu` VALUES (2, 1034); +INSERT INTO `sys_role_menu` VALUES (2, 1035); +INSERT INTO `sys_role_menu` VALUES (2, 1036); +INSERT INTO `sys_role_menu` VALUES (2, 1037); +INSERT INTO `sys_role_menu` VALUES (2, 1038); +INSERT INTO `sys_role_menu` VALUES (2, 1039); +INSERT INTO `sys_role_menu` VALUES (2, 1040); +INSERT INTO `sys_role_menu` VALUES (2, 1041); +INSERT INTO `sys_role_menu` VALUES (2, 1042); +INSERT INTO `sys_role_menu` VALUES (2, 1043); +INSERT INTO `sys_role_menu` VALUES (2, 1044); +INSERT INTO `sys_role_menu` VALUES (2, 1045); +INSERT INTO `sys_role_menu` VALUES (2, 1046); +INSERT INTO `sys_role_menu` VALUES (2, 1047); +INSERT INTO `sys_role_menu` VALUES (2, 1048); +INSERT INTO `sys_role_menu` VALUES (2, 1049); +INSERT INTO `sys_role_menu` VALUES (2, 1050); +INSERT INTO `sys_role_menu` VALUES (2, 1051); +INSERT INTO `sys_role_menu` VALUES (2, 1052); +INSERT INTO `sys_role_menu` VALUES (2, 1053); +INSERT INTO `sys_role_menu` VALUES (2, 1054); +INSERT INTO `sys_role_menu` VALUES (2, 1055); +INSERT INTO `sys_role_menu` VALUES (2, 1056); +INSERT INTO `sys_role_menu` VALUES (2, 1057); +INSERT INTO `sys_role_menu` VALUES (2, 1058); +INSERT INTO `sys_role_menu` VALUES (2, 1059); +INSERT INTO `sys_role_menu` VALUES (2, 1060); +INSERT INTO `sys_role_menu` VALUES (100, 1); +INSERT INTO `sys_role_menu` VALUES (100, 100); +INSERT INTO `sys_role_menu` VALUES (100, 1000); +INSERT INTO `sys_role_menu` VALUES (100, 1001); +INSERT INTO `sys_role_menu` VALUES (100, 1002); +INSERT INTO `sys_role_menu` VALUES (100, 1003); +INSERT INTO `sys_role_menu` VALUES (100, 1004); +INSERT INTO `sys_role_menu` VALUES (100, 1005); +INSERT INTO `sys_role_menu` VALUES (100, 1006); +INSERT INTO `sys_role_menu` VALUES (100, 2097); +INSERT INTO `sys_role_menu` VALUES (100, 2099); +INSERT INTO `sys_role_menu` VALUES (100, 2100); +INSERT INTO `sys_role_menu` VALUES (100, 2101); +INSERT INTO `sys_role_menu` VALUES (100, 2102); +INSERT INTO `sys_role_menu` VALUES (100, 2103); +INSERT INTO `sys_role_menu` VALUES (100, 2104); + +-- ---------------------------- +-- Table structure for sys_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user`; +CREATE TABLE `sys_user` ( + `user_id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID', + `dept_id` bigint NULL DEFAULT NULL COMMENT '部门ID', + `user_name` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户账号', + `nick_name` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户昵称', + `user_type` varchar(2) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '00' COMMENT '用户类型(00系统用户)', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '用户邮箱', + `phonenumber` varchar(11) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '手机号码', + `sex` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '用户性别(0男 1女 2未知)', + `avatar` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '头像地址', + `password` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '密码', + `status` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '帐号状态(0正常 1停用)', + `del_flag` char(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `login_ip` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '最后登录IP', + `login_date` datetime NULL DEFAULT NULL COMMENT '最后登录时间', + `create_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`user_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 101 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user +-- ---------------------------- +INSERT INTO `sys_user` VALUES (1, 103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', 'avatar/admin/1/20250526183841-avatar.png', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '218.2.75.254', '2025-06-02 19:33:32', 'admin', '2025-05-26 17:20:06', '', '2025-06-02 19:33:32', '管理员'); +INSERT INTO `sys_user` VALUES (2, 105, 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '2', '127.0.0.1', '2025-05-26 17:20:06', 'admin', '2025-05-26 17:20:06', '', NULL, '测试员'); +INSERT INTO `sys_user` VALUES (100, 200, 'hasfj', '淮安市司法局', '00', '', '', '0', '', '$2a$10$.ZiW8u/mWmHPannD4ewWOenMlUR/BD6lYUrVJopOWfB69..5BJEx2', '0', '0', '114.238.34.181', '2025-05-29 14:57:16', 'admin', '2025-05-29 08:45:27', 'admin', '2025-05-29 14:57:15', NULL); + +-- ---------------------------- +-- Table structure for sys_user_post +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_post`; +CREATE TABLE `sys_user_post` ( + `user_id` bigint NOT NULL COMMENT '用户ID', + `post_id` bigint NOT NULL COMMENT '岗位ID', + PRIMARY KEY (`user_id`, `post_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户与岗位关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user_post +-- ---------------------------- +INSERT INTO `sys_user_post` VALUES (1, 1); + +-- ---------------------------- +-- Table structure for sys_user_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_role`; +CREATE TABLE `sys_user_role` ( + `user_id` bigint NOT NULL COMMENT '用户ID', + `role_id` bigint NOT NULL COMMENT '角色ID', + PRIMARY KEY (`user_id`, `role_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户和角色关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user_role +-- ---------------------------- +INSERT INTO `sys_user_role` VALUES (1, 1); +INSERT INTO `sys_user_role` VALUES (100, 100); + +SET FOREIGN_KEY_CHECKS = 1;