4 Commits

Author SHA1 Message Date
duhongming
b95122babb Merge remote-tracking branch 'origin/master'
# Conflicts:
#	docker/copy.sh
2024-09-20 15:20:04 +08:00
duhongming
6da19f5a3f Dockerfile by k8s 2024-08-28 22:35:34 +08:00
duhongming
43f34c1c42 Dockerfile by k8s 2024-08-28 21:08:00 +08:00
duhongming
3709c17e17 修复MySQL第一次启动不初始化数据库问题 2024-08-27 13:29:31 +08:00
52 changed files with 194 additions and 249 deletions

1
.gitignore vendored
View File

@@ -44,3 +44,4 @@ nbdist/
!*/build/*.java !*/build/*.java
!*/build/*.html !*/build/*.html
!*/build/*.xml !*/build/*.xml
docker

View File

@@ -1,11 +1,11 @@
<p align="center"> <p align="center">
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-b99b286755aef70355a7084753f89cdb7c9.png"> <img alt="logo" src="https://oscimg.oschina.net/oscnet/up-b99b286755aef70355a7084753f89cdb7c9.png">
</p> </p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.6.5</h1> <h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.6.4</h1>
<h4 align="center">基于 Vue/Element UI 和 Spring Boot/Spring Cloud & Alibaba 前后端分离的分布式微服务架构</h4> <h4 align="center">基于 Vue/Element UI 和 Spring Boot/Spring Cloud & Alibaba 前后端分离的分布式微服务架构</h4>
<p align="center"> <p align="center">
<a href="https://gitee.com/y_project/RuoYi-Cloud/stargazers"><img src="https://gitee.com/y_project/RuoYi-Cloud/badge/star.svg?theme=dark"></a> <a href="https://gitee.com/y_project/RuoYi-Cloud/stargazers"><img src="https://gitee.com/y_project/RuoYi-Cloud/badge/star.svg?theme=dark"></a>
<a href="https://gitee.com/y_project/RuoYi-Cloud"><img src="https://img.shields.io/badge/RuoYi-v3.6.5-brightgreen.svg"></a> <a href="https://gitee.com/y_project/RuoYi-Cloud"><img src="https://img.shields.io/badge/RuoYi-v3.6.4-brightgreen.svg"></a>
<a href="https://gitee.com/y_project/RuoYi-Cloud/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a> <a href="https://gitee.com/y_project/RuoYi-Cloud/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
</p> </p>
@@ -17,9 +17,12 @@
* 后端采用Spring Boot、Spring Cloud & Alibaba。 * 后端采用Spring Boot、Spring Cloud & Alibaba。
* 注册中心、配置中心选型Nacos权限认证使用Redis。 * 注册中心、配置中心选型Nacos权限认证使用Redis。
* 流量控制框架选型Sentinel分布式事务选型Seata。 * 流量控制框架选型Sentinel分布式事务选型Seata。
* 提供了技术栈([Vue3](https://v3.cn.vuejs.org) [Element Plus](https://element-plus.org/zh-CN) [Vite](https://cn.vitejs.dev))版本[RuoYi-Cloud-Vue3](https://gitcode.com/yangzongzhuan/RuoYi-Cloud-Vue3),保持同步更新。 * 提供了技术栈([Vue3](https://v3.cn.vuejs.org) [Element Plus](https://element-plus.org/zh-CN) [Vite](https://cn.vitejs.dev))版本[RuoYi-Cloud-Vue3](https://github.com/yangzongzhuan/RuoYi-Cloud-Vue3),保持同步更新。
* 如需不分离应用,请移步 [RuoYi](https://gitee.com/y_project/RuoYi),如需分离应用,请移步 [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) * 如需不分离应用,请移步 [RuoYi](https://gitee.com/y_project/RuoYi),如需分离应用,请移步 [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue)
* 阿里云优惠券[点我进入](http://aly.ruoyi.vip),腾讯云优惠券[点我进入](http://txy.ruoyi.vip)&nbsp;&nbsp; * 阿里云折扣场[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场[点我进入](http://txy.ruoyi.vip)&nbsp;&nbsp;
* 阿里云优惠券:[点我领取](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)&nbsp;&nbsp;
#### 友情链接 [若依/RuoYi-Cloud](https://gitee.com/zhangmrit/ruoyi-cloud) Ant Design版本。
## 系统模块 ## 系统模块
@@ -38,7 +41,6 @@ com.ruoyi
│ └── ruoyi-common-redis // 缓存服务 │ └── ruoyi-common-redis // 缓存服务
│ └── ruoyi-common-seata // 分布式事务 │ └── ruoyi-common-seata // 分布式事务
│ └── ruoyi-common-security // 安全模块 │ └── ruoyi-common-security // 安全模块
│ └── ruoyi-common-sensitive // 数据脱敏
│ └── ruoyi-common-swagger // 系统接口 │ └── ruoyi-common-swagger // 系统接口
├── ruoyi-modules // 业务模块 ├── ruoyi-modules // 业务模块
│ └── ruoyi-system // 系统模块 [9201] │ └── ruoyi-system // 系统模块 [9201]

View File

@@ -9,8 +9,9 @@ usage() {
# copy sql # copy sql
echo "begin copy sql " echo "begin copy sql "
cp ../sql/ry_20240629.sql ./mysql/db cp ../sql/ry_*.sql ./mysql/db
cp ../sql/ry_config_20240902.sql ./mysql/db cp ../sql/ry_config_*.sql ./mysql/db
cp ../sql/ry_seata_*.sql ./mysql/db
# copy html # copy html
echo "begin copy html " echo "begin copy html "

View File

@@ -27,6 +27,7 @@ services:
- ./mysql/conf:/etc/mysql/conf.d - ./mysql/conf:/etc/mysql/conf.d
- ./mysql/logs:/logs - ./mysql/logs:/logs
- ./mysql/data:/var/lib/mysql - ./mysql/data:/var/lib/mysql
- ./mysql/db:/docker-entrypoint-initdb.d
command: [ command: [
'mysqld', 'mysqld',
'--innodb-buffer-pool-size=80M', '--innodb-buffer-pool-size=80M',

54
pom.xml
View File

@@ -6,46 +6,42 @@
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
<name>ruoyi</name> <name>ruoyi</name>
<url>http://www.ruoyi.vip</url> <url>http://www.ruoyi.vip</url>
<description>若依微服务系统</description> <description>若依微服务系统</description>
<properties> <properties>
<ruoyi.version>3.6.5</ruoyi.version> <ruoyi.version>3.6.4</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version> <java.version>1.8</java.version>
<spring-boot.version>2.7.18</spring-boot.version> <spring-boot.version>2.7.18</spring-boot.version>
<spring-cloud.version>2021.0.9</spring-cloud.version> <spring-cloud.version>2021.0.8</spring-cloud.version>
<spring-cloud-alibaba.version>2021.0.6.1</spring-cloud-alibaba.version> <spring-cloud-alibaba.version>2021.0.5.0</spring-cloud-alibaba.version>
<spring-boot-admin.version>2.7.16</spring-boot-admin.version> <spring-framework.version>5.3.33</spring-framework.version>
<spring-boot-admin.version>2.7.15</spring-boot-admin.version>
<tobato.version>1.27.2</tobato.version> <tobato.version>1.27.2</tobato.version>
<kaptcha.version>2.3.3</kaptcha.version> <kaptcha.version>2.3.3</kaptcha.version>
<pagehelper.boot.version>2.0.0</pagehelper.boot.version> <pagehelper.boot.version>2.0.0</pagehelper.boot.version>
<druid.version>1.2.23</druid.version> <druid.version>1.2.23</druid.version>
<dynamic-ds.version>4.3.1</dynamic-ds.version> <dynamic-ds.version>4.2.0</dynamic-ds.version>
<commons.io.version>2.13.0</commons.io.version> <commons.io.version>2.13.0</commons.io.version>
<velocity.version>2.3</velocity.version> <velocity.version>2.3</velocity.version>
<fastjson.version>2.0.53</fastjson.version> <fastjson.version>2.0.43</fastjson.version>
<jjwt.version>0.9.1</jjwt.version> <jjwt.version>0.9.1</jjwt.version>
<minio.version>8.2.2</minio.version> <minio.version>8.2.2</minio.version>
<poi.version>4.1.2</poi.version> <poi.version>4.1.2</poi.version>
<springdoc.version>1.6.9</springdoc.version> <springdoc.version>1.6.9</springdoc.version>
<transmittable-thread-local.version>2.14.4</transmittable-thread-local.version> <transmittable-thread-local.version>2.14.4</transmittable-thread-local.version>
<!-- override dependency version -->
<tomcat.version>9.0.96</tomcat.version>
<logback.version>1.2.13</logback.version>
<spring-framework.version>5.3.39</spring-framework.version>
</properties> </properties>
<!-- 依赖声明 --> <!-- 依赖声明 -->
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<!-- 覆盖SpringFramework的依赖配置--> <!-- SpringFramework的依赖配置-->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId> <artifactId>spring-framework-bom</artifactId>
@@ -81,38 +77,6 @@
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<!-- 覆盖logback的依赖配置-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- 覆盖tomcat的依赖配置-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>${tomcat.version}</version>
</dependency>
<!-- FastDFS 分布式文件系统 --> <!-- FastDFS 分布式文件系统 -->
<dependency> <dependency>
<groupId>com.github.tobato</groupId> <groupId>com.github.tobato</groupId>

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-api</artifactId> <artifactId>ruoyi-api</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

12
ruoyi-auth/Dockerfile Normal file
View File

@@ -0,0 +1,12 @@
FROM openjdk:8-jdk
LABEL maintainer=duhongming
#docker run -e PARAMS="--server.port 9090"
ENV PARAMS="--server.port=8080 --spring.profiles.active=prod --spring.cloud.nacos.discovery.server-addr=nacos.ruoyi:8848 --spring.cloud.nacos.config.server-addr=nacos.ruoyi:8848 --spring.cloud.nacos.config.namespace=prod --spring.cloud.nacos.config.file-extension=yml"
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
COPY target/*.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["/bin/sh","-c","java -jar app.jar ${PARAMS}"]

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -20,7 +20,7 @@ public class SecurityConstants
/** /**
* 授权信息字段 * 授权信息字段
*/ */
public static final String AUTHORIZATION_HEADER = "Authorization"; public static final String AUTHORIZATION_HEADER = "authorization";
/** /**
* 请求来源 * 请求来源

View File

@@ -7,6 +7,11 @@ package com.ruoyi.common.core.constant;
*/ */
public class TokenConstants public class TokenConstants
{ {
/**
* 令牌自定义标识
*/
public static final String AUTHENTICATION = "Authorization";
/** /**
* 令牌前缀 * 令牌前缀
*/ */

View File

@@ -21,9 +21,6 @@ public class UserConstants
/** 用户封禁状态 */ /** 用户封禁状态 */
public static final String USER_DISABLE = "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 ROLE_DISABLE = "1";

View File

@@ -167,11 +167,6 @@ public class ExcelUtil<T>
*/ */
public Class<T> clazz; public Class<T> clazz;
/**
* 需要显示列属性
*/
public String[] includeFields;
/** /**
* 需要排除列属性 * 需要排除列属性
*/ */
@@ -182,20 +177,11 @@ public class ExcelUtil<T>
this.clazz = clazz; this.clazz = clazz;
} }
/**
* 仅在Excel中显示列属性
*
* @param fields 列属性名 示例[单个"name"/多个"id","name"]
*/
public void showColumn(String... fields)
{
this.includeFields = fields;
}
/** /**
* 隐藏Excel中列属性 * 隐藏Excel中列属性
* *
* @param fields 列属性名 示例[单个"name"/多个"id","name"] * @param fields 列属性名 示例[单个"name"/多个"id","name"]
* @throws Exception
*/ */
public void hideColumn(String... fields) public void hideColumn(String... fields)
{ {
@@ -1294,40 +1280,9 @@ public class ExcelUtil<T>
List<Field> tempFields = new ArrayList<>(); List<Field> tempFields = new ArrayList<>();
tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
tempFields.addAll(Arrays.asList(clazz.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) for (Field field : tempFields)
{ {
if (!ArrayUtils.contains(this.excludeFields, field.getName())) if (!ArrayUtils.contains(this.excludeFields, field.getName()))
{
addField(fields, field);
}
}
}
else
{
for (Field field : tempFields)
{
addField(fields, field);
}
}
return fields;
}
/**
* 添加字段信息
*/
public void addField(List<Object[]> fields, Field field)
{ {
// 单注解 // 单注解
if (field.isAnnotationPresent(Excel.class)) if (field.isAnnotationPresent(Excel.class))
@@ -1353,17 +1308,6 @@ public class ExcelUtil<T>
Excels attrs = field.getAnnotation(Excels.class); Excels attrs = field.getAnnotation(Excels.class);
Excel[] excels = attrs.value(); Excel[] excels = attrs.value();
for (Excel attr : excels) 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)))
{
field.setAccessible(true);
fields.add(new Object[] { field, attr });
}
}
else
{ {
if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr()) if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr())
&& (attr != null && (attr.type() == Type.ALL || attr.type() == type))) && (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
@@ -1375,6 +1319,8 @@ public class ExcelUtil<T>
} }
} }
} }
return fields;
}
/** /**
* 根据注解获取最大行高 * 根据注解获取最大行高

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -6,7 +6,6 @@ import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.ruoyi.common.core.constant.UserConstants;
import com.ruoyi.common.core.context.SecurityContextHolder; import com.ruoyi.common.core.context.SecurityContextHolder;
import com.ruoyi.common.core.text.Convert; import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.StringUtils;
@@ -74,7 +73,8 @@ public class DataScopeAspect
if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin())
{ {
String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), SecurityContextHolder.getPermission()); String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), SecurityContextHolder.getPermission());
dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), controllerDataScope.userAlias(), permission); dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
controllerDataScope.userAlias(), permission);
} }
} }
} }
@@ -94,7 +94,7 @@ public class DataScopeAspect
List<String> conditions = new ArrayList<String>(); List<String> conditions = new ArrayList<String>();
List<String> scopeCustomIds = new ArrayList<String>(); List<String> scopeCustomIds = new ArrayList<String>();
user.getRoles().forEach(role -> { 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))) if (DATA_SCOPE_CUSTOM.equals(role.getDataScope()) && StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
{ {
scopeCustomIds.add(Convert.toStr(role.getRoleId())); scopeCustomIds.add(Convert.toStr(role.getRoleId()));
} }
@@ -103,7 +103,7 @@ public class DataScopeAspect
for (SysRole role : user.getRoles()) for (SysRole role : user.getRoles())
{ {
String dataScope = role.getDataScope(); String dataScope = role.getDataScope();
if (conditions.contains(dataScope) || StringUtils.equals(role.getStatus(), UserConstants.ROLE_DISABLE)) if (conditions.contains(dataScope))
{ {
continue; continue;
} }

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -164,9 +164,10 @@ public class LogAspect
*/ */
private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception
{ {
Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
String requestMethod = operLog.getRequestMethod(); String requestMethod = operLog.getRequestMethod();
if (StringUtils.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name())) Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
if (StringUtils.isEmpty(paramsMap)
&& (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)))
{ {
String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames); String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
operLog.setOperParam(StringUtils.substring(params, 0, 2000)); operLog.setOperParam(StringUtils.substring(params, 0, 2000));

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -62,7 +62,7 @@ public class SecurityUtils
public static String getToken(HttpServletRequest request) public static String getToken(HttpServletRequest request)
{ {
// 从header获取token标识 // 从header获取token标识
String token = request.getHeader(SecurityConstants.AUTHORIZATION_HEADER); String token = request.getHeader(TokenConstants.AUTHENTICATION);
return replaceTokenPrefix(token); return replaceTokenPrefix(token);
} }

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -23,7 +23,7 @@ public enum DesensitizedType
/** /**
* 身份证中间10位星号替换 * 身份证中间10位星号替换
*/ */
ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{3}[Xx]|\\d{4})", "$1** **** ****$2")), ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{4})", "$1** **** ****$2")),
/** /**
* 手机号中间4位星号替换 * 手机号中间4位星号替换

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

12
ruoyi-gateway/Dockerfile Normal file
View File

@@ -0,0 +1,12 @@
FROM openjdk:8-jdk
LABEL maintainer=duhongming
#docker run -e PARAMS="--server.port 9090"
ENV PARAMS="--server.port=8080 --spring.profiles.active=prod --spring.cloud.nacos.discovery.server-addr=nacos.ruoyi:8848 --spring.cloud.nacos.config.server-addr=nacos.ruoyi:8848 --spring.cloud.nacos.config.namespace=prod --spring.cloud.nacos.config.file-extension=yml"
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
COPY target/*.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["/bin/sh","-c","java -jar app.jar ${PARAMS}"]

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -118,7 +118,7 @@ public class AuthFilter implements GlobalFilter, Ordered
*/ */
private String getToken(ServerHttpRequest request) private String getToken(ServerHttpRequest request)
{ {
String token = request.getHeaders().getFirst(SecurityConstants.AUTHORIZATION_HEADER); String token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION);
// 如果前端设置了令牌前缀,则裁剪掉前缀 // 如果前端设置了令牌前缀,则裁剪掉前缀
if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX))
{ {

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,12 @@
FROM openjdk:8-jdk
LABEL maintainer=duhongming
#docker run -e PARAMS="--server.port 9090"
ENV PARAMS="--server.port=8080 --spring.profiles.active=prod --spring.cloud.nacos.discovery.server-addr=nacos.ruoyi:8848 --spring.cloud.nacos.config.server-addr=nacos.ruoyi:8848 --spring.cloud.nacos.config.namespace=prod --spring.cloud.nacos.config.file-extension=yml"
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
COPY target/*.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["/bin/sh","-c","java -jar app.jar ${PARAMS}"]

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId> <artifactId>ruoyi-modules</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,12 @@
FROM openjdk:8-jdk
LABEL maintainer=duhongming
#docker run -e PARAMS="--server.port 9090"
ENV PARAMS="--server.port=8080 --spring.profiles.active=prod --spring.cloud.nacos.discovery.server-addr=nacos.ruoyi:8848 --spring.cloud.nacos.config.server-addr=nacos.ruoyi:8848 --spring.cloud.nacos.config.namespace=prod --spring.cloud.nacos.config.file-extension=yml"
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
COPY target/*.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["/bin/sh","-c","java -jar app.jar ${PARAMS}"]

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId> <artifactId>ruoyi-modules</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -93,7 +93,7 @@ public class GenTable extends BaseEntity
private String treeName; private String treeName;
/** 上级菜单ID字段 */ /** 上级菜单ID字段 */
private Long parentMenuId; private String parentMenuId;
/** 上级菜单名称字段 */ /** 上级菜单名称字段 */
private String parentMenuName; private String parentMenuName;
@@ -317,12 +317,12 @@ public class GenTable extends BaseEntity
this.treeName = treeName; this.treeName = treeName;
} }
public Long getParentMenuId() public String getParentMenuId()
{ {
return parentMenuId; return parentMenuId;
} }
public void setParentMenuId(Long parentMenuId) public void setParentMenuId(String parentMenuId)
{ {
this.parentMenuId = parentMenuId; this.parentMenuId = parentMenuId;
} }

