securityReferences = new ArrayList<>();
+ securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
+ return securityReferences;
+ }
+
+ /**
+ * 添加摘要信息
+ */
+ private ApiInfo apiInfo () {
+ // 用ApiInfoBuilder进行定制
+ return new ApiInfoBuilder()
+ // 设置标题
+ .title("标题:接口文档")
+ // 描述
+ .description("描述:接口文档")
+ // 作者信息
+ .contact(new Contact(ruoyiConfig.getName(), null, null))
+ // 版本
+ .version("版本号:" + ruoyiConfig.getVersion())
+ .build();
+ }
+}
diff --git a/ruoyi-application/src/main/resources/META-INF/spring-devtools.properties b/ruoyi-application/src/main/resources/META-INF/spring-devtools.properties
new file mode 100644
index 0000000..2b23f85
--- /dev/null
+++ b/ruoyi-application/src/main/resources/META-INF/spring-devtools.properties
@@ -0,0 +1 @@
+restart.include.json=/com.alibaba.fastjson.*.jar
\ No newline at end of file
diff --git a/ruoyi-application/src/main/resources/application-dev.yml b/ruoyi-application/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..aedb2af
--- /dev/null
+++ b/ruoyi-application/src/main/resources/application-dev.yml
@@ -0,0 +1,90 @@
+# Swagger配置
+swagger:
+ # 是否开启swagger
+ enabled: true
+ # 请求前缀
+ pathMapping: /dev-api
+
+# 数据源配置
+spring:
+ # redis 配置
+ redis:
+ # 地址
+ host: localhost
+ # 端口,默认为6379
+ port: 6379
+ # 数据库索引
+ database: 0
+ # 密码
+ password:
+ # 连接超时时间
+ timeout: 10s
+ lettuce:
+ pool:
+ # 连接池中的最小空闲连接
+ min-idle: 0
+ # 连接池中的最大空闲连接
+ max-idle: 8
+ # 连接池的最大数据库连接数
+ max-active: 8
+ # #连接池最大阻塞等待时间(使用负值表示没有限制)
+ max-wait: -1ms
+ datasource:
+ type: com.alibaba.druid.pool.DruidDataSource
+ driverClassName: com.mysql.cj.jdbc.Driver
+ druid:
+ # 主库数据源
+ master:
+ url: jdbc:mysql://114.55.65.243:3306/vue-server?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+ username: root
+ password: 1234
+ # 从库数据源
+ slave:
+ # 从数据源开关/默认关闭
+ enabled: false
+ url:
+ username:
+ password:
+ # 初始连接数
+ initialSize: 5
+ # 最小连接池数量
+ minIdle: 10
+ # 最大连接池数量
+ maxActive: 20
+ # 配置获取连接等待超时的时间
+ maxWait: 60000
+ # 配置连接超时时间
+ connectTimeout: 30000
+ # 配置网络超时时间
+ socketTimeout: 60000
+ # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+ timeBetweenEvictionRunsMillis: 60000
+ # 配置一个连接在池中最小生存的时间,单位是毫秒
+ minEvictableIdleTimeMillis: 300000
+ # 配置一个连接在池中最大生存的时间,单位是毫秒
+ maxEvictableIdleTimeMillis: 900000
+ # 配置检测连接是否有效
+ validationQuery: SELECT 1 FROM DUAL
+ testWhileIdle: true
+ testOnBorrow: false
+ testOnReturn: false
+ webStatFilter:
+ enabled: true
+ statViewServlet:
+ enabled: true
+ # 设置白名单,不填则允许所有访问
+ allow:
+ url-pattern: /druid/*
+ # 控制台管理用户名和密码
+ login-username: ruoyi
+ login-password: 123456
+ filter:
+ stat:
+ enabled: true
+ # 慢SQL记录
+ log-slow-sql: true
+ slow-sql-millis: 1000
+ merge-sql: true
+ wall:
+ config:
+ multi-statement-allow: true
diff --git a/ruoyi-application/src/main/resources/application-test.yml b/ruoyi-application/src/main/resources/application-test.yml
new file mode 100644
index 0000000..4b976ac
--- /dev/null
+++ b/ruoyi-application/src/main/resources/application-test.yml
@@ -0,0 +1,90 @@
+# Swagger配置
+swagger:
+ # 是否开启swagger
+ enabled: false
+ # 请求前缀
+ pathMapping: /dev-api
+
+# 数据源配置
+spring:
+ # redis 配置
+ redis:
+ # 地址
+ host: localhost
+ # 端口,默认为6379
+ port: 6379
+ # 数据库索引
+ database: 0
+ # 密码
+ password:
+ # 连接超时时间
+ timeout: 10s
+ lettuce:
+ pool:
+ # 连接池中的最小空闲连接
+ min-idle: 0
+ # 连接池中的最大空闲连接
+ max-idle: 8
+ # 连接池的最大数据库连接数
+ max-active: 8
+ # #连接池最大阻塞等待时间(使用负值表示没有限制)
+ max-wait: -1ms
+ datasource:
+ type: com.alibaba.druid.pool.DruidDataSource
+ driverClassName: com.mysql.cj.jdbc.Driver
+ druid:
+ # 主库数据源
+ master:
+ url: jdbc:mysql://114.55.65.243:3306/vue-server?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+ username: root
+ password: 1234
+ # 从库数据源
+ slave:
+ # 从数据源开关/默认关闭
+ enabled: false
+ url:
+ username:
+ password:
+ # 初始连接数
+ initialSize: 5
+ # 最小连接池数量
+ minIdle: 10
+ # 最大连接池数量
+ maxActive: 20
+ # 配置获取连接等待超时的时间
+ maxWait: 60000
+ # 配置连接超时时间
+ connectTimeout: 30000
+ # 配置网络超时时间
+ socketTimeout: 60000
+ # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+ timeBetweenEvictionRunsMillis: 60000
+ # 配置一个连接在池中最小生存的时间,单位是毫秒
+ minEvictableIdleTimeMillis: 300000
+ # 配置一个连接在池中最大生存的时间,单位是毫秒
+ maxEvictableIdleTimeMillis: 900000
+ # 配置检测连接是否有效
+ validationQuery: SELECT 1 FROM DUAL
+ testWhileIdle: true
+ testOnBorrow: false
+ testOnReturn: false
+ webStatFilter:
+ enabled: true
+ statViewServlet:
+ enabled: true
+ # 设置白名单,不填则允许所有访问
+ allow:
+ url-pattern: /druid/*
+ # 控制台管理用户名和密码
+ login-username: ruoyi
+ login-password: 123456
+ filter:
+ stat:
+ enabled: true
+ # 慢SQL记录
+ log-slow-sql: true
+ slow-sql-millis: 1000
+ merge-sql: true
+ wall:
+ config:
+ multi-statement-allow: true
diff --git a/ruoyi-application/src/main/resources/application.yml b/ruoyi-application/src/main/resources/application.yml
new file mode 100644
index 0000000..97c47a9
--- /dev/null
+++ b/ruoyi-application/src/main/resources/application.yml
@@ -0,0 +1,97 @@
+# 项目相关配置
+ruoyi:
+ # 名称
+ name: RuoYi
+ # 版本
+ version: 3.8.6
+ # 版权年份
+ copyrightYear: 2023
+ # 实例演示开关
+ demoEnabled: true
+ # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
+ profile: D:/ruoyi/uploadPath
+ # 获取ip地址开关
+ addressEnabled: false
+ # 验证码类型 math 数字计算 char 字符验证
+ captchaType: math
+
+# 开发环境配置
+server:
+ # 服务器的HTTP端口,默认为8080
+ port: 8080
+ 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.ruoyi: debug
+ org.springframework: warn
+
+# 用户配置
+user:
+ password:
+ # 密码最大错误次数
+ maxRetryCount: 5
+ # 密码锁定时间(默认10分钟)
+ lockTime: 10
+
+# Spring配置
+spring:
+ # 资源信息
+ messages:
+ # 国际化资源文件路径
+ basename: i18n/messages
+ profiles:
+ active: dev
+ # 文件上传
+ servlet:
+ multipart:
+ # 单个文件大小
+ max-file-size: 10MB
+ # 设置总上传的文件大小
+ max-request-size: 20MB
+
+
+# token配置
+token:
+ # 令牌自定义标识
+ header: Authorization
+ # 令牌密钥
+ secret: abcdefghijklmnopqrstuvwxyz
+ # 令牌有效期(默认30分钟)
+ expireTime: 30
+
+# MyBatis配置
+mybatis:
+ # 配置mapper的扫描,找到所有的mapper.xml映射文件
+ mapperLocations: classpath*:mapper/**/*Mapper.xml
+ # 加载全局的配置文件
+ configLocation: classpath:mybatis/mybatis-config.xml
+
+# PageHelper分页插件
+pagehelper:
+ helperDialect: mysql
+ supportMethodsArguments: true
+ params: count=countSql
+
+
+# 防止XSS攻击
+xss:
+ # 过滤开关
+ enabled: true
+ # 排除链接(多个用逗号分隔)
+ excludes: /system/notice
+ # 匹配链接
+ urlPatterns: /system/*,/monitor/*,/tool/*
diff --git a/ruoyi-application/src/main/resources/banner.txt b/ruoyi-application/src/main/resources/banner.txt
new file mode 100644
index 0000000..c0e09cd
--- /dev/null
+++ b/ruoyi-application/src/main/resources/banner.txt
@@ -0,0 +1,2 @@
+Application Version: ${ruoyi.version}
+Spring Boot Version: ${spring-boot.version}
diff --git a/ruoyi-application/src/main/resources/i18n/messages.properties b/ruoyi-application/src/main/resources/i18n/messages.properties
new file mode 100644
index 0000000..dbd997b
--- /dev/null
+++ b/ruoyi-application/src/main/resources/i18n/messages.properties
@@ -0,0 +1,33 @@
+#错误消息
+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/ruoyi-application/src/main/resources/logback.xml b/ruoyi-application/src/main/resources/logback.xml
new file mode 100644
index 0000000..ef785a0
--- /dev/null
+++ b/ruoyi-application/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}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-application/src/main/resources/mybatis/mybatis-config.xml b/ruoyi-application/src/main/resources/mybatis/mybatis-config.xml
new file mode 100644
index 0000000..54dacde
--- /dev/null
+++ b/ruoyi-application/src/main/resources/mybatis/mybatis-config.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-basic/pom.xml b/ruoyi-basic/pom.xml
new file mode 100644
index 0000000..3660df6
--- /dev/null
+++ b/ruoyi-basic/pom.xml
@@ -0,0 +1,27 @@
+
+
+ 4.0.0
+
+ com.muyu
+ ruoyi
+ 3.8.6
+
+
+ ruoyi-basic
+ pom
+
+ ruoyi-plugin
+ ruoyi-framework
+ ruoyi-system
+ ruoyi-common
+
+
+
+ 17
+ 17
+ UTF-8
+
+
+
diff --git a/ruoyi-basic/ruoyi-common/pom.xml b/ruoyi-basic/ruoyi-common/pom.xml
new file mode 100644
index 0000000..4c02e60
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/pom.xml
@@ -0,0 +1,160 @@
+
+
+
+ ruoyi-basic
+ com.muyu
+ 3.8.6
+
+ 4.0.0
+
+ ruoyi-common
+
+
+ common通用工具
+
+
+
+
+
+
+ org.springframework
+ spring-context-support
+
+
+
+
+ org.springframework
+ spring-web
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+
+ com.github.pagehelper
+ pagehelper-spring-boot-starter
+
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ 3.5.3.1
+
+
+ com.github.jsqlparser
+ jsqlparser
+
+
+ org.mybatis
+ mybatis
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+
+ com.baomidou
+ dynamic-datasource-spring-boot-starter
+ 3.5.2
+
+
+
+
+ com.alibaba.fastjson2
+ fastjson2
+
+
+
+
+ commons-io
+ commons-io
+
+
+
+
+ org.apache.poi
+ poi-ooxml
+
+
+
+
+ org.yaml
+ snakeyaml
+
+
+
+
+ io.jsonwebtoken
+ jjwt
+
+
+
+
+ javax.xml.bind
+ jaxb-api
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+
+
+ org.apache.commons
+ commons-pool2
+
+
+
+
+ eu.bitwalker
+ UserAgentUtils
+
+
+
+
+ javax.servlet
+ javax.servlet-api
+
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+ io.swagger
+ swagger-annotations
+ 1.5.20
+
+
+
+
+
diff --git a/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java
new file mode 100644
index 0000000..2b719da
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java
@@ -0,0 +1,14 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 匿名访问不鉴权注解
+ *
+ * @author ruoyi
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Anonymous {
+}
diff --git a/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java
new file mode 100644
index 0000000..dfaaeac
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java
@@ -0,0 +1,28 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 数据权限过滤注解
+ *
+ * @author ruoyi
+ */
+@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/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
new file mode 100644
index 0000000..0b105a8
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
@@ -0,0 +1,23 @@
+package com.ruoyi.common.annotation;
+
+import com.ruoyi.common.enums.DataSourceType;
+
+import java.lang.annotation.*;
+
+/**
+ * 自定义多数据源切换注解
+ *
+ * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
+ *
+ * @author ruoyi
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface DataSource {
+ /**
+ * 切换数据源名称
+ */
+ public DataSourceType value () default DataSourceType.MASTER;
+}
diff --git a/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java
new file mode 100644
index 0000000..a06580f
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java
@@ -0,0 +1,216 @@
+package com.ruoyi.common.annotation;
+
+import com.ruoyi.common.utils.poi.ExcelHandlerAdapter;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.math.BigDecimal;
+
+/**
+ * 自定义导出Excel数据注解
+ *
+ * @author ruoyi
+ */
+@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 int roundingMode () default BigDecimal.ROUND_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 String[] combo () default {};
+
+ /**
+ * 是否需要纵向合并单元格,应对需求:含有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);
+
+ /**
+ * 枚举类型值
+ */
+ private final int value;
+
+ /**
+ * 类类型枚举构造器
+ * @param value 枚举类型值
+ */
+ ColumnType (int value) {
+ this.value = value;
+ }
+
+ /**
+ * 获取列枚举类型
+ * @return 枚举值
+ */
+ public int value () {
+ return this.value;
+ }
+ }
+}
diff --git a/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java
new file mode 100644
index 0000000..25dbff3
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java
@@ -0,0 +1,17 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Excel注解集
+ *
+ * @author ruoyi
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Excels {
+ public Excel[] value ();
+}
diff --git a/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
new file mode 100644
index 0000000..33fbb40
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
@@ -0,0 +1,46 @@
+package com.ruoyi.common.annotation;
+
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.enums.OperatorType;
+
+import java.lang.annotation.*;
+
+/**
+ * 自定义操作日志记录注解
+ *
+ * @author ruoyi
+ */
+@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/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
new file mode 100644
index 0000000..70a45c3
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
@@ -0,0 +1,36 @@
+package com.ruoyi.common.annotation;
+
+import com.ruoyi.common.constant.CacheConstants;
+import com.ruoyi.common.enums.LimitType;
+
+import java.lang.annotation.*;
+
+/**
+ * 限流注解
+ *
+ * @author ruoyi
+ */
+@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/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
new file mode 100644
index 0000000..69dca56
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
@@ -0,0 +1,24 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 自定义注解防止表单重复提交
+ *
+ * @author ruoyi
+ */
+@Inherited
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RepeatSubmit {
+ /**
+ * 间隔时间(ms),小于此时间视为重复提交
+ */
+ public int interval () default 5000;
+
+ /**
+ * 提示消息
+ */
+ public String message () default "不允许重复提交,请稍候再试";
+}
diff --git a/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
new file mode 100644
index 0000000..ae50d19
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
@@ -0,0 +1,126 @@
+package com.ruoyi.common.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 读取项目相关配置
+ *
+ * @author ruoyi
+ */
+@Component
+@ConfigurationProperties(prefix = "ruoyi")
+public class RuoYiConfig {
+ /**
+ * 上传路径
+ */
+ private static String profile;
+ /**
+ * 获取地址开关
+ */
+ private static boolean addressEnabled;
+ /**
+ * 验证码类型
+ */
+ private static String captchaType;
+ /**
+ * 项目名称
+ */
+ private String name;
+ /**
+ * 版本
+ */
+ private String version;
+ /**
+ * 版权年份
+ */
+ private String copyrightYear;
+ /**
+ * 实例演示开关
+ */
+ private boolean demoEnabled;
+
+ public static String getProfile () {
+ return profile;
+ }
+
+ public void setProfile (String profile) {
+ RuoYiConfig.profile = profile;
+ }
+
+ public static boolean isAddressEnabled () {
+ return addressEnabled;
+ }
+
+ public void setAddressEnabled (boolean addressEnabled) {
+ RuoYiConfig.addressEnabled = addressEnabled;
+ }
+
+ public static String getCaptchaType () {
+ return captchaType;
+ }
+
+ public void setCaptchaType (String captchaType) {
+ RuoYiConfig.captchaType = captchaType;
+ }
+
+ /**
+ * 获取导入上传路径
+ */
+ 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";
+ }
+
+ 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 boolean isDemoEnabled () {
+ return demoEnabled;
+ }
+
+ public void setDemoEnabled (boolean demoEnabled) {
+ this.demoEnabled = demoEnabled;
+ }
+}
diff --git a/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
new file mode 100644
index 0000000..1d3f457
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
@@ -0,0 +1,43 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 缓存的key 常量
+ *
+ * @author ruoyi
+ */
+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:";
+}
diff --git a/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
new file mode 100644
index 0000000..1fbc506
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
@@ -0,0 +1,146 @@
+package com.ruoyi.common.constant;
+
+import io.jsonwebtoken.Claims;
+
+/**
+ * 通用常量信息
+ *
+ * @author ruoyi
+ */
+public class Constants {
+ /**
+ * UTF-8 字符集
+ */
+ public static final String UTF8 = "UTF-8";
+
+ /**
+ * GBK 字符集
+ */
+ public static final String GBK = "GBK";
+
+ /**
+ * 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 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.ruoyi"};
+
+ /**
+ * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
+ */
+ public static final String[] JOB_WHITELIST_STR = {"com.ruoyi"};
+
+ /**
+ * 定时任务违规的字符
+ */
+ public static final String[] JOB_ERROR_STR = {"java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
+ "org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config"};
+}
diff --git a/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
new file mode 100644
index 0000000..bb306cd
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
@@ -0,0 +1,181 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 代码生成通用常量
+ *
+ * @author ruoyi
+ */
+public class GenConstants {
+ /**
+ * 单表(增删改查)
+ */
+ public static final String TPL_CRUD = "crud";
+
+ /**
+ * 树表(增删改查)
+ */
+ public static final String TPL_TREE = "tree";
+
+ /**
+ * 树编码字段
+ */
+ 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_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 = "Date";
+
+ /**
+ * 模糊查询
+ */
+ public static final String QUERY_LIKE = "LIKE";
+
+ /**
+ * 相等查询
+ */
+ public static final String QUERY_EQ = "EQ";
+
+ /**
+ * 需要
+ */
+ public static final String REQUIRE = "1";
+}
diff --git a/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java
new file mode 100644
index 0000000..54a2439
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java
@@ -0,0 +1,93 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 返回状态码
+ *
+ * @author ruoyi
+ */
+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/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java
new file mode 100644
index 0000000..990f326
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java
@@ -0,0 +1,56 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 任务调度通用常量
+ *
+ * @author ruoyi
+ */
+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/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
new file mode 100644
index 0000000..23396cc
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
@@ -0,0 +1,111 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 用户常量信息
+ *
+ * @author ruoyi
+ */
+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_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/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
new file mode 100644
index 0000000..b276270
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
@@ -0,0 +1,170 @@
+package com.ruoyi.common.core.controller;
+
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.ruoyi.common.core.domain.Result;
+import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.core.page.PageDomain;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.core.page.TableSupport;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.PageUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.sql.SqlUtil;
+import org.apache.poi.ss.formula.functions.T;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.bind.annotation.InitBinder;
+
+import java.beans.PropertyEditorSupport;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * web层通用数据处理
+ *
+ * @author ruoyi
+ */
+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 Result> getDataTable (List list) {
+ return Result.success(
+ TableDataInfo.builder()
+ .total(new PageInfo(list).getTotal())
+ .rows(list)
+ .build()
+ , "查询成功");
+ }
+
+ /**
+ * 返回成功
+ */
+ public Result success () {
+ return Result.success();
+ }
+
+ /**
+ * 返回失败消息
+ */
+ public Result error () {
+ return Result.error();
+ }
+
+
+ /**
+ * 返回失败消息
+ */
+ public Result error (String message) {
+ return Result.error(message);
+ }
+
+ /**
+ * 返回警告消息
+ */
+ public Result warn (String message) {
+ return Result.warn(message);
+ }
+
+ /**
+ * 响应返回结果
+ *
+ * @param rows 影响行数
+ *
+ * @return 操作结果
+ */
+ protected Result toAjax (int rows) {
+ return rows > 0 ? Result.success() : Result.error();
+ }
+
+ /**
+ * 响应返回结果
+ *
+ * @param result 结果
+ *
+ * @return 操作结果
+ */
+ protected Result toAjax (boolean result) {
+ return result ? success() : error();
+ }
+
+ /**
+ * 页面跳转
+ */
+ public String redirect (String url) {
+ return StringUtils.format("redirect:{}", url);
+ }
+
+ /**
+ * 获取用户缓存信息
+ */
+ public static 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/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
new file mode 100644
index 0000000..53151e0
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
@@ -0,0 +1,119 @@
+package com.ruoyi.common.core.domain;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.ruoyi.common.core.page.ReqDomain;
+import com.ruoyi.common.utils.StringUtils;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Entity基类
+ *
+ * @author ruoyi
+ */
+@Data
+@SuperBuilder
+@NoArgsConstructor
+@AllArgsConstructor
+public class BaseEntity implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 搜索值
+ */
+ @JsonIgnore
+ @TableField(exist = false)
+ private String searchValue;
+
+ /**
+ * 创建者
+ */
+ @TableField(value = "create_by" , fill = FieldFill.INSERT , exist = false)
+ @ApiModelProperty(hidden=true)
+ private Long createBy;
+
+ /**
+ * 创建时间
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @TableField(value = "create_time" , fill = FieldFill.INSERT , exist = false)
+ @ApiModelProperty(hidden=true)
+ private Date createTime;
+
+ /**
+ * 更新者
+ */
+ @TableField(value = "update_by" , fill = FieldFill.UPDATE , exist = false)
+ @ApiModelProperty(hidden=true)
+ private Long updateBy;
+
+ /**
+ * 更新时间
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @TableField(value = "update_time" , fill = FieldFill.UPDATE ,exist = false)
+ @ApiModelProperty(hidden=true)
+ private Date updateTime;
+
+ /**
+ * 请求参数
+ */
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @TableField(exist = false)
+ @ApiModelProperty(hidden=true)
+ private Map params;
+
+ public Map getParams () {
+ if (params == null) {
+ params = new HashMap<>();
+ }
+ return params;
+ }
+
+ public void setParams (Map params) {
+ this.params = params;
+ }
+
+ /**
+ * 开始时间
+ * @param key 属性名称
+ * @return 结果数据
+ */
+ public Object getBeginParam(String key){
+ return getParams().get(
+ StringUtils.format(ReqDomain.BEGIN_REF, key)
+ );
+ }
+
+ /**
+ * 开始时间
+ * @param key 属性名称
+ * @return 结果数据
+ */
+ public Object getEndParam(String key){
+ return getParams().get(
+ StringUtils.format(ReqDomain.END_REF, key)
+ );
+ }
+
+ /**
+ * 获取区间数据
+ * @param key 属性名称
+ * @return 结果数据
+ */
+ public Object[] getBetween(String key){
+ return new Object[]{getBeginParam(key), getEndParam(key)};
+ }
+}
diff --git a/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/Result.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/Result.java
new file mode 100644
index 0000000..a9b8981
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/Result.java
@@ -0,0 +1,102 @@
+package com.ruoyi.common.core.domain;
+
+import com.ruoyi.common.constant.HttpStatus;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 响应信息主体
+ *
+ * @author ruoyi
+ */
+@Data
+public class Result implements Serializable {
+ /**
+ * 成功
+ */
+ public static final int SUCCESS = HttpStatus.SUCCESS;
+ /**
+ * 失败
+ */
+ public static final int FAIL = HttpStatus.ERROR;
+ private static final long serialVersionUID = 1L;
+ /**
+ * 系统警告消息
+ */
+ private static final int WARN = HttpStatus.WARN;
+
+ private int code;
+
+ private String msg;
+
+ private T data;
+
+ public static Result success () {
+ return restResult(null, SUCCESS, "操作成功");
+ }
+
+ public static Result success (T data) {
+ return restResult(data, SUCCESS, "操作成功");
+ }
+
+ public static Result success (T data, String msg) {
+ return restResult(data, SUCCESS, msg);
+ }
+
+ public static Result error () {
+ return restResult(null, FAIL, "操作失败");
+ }
+
+ public static Result error (String msg) {
+ return restResult(null, FAIL, msg);
+ }
+
+ public static Result error (T data) {
+ return restResult(data, FAIL, "操作失败");
+ }
+
+ public static Result error (T data, String msg) {
+ return restResult(data, FAIL, msg);
+ }
+
+ public static Result error (int code, String msg) {
+ return restResult(null, code, msg);
+ }
+
+ public static Result warn () {
+ return restResult(null, WARN, "操作失败");
+ }
+
+ public static Result warn (String msg) {
+ return restResult(null, WARN, msg);
+ }
+
+ public static Result warn (T data) {
+ return restResult(data, WARN, "操作失败");
+ }
+
+ public static Result warn (T data, String msg) {
+ return restResult(data, WARN, msg);
+ }
+
+ public static Result warn (int code, String msg) {
+ return restResult(null, code, msg);
+ }
+
+ private static Result restResult (T data, int code, String msg) {
+ Result apiResult = new Result<>();
+ apiResult.setCode(code);
+ apiResult.setData(data);
+ apiResult.setMsg(msg);
+ return apiResult;
+ }
+
+ public static Boolean isError (Result ret) {
+ return !isSuccess(ret);
+ }
+
+ public static Boolean isSuccess (Result ret) {
+ return Result.SUCCESS == ret.getCode();
+ }
+}
diff --git a/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java
new file mode 100644
index 0000000..46d8227
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java
@@ -0,0 +1,78 @@
+package com.ruoyi.common.core.domain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tree基类
+ *
+ * @author ruoyi
+ */
+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/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java
new file mode 100644
index 0000000..11ec333
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java
@@ -0,0 +1,74 @@
+package com.ruoyi.common.core.domain;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.ruoyi.common.core.domain.entity.SysDept;
+import com.ruoyi.common.core.domain.entity.SysMenu;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Treeselect树结构实体类
+ *
+ * @author ruoyi
+ */
+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/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
new file mode 100644
index 0000000..42f2156
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
@@ -0,0 +1,203 @@
+package com.ruoyi.common.core.domain.entity;
+
+import com.ruoyi.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 部门表 sys_dept
+ *
+ * @author ruoyi
+ */
+public class SysDept extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 部门ID
+ */
+ private Long deptId;
+
+ /**
+ * 父部门ID
+ */
+ private Long parentId;
+
+ /**
+ * 祖级列表
+ */
+ private String ancestors;
+
+ /**
+ * 部门名称
+ */
+ private String deptName;
+
+ /**
+ * 显示顺序
+ */
+ private Integer orderNum;
+
+ /**
+ * 负责人
+ */
+ private String leader;
+
+ /**
+ * 联系电话
+ */
+ private String phone;
+
+ /**
+ * 邮箱
+ */
+ private String email;
+
+ /**
+ * 部门状态:0正常,1停用
+ */
+ private String status;
+
+ /**
+ * 删除标志(0代表存在 2代表删除)
+ */
+ private String delFlag;
+
+ /**
+ * 父部门名称
+ */
+ private String parentName;
+
+ /**
+ * 子部门
+ */
+ 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/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java
new file mode 100644
index 0000000..f83f4e4
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java
@@ -0,0 +1,130 @@
+package com.ruoyi.common.core.domain.entity;
+
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.annotation.Excel.ColumnType;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.core.domain.BaseEntity;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+
+/**
+ * 字典数据表 sys_dict_data
+ *
+ * @author ruoyi
+ */
+@Data
+@SuperBuilder
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class SysDictData extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 字典编码
+ */
+ @Excel(name = "字典编码", cellType = ColumnType.NUMERIC)
+ private Long dictCode;
+
+ /**
+ * 字典排序
+ */
+ @Excel(name = "字典排序", cellType = ColumnType.NUMERIC)
+ private Long dictSort;
+
+ /**
+ * 字典标签
+ */
+ @Excel(name = "字典标签")
+ private String dictLabel;
+
+ /**
+ * 字典键值
+ */
+ @Excel(name = "字典键值")
+ private String dictValue;
+
+ /**
+ * 字典类型
+ */
+ @Excel(name = "字典类型")
+ private String dictType;
+
+ /**
+ * 样式属性(其他样式扩展)
+ */
+ private String cssClass;
+
+ /**
+ * 表格字典样式
+ */
+ private String listClass;
+
+ /**
+ * 是否默认(Y是 N否)
+ */
+ @Excel(name = "是否默认", readConverterExp = "Y=是,N=否")
+ private String isDefault;
+
+ /**
+ * 状态(0正常 1停用)
+ */
+ @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
+ private String status;
+
+ /**
+ * 备注
+ */
+ private String remark;
+
+ @NotBlank(message = "字典标签不能为空")
+ @Size(min = 0, max = 100, message = "字典标签长度不能超过100个字符")
+ public String getDictLabel () {
+ return dictLabel;
+ }
+
+ @NotBlank(message = "字典键值不能为空")
+ @Size(min = 0, max = 100, message = "字典键值长度不能超过100个字符")
+ public String getDictValue () {
+ return dictValue;
+ }
+
+ @NotBlank(message = "字典类型不能为空")
+ @Size(min = 0, max = 100, message = "字典类型长度不能超过100个字符")
+ public String getDictType () {
+ return dictType;
+ }
+
+ @Size(min = 0, max = 100, message = "样式属性长度不能超过100个字符")
+ public String getCssClass () {
+ return cssClass;
+ }
+
+ @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/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java
new file mode 100644
index 0000000..d6c408f
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java
@@ -0,0 +1,88 @@
+package com.ruoyi.common.core.domain.entity;
+
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.annotation.Excel.ColumnType;
+import com.ruoyi.common.core.domain.BaseEntity;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+
+/**
+ * 字典类型表 sys_dict_type
+ *
+ * @author ruoyi
+ */
+@Data
+@SuperBuilder
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class SysDictType extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 字典主键
+ */
+ @Excel(name = "字典主键", cellType = ColumnType.NUMERIC)
+ private Long dictId;
+
+ /**
+ * 字典名称
+ */
+ @Excel(name = "字典名称")
+ private String dictName;
+
+ /**
+ * 字典类型
+ */
+ @Excel(name = "字典类型")
+ private String dictType;
+
+ /**
+ * 状态(0正常 1停用)
+ */
+ @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
+ private String status;
+
+ /**
+ * 备注
+ */
+ private String remark;
+
+
+ @NotBlank(message = "字典名称不能为空")
+ @Size(min = 0, max = 100, message = "字典类型名称长度不能超过100个字符")
+ public String getDictName () {
+ return dictName;
+ }
+
+ @NotBlank(message = "字典类型不能为空")
+ @Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符")
+ @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)")
+ public String getDictType () {
+ return dictType;
+ }
+
+ @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/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
new file mode 100644
index 0000000..c8b8348
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
@@ -0,0 +1,172 @@
+package com.ruoyi.common.core.domain.entity;
+
+import com.ruoyi.common.core.domain.BaseEntity;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 菜单权限表 sys_menu
+ *
+ * @author ruoyi
+ */
+@Data
+@SuperBuilder
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class SysMenu extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 菜单ID
+ */
+ private Long menuId;
+
+ /**
+ * 菜单名称
+ */
+ private String menuName;
+
+ /**
+ * 父菜单名称
+ */
+ private String parentName;
+
+ /**
+ * 父菜单ID
+ */
+ private Long parentId;
+
+ /**
+ * 显示顺序
+ */
+ private Integer orderNum;
+
+ /**
+ * 路由地址
+ */
+ private String path;
+
+ /**
+ * 组件路径
+ */
+ private String component;
+
+ /**
+ * 路由参数
+ */
+ private String query;
+
+ /**
+ * 是否为外链(0是 1否)
+ */
+ private String isFrame;
+
+ /**
+ * 是否缓存(0缓存 1不缓存)
+ */
+ private String isCache;
+
+ /**
+ * 类型(M目录 C菜单 F按钮)
+ */
+ private String menuType;
+
+ /**
+ * 显示状态(0显示 1隐藏)
+ */
+ private String visible;
+
+ /**
+ * 菜单状态(0正常 1停用)
+ */
+ private String status;
+
+ /**
+ * 权限字符串
+ */
+ private String perms;
+
+ /**
+ * 菜单图标
+ */
+ private String icon;
+
+ /**
+ * 子菜单
+ */
+ private List children = new ArrayList();
+
+ /**
+ * 备注
+ */
+ private String remark;
+
+
+ @NotBlank(message = "菜单名称不能为空")
+ @Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符")
+ public String getMenuName () {
+ return menuName;
+ }
+
+
+ @NotNull(message = "显示顺序不能为空")
+ public Integer getOrderNum () {
+ return orderNum;
+ }
+
+ @Size(min = 0, max = 200, message = "路由地址不能超过200个字符")
+ public String getPath () {
+ return path;
+ }
+
+ @Size(min = 0, max = 200, message = "组件路径不能超过255个字符")
+ public String getComponent () {
+ return component;
+ }
+
+ @NotBlank(message = "菜单类型不能为空")
+ public String getMenuType () {
+ return menuType;
+ }
+
+ @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")
+ public String getPerms () {
+ return perms;
+ }
+
+ @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("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/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
new file mode 100644
index 0000000..8c9ce58
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
@@ -0,0 +1,167 @@
+package com.ruoyi.common.core.domain.entity;
+
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.annotation.Excel.ColumnType;
+import com.ruoyi.common.core.domain.BaseEntity;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.Set;
+
+/**
+ * 角色表 sys_role
+ *
+ * @author ruoyi
+ */
+@Data
+@SuperBuilder
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class SysRole extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 角色ID
+ */
+ @Excel(name = "角色序号", cellType = ColumnType.NUMERIC)
+ private Long roleId;
+
+ /**
+ * 角色名称
+ */
+ @Excel(name = "角色名称")
+ private String roleName;
+
+ /**
+ * 角色权限
+ */
+ @Excel(name = "角色权限")
+ private String roleKey;
+
+ /**
+ * 角色排序
+ */
+ @Excel(name = "角色排序")
+ private Integer roleSort;
+
+ /**
+ * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限)
+ */
+ @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限")
+ private String dataScope;
+
+ /**
+ * 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示)
+ */
+ private boolean menuCheckStrictly;
+
+ /**
+ * 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 )
+ */
+ private boolean deptCheckStrictly;
+
+ /**
+ * 角色状态(0正常 1停用)
+ */
+ @Excel(name = "角色状态", readConverterExp = "0=正常,1=停用")
+ private String status;
+
+ /**
+ * 删除标志(0代表存在 2代表删除)
+ */
+ private String delFlag;
+
+ /**
+ * 用户是否存在此角色标识 默认不存在
+ */
+ private boolean flag = false;
+
+ /**
+ * 菜单组
+ */
+ private Long[] menuIds;
+
+ /**
+ * 部门组(数据权限)
+ */
+ private Long[] deptIds;
+
+ /**
+ * 角色菜单权限
+ */
+ private Set permissions;
+
+ /**
+ * 备注
+ */
+ private String remark;
+
+
+ public SysRole () {
+
+ }
+
+ public SysRole (Long roleId) {
+ this.roleId = roleId;
+ }
+
+ public static boolean isAdmin (Long roleId) {
+ return roleId != null && 1L == roleId;
+ }
+
+ public boolean isAdmin () {
+ return isAdmin(this.roleId);
+ }
+
+ @NotBlank(message = "角色名称不能为空")
+ @Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符")
+ public String getRoleName () {
+ return roleName;
+ }
+
+ @NotBlank(message = "权限字符不能为空")
+ @Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符")
+ public String getRoleKey () {
+ return roleKey;
+ }
+
+ @NotNull(message = "显示顺序不能为空")
+ public Integer getRoleSort () {
+ return roleSort;
+ }
+
+ public boolean isMenuCheckStrictly () {
+ return menuCheckStrictly;
+ }
+
+ public boolean isDeptCheckStrictly () {
+ return deptCheckStrictly;
+ }
+ @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/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
new file mode 100644
index 0000000..5e58fb8
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
@@ -0,0 +1,207 @@
+package com.ruoyi.common.core.domain.entity;
+
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.annotation.Excel.ColumnType;
+import com.ruoyi.common.annotation.Excel.Type;
+import com.ruoyi.common.annotation.Excels;
+import com.ruoyi.common.core.domain.BaseEntity;
+import com.ruoyi.common.xss.Xss;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 用户对象 sys_user
+ *
+ * @author ruoyi
+ */
+@Data
+@SuperBuilder
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class SysUser extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 用户ID
+ */
+ @Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号")
+ private Long userId;
+
+ /**
+ * 部门ID
+ */
+ @Excel(name = "部门编号", type = Type.IMPORT)
+ private Long deptId;
+
+ /**
+ * 用户账号
+ */
+ @Excel(name = "登录名称")
+ private String userName;
+
+ /**
+ * 用户昵称
+ */
+ @Excel(name = "用户名称")
+ private String nickName;
+
+ /**
+ * 用户邮箱
+ */
+ @Excel(name = "用户邮箱")
+ private String email;
+
+ /**
+ * 手机号码
+ */
+ @Excel(name = "手机号码")
+ private String phonenumber;
+
+ /**
+ * 用户性别
+ */
+ @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
+ private String sex;
+
+ /**
+ * 用户头像
+ */
+ private String avatar;
+
+ /**
+ * 密码
+ */
+ private String password;
+
+ /**
+ * 帐号状态(0正常 1停用)
+ */
+ @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
+ private String status;
+
+ /**
+ * 删除标志(0代表存在 2代表删除)
+ */
+ private String delFlag;
+
+ /**
+ * 最后登录IP
+ */
+ @Excel(name = "最后登录IP", type = Type.EXPORT)
+ private String loginIp;
+
+ /**
+ * 最后登录时间
+ */
+ @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)
+ private Date loginDate;
+
+ /**
+ * 部门对象
+ */
+ @Excels({
+ @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
+ @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)
+ })
+ private SysDept dept;
+
+ /**
+ * 角色对象
+ */
+ private List roles;
+
+ /**
+ * 角色组
+ */
+ private Long[] roleIds;
+
+ /**
+ * 岗位组
+ */
+ private Long[] postIds;
+
+ /**
+ * 角色ID
+ */
+ private Long roleId;
+
+ /**
+ * 备注
+ */
+ private String remark;
+
+ public SysUser () {
+
+ }
+
+ public SysUser (Long userId) {
+ this.userId = userId;
+ }
+
+ public static boolean isAdmin (Long userId) {
+ return userId != null && 1L == userId;
+ }
+
+ public boolean isAdmin () {
+ return isAdmin(this.userId);
+ }
+
+ @Xss(message = "用户昵称不能包含脚本字符")
+ @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
+ public String getNickName () {
+ return nickName;
+ }
+
+ @Xss(message = "用户账号不能包含脚本字符")
+ @NotBlank(message = "用户账号不能为空")
+ @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
+ public String getUserName () {
+ return userName;
+ }
+
+ @Email(message = "邮箱格式不正确")
+ @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
+ public String getEmail () {
+ return email;
+ }
+
+ @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符")
+ public String getPhonenumber () {
+ return phonenumber;
+ }
+ @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/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/CaptchaModel.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/CaptchaModel.java
new file mode 100644
index 0000000..58bddf9
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/CaptchaModel.java
@@ -0,0 +1,33 @@
+package com.ruoyi.common.core.domain.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
+
+/**
+ * @author DongZl
+ * @description: 验证码生成业务模型
+ * @Date 2023-6-19 下午 02:00
+ */
+@Data
+@SuperBuilder
+@NoArgsConstructor
+@AllArgsConstructor
+public class CaptchaModel {
+
+ /**
+ * 是否开启验证码
+ */
+ private boolean captchaEnabled;
+
+ /**
+ * 验证码校验唯一标识
+ */
+ private String uuid;
+
+ /**
+ * 验证码的base64加密串
+ */
+ private String img;
+}
diff --git a/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java
new file mode 100644
index 0000000..de57094
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java
@@ -0,0 +1,60 @@
+package com.ruoyi.common.core.domain.model;
+
+/**
+ * 用户登录对象
+ *
+ * @author ruoyi
+ */
+public class LoginBody {
+ /**
+ * 用户名
+ */
+ private String username;
+
+ /**
+ * 用户密码
+ */
+ private String password;
+
+ /**
+ * 验证码
+ */
+ private String code;
+
+ /**
+ * 唯一标识
+ */
+ 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;
+ }
+}
diff --git a/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
new file mode 100644
index 0000000..485482c
--- /dev/null
+++ b/ruoyi-basic/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
@@ -0,0 +1,234 @@
+package com.ruoyi.common.core.domain.model;
+
+import com.alibaba.fastjson2.annotation.JSONField;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * 登录用户身份权限
+ *
+ * @author ruoyi
+ */
+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 LoginUser () {
+ }
+
+ public LoginUser (SysUser user, Set