View File

@@ -491,7 +491,7 @@ public class GenTableServiceImpl implements IGenTableService
String treeCode = paramsObj.getString(GenConstants.TREE_CODE); String treeCode = paramsObj.getString(GenConstants.TREE_CODE);
String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE); String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE);
String treeName = paramsObj.getString(GenConstants.TREE_NAME); String treeName = paramsObj.getString(GenConstants.TREE_NAME);
Long parentMenuId = paramsObj.getLongValue(GenConstants.PARENT_MENU_ID); String parentMenuId = paramsObj.getString(GenConstants.PARENT_MENU_ID);
String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME); String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME);
genTable.setTreeCode(treeCode); genTable.setTreeCode(treeCode);

View File

@@ -0,0 +1,12 @@
FROM openjdk:8-jdk
LABEL maintainer=duhongming
#docker run -e PARAMS="--server.port 9090"
ENV PARAMS="--server.port=8080 --spring.profiles.active=prod --spring.cloud.nacos.discovery.server-addr=nacos.ruoyi:8848 --spring.cloud.nacos.config.server-addr=nacos.ruoyi:8848 --spring.cloud.nacos.config.namespace=prod --spring.cloud.nacos.config.file-extension=yml"
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
COPY target/*.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["/bin/sh","-c","java -jar app.jar ${PARAMS}"]

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId> <artifactId>ruoyi-modules</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,12 @@
FROM openjdk:8-jdk
LABEL maintainer=duhongming
#docker run -e PARAMS="--server.port 9090"
ENV PARAMS="--server.port=8080 --spring.profiles.active=prod --spring.cloud.nacos.discovery.server-addr=nacos.ruoyi:8848 --spring.cloud.nacos.config.server-addr=nacos.ruoyi:8848 --spring.cloud.nacos.config.namespace=prod --spring.cloud.nacos.config.file-extension=yml"
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
COPY target/*.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["/bin/sh","-c","java -jar app.jar ${PARAMS}"]

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId> <artifactId>ruoyi-modules</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -27,7 +27,6 @@ import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.InnerAuth; import com.ruoyi.common.security.annotation.InnerAuth;
import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.domain.SysDept; import com.ruoyi.system.api.domain.SysDept;
import com.ruoyi.system.api.domain.SysRole; import com.ruoyi.system.api.domain.SysRole;
@@ -67,9 +66,6 @@ public class SysUserController extends BaseController
@Autowired @Autowired
private ISysConfigService configService; private ISysConfigService configService;
@Autowired
private TokenService tokenService;
/** /**
* 获取用户列表 * 获取用户列表
*/ */
@@ -171,17 +167,11 @@ public class SysUserController extends BaseController
@GetMapping("getInfo") @GetMapping("getInfo")
public AjaxResult getInfo() public AjaxResult getInfo()
{ {
LoginUser loginUser = SecurityUtils.getLoginUser(); SysUser user = userService.selectUserById(SecurityUtils.getUserId());
SysUser user = loginUser.getSysUser();
// 角色集合 // 角色集合
Set<String> roles = permissionService.getRolePermission(user); Set<String> roles = permissionService.getRolePermission(user);
// 权限集合 // 权限集合
Set<String> permissions = permissionService.getMenuPermission(user); Set<String> permissions = permissionService.getMenuPermission(user);
if (!loginUser.getPermissions().equals(permissions))
{
loginUser.setPermissions(permissions);
tokenService.refreshToken(loginUser);
}
AjaxResult ajax = AjaxResult.success(); AjaxResult ajax = AjaxResult.success();
ajax.put("user", user); ajax.put("user", user);
ajax.put("roles", roles); ajax.put("roles", roles);
@@ -196,18 +186,18 @@ public class SysUserController extends BaseController
@GetMapping(value = { "/", "/{userId}" }) @GetMapping(value = { "/", "/{userId}" })
public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
{ {
userService.checkUserDataScope(userId);
AjaxResult ajax = AjaxResult.success(); AjaxResult ajax = AjaxResult.success();
List<SysRole> roles = roleService.selectRoleAll();
ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
ajax.put("posts", postService.selectPostAll());
if (StringUtils.isNotNull(userId)) if (StringUtils.isNotNull(userId))
{ {
userService.checkUserDataScope(userId);
SysUser sysUser = userService.selectUserById(userId); SysUser sysUser = userService.selectUserById(userId);
ajax.put(AjaxResult.DATA_TAG, sysUser); ajax.put(AjaxResult.DATA_TAG, sysUser);
ajax.put("postIds", postService.selectPostListByUserId(userId)); ajax.put("postIds", postService.selectPostListByUserId(userId));
ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList())); ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
} }
List<SysRole> 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; return ajax;
} }

View File

@@ -6,8 +6,6 @@ import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import com.ruoyi.common.core.constant.UserConstants;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.system.api.domain.SysRole; import com.ruoyi.system.api.domain.SysRole;
import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.service.ISysMenuService; import com.ruoyi.system.service.ISysMenuService;
@@ -72,15 +70,12 @@ public class SysPermissionServiceImpl implements ISysPermissionService
{ {
// 多角色设置permissions属性以便数据权限匹配权限 // 多角色设置permissions属性以便数据权限匹配权限
for (SysRole role : roles) for (SysRole role : roles)
{
if (StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL))
{ {
Set<String> rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId()); Set<String> rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId());
role.setPermissions(rolePerms); role.setPermissions(rolePerms);
perms.addAll(rolePerms); perms.addAll(rolePerms);
} }
} }
}
else else
{ {
perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId())); perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId()));

View File

@@ -1,6 +1,6 @@
{ {
"name": "ruoyi", "name": "ruoyi",
"version": "3.6.5", "version": "3.6.4",
"description": "若依管理系统", "description": "若依管理系统",
"author": "若依", "author": "若依",
"license": "MIT", "license": "MIT",
@@ -49,7 +49,7 @@
"js-cookie": "3.0.1", "js-cookie": "3.0.1",
"jsencrypt": "3.0.0-rc.1", "jsencrypt": "3.0.0-rc.1",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"quill": "2.0.2", "quill": "1.3.7",
"screenfull": "5.0.2", "screenfull": "5.0.2",
"sortablejs": "1.10.2", "sortablejs": "1.10.2",
"vue": "2.6.12", "vue": "2.6.12",

View File

@@ -108,7 +108,7 @@ export default {
if (val !== this.currentValue) { if (val !== this.currentValue) {
this.currentValue = val === null ? "" : val; this.currentValue = val === null ? "" : val;
if (this.Quill) { if (this.Quill) {
this.Quill.clipboard.dangerouslyPasteHTML(this.currentValue); this.Quill.pasteHTML(this.currentValue);
} }
} }
}, },
@@ -136,7 +136,7 @@ export default {
} }
}); });
} }
this.Quill.clipboard.dangerouslyPasteHTML(this.currentValue); this.Quill.pasteHTML(this.currentValue);
this.Quill.on("text-change", (delta, oldDelta, source) => { this.Quill.on("text-change", (delta, oldDelta, source) => {
const html = this.$refs.editor.children[0].innerHTML; const html = this.$refs.editor.children[0].innerHTML;
const text = this.Quill.getText(); const text = this.Quill.getText();

View File

@@ -118,15 +118,10 @@ export default {
const fileExt = fileName[fileName.length - 1]; const fileExt = fileName[fileName.length - 1];
const isTypeOk = this.fileType.indexOf(fileExt) >= 0; const isTypeOk = this.fileType.indexOf(fileExt) >= 0;
if (!isTypeOk) { if (!isTypeOk) {
this.$modal.msgError(`文件格式不正确请上传${this.fileType.join("/")}格式文件!`); this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
return false; return false;
} }
} }
// 校检文件名是否包含特殊字符
if (file.name.includes(',')) {
this.$modal.msgError('文件名不正确,不能包含英文逗号!');
return false;
}
// 校检文件大小 // 校检文件大小
if (this.fileSize) { if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize; const isLt = file.size / 1024 / 1024 < this.fileSize;

View File

@@ -130,11 +130,7 @@ export default {
} }
if (!isImg) { if (!isImg) {
this.$modal.msgError(`文件格式不正确请上传${this.fileType.join("/")}图片格式文件!`); this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join("/")}图片格式文件!`);
return false;
}
if (file.name.includes(',')) {
this.$modal.msgError('文件名不正确,不能包含英文逗号!');
return false; return false;
} }
if (this.fileSize) { if (this.fileSize) {

View File

@@ -145,38 +145,6 @@
<span>更新日志</span> <span>更新日志</span>
</div> </div>
<el-collapse accordion> <el-collapse accordion>
<el-collapse-item title="v3.6.5 - 2024-11-13">
<ol>
<li>使用SpringDoc代替Swagger</li>
<li>菜单管理新增路由名称</li>
<li>新增数据脱敏过滤注解</li>
<li>限制用户操作数据权限范围</li>
<li>支持自定义显示Excel属性列</li>
<li>操作日志记录DELETE请求参数</li>
<li>用户登录后记录最后登录IP&时间</li>
<li>升级druid到最新版本1.2.23</li>
<li>升级fastjson到最新版2.0.53</li>
<li>升级dynamic-ds到最新版本4.3.1</li>
<li>升级spring-cloud到最新版2021.0.9</li>
<li>升级spring-boot-admin到最新版2.7.16</li>
<li>升级spring-cloud-alibaba到最新版2021.0.6.1</li>
<li>升级quill到最新版本2.0.2</li>
<li>升级axios到最新版本0.28.1</li>
<li>升级core-js到最新版本3.37.1</li>
<li>升级其他依赖到安全版本防止漏洞风险</li>
<li>修复角色禁用权限不失效问题</li>
<li>优化身份证脱敏正则</li>
<li>优化权限更新后同步缓存</li>
<li>优化查询时间范围日期格式</li>
<li>优化代码生成上级菜单字段类型</li>
<li>优化无用户编号不校验数据权限</li>
<li>优化代码生成主子表关联查询方式</li>
<li>优化校检文件名是否包含特殊字符</li>
<li>优化查表特殊字符使用反斜杠进行转义</li>
<li>优化多个自定数据权限使用in查询,避免多次拼接</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.6.4 - 2024-04-01"> <el-collapse-item title="v3.6.4 - 2024-04-01">
<ol> <ol>
<li>全局数据存储用户编号</li> <li>全局数据存储用户编号</li>
@@ -946,7 +914,7 @@ export default {
data() { data() {
return { return {
// 版本号 // 版本号
version: "3.6.5", version: "3.6.4",
}; };
}, },
methods: { methods: {

View File

@@ -27,7 +27,6 @@ module.exports = {
lintOnSave: process.env.NODE_ENV === 'development', lintOnSave: process.env.NODE_ENV === 'development',
// 如果你不需要生产环境的 source map可以将其设置为 false 以加速生产环境构建。 // 如果你不需要生产环境的 source map可以将其设置为 false 以加速生产环境构建。
productionSourceMap: false, productionSourceMap: false,
transpileDependencies: ['quill'],
// webpack-dev-server 相关配置 // webpack-dev-server 相关配置
devServer: { devServer: {
host: '0.0.0.0', host: '0.0.0.0',

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,12 @@
FROM openjdk:8-jdk
LABEL maintainer=duhongming
#docker run -e PARAMS="--server.port 9090"
ENV PARAMS="--server.port=8080 --spring.profiles.active=prod --spring.cloud.nacos.discovery.server-addr=nacos.ruoyi:8848 --spring.cloud.nacos.config.server-addr=nacos.ruoyi:8848 --spring.cloud.nacos.config.namespace=prod --spring.cloud.nacos.config.file-extension=yml"
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
COPY target/*.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["/bin/sh","-c","java -jar app.jar ${PARAMS}"]

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-visual</artifactId> <artifactId>ruoyi-visual</artifactId>
<version>3.6.5</version> <version>3.6.4</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>