- 3.2.0
+ 3.2.1
UTF-8
UTF-8
1.8
diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml
index da3aa62bb..3257d8cf7 100644
--- a/ruoyi-admin/pom.xml
+++ b/ruoyi-admin/pom.xml
@@ -5,7 +5,7 @@
ruoyi
com.ruoyi
- 3.2.0
+ 3.2.1
4.0.0
jar
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
index f02b6d3e4..e0c728fac 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
@@ -5,6 +5,7 @@ import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -41,17 +42,15 @@ public class CommonController
{
try
{
- if (!FileUtils.isValidFilename(fileName))
+ if (!FileUtils.checkAllowDownload(fileName))
{
throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
}
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
String filePath = RuoYiConfig.getDownloadPath() + fileName;
- response.setCharacterEncoding("utf-8");
- response.setContentType("multipart/form-data");
- response.setHeader("Content-Disposition",
- "attachment;fileName=" + FileUtils.setFileDownloadHeader(request, realFileName));
+ response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
+ FileUtils.setAttachmentResponseHeader(response, realFileName);
FileUtils.writeBytes(filePath, response.getOutputStream());
if (delete)
{
@@ -92,18 +91,28 @@ public class CommonController
* 本地资源通用下载
*/
@GetMapping("/common/download/resource")
- public void resourceDownload(String name, HttpServletRequest request, HttpServletResponse response) throws Exception
+ public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
+ throws Exception
{
- // 本地资源路径
- String localPath = RuoYiConfig.getProfile();
- // 数据库资源地址
- String downloadPath = localPath + StringUtils.substringAfter(name, Constants.RESOURCE_PREFIX);
- // 下载名称
- String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
- response.setCharacterEncoding("utf-8");
- response.setContentType("multipart/form-data");
- response.setHeader("Content-Disposition",
- "attachment;fileName=" + FileUtils.setFileDownloadHeader(request, downloadName));
- FileUtils.writeBytes(downloadPath, response.getOutputStream());
+ try
+ {
+ if (!FileUtils.checkAllowDownload(resource))
+ {
+ throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
+ }
+ // 本地资源路径
+ String localPath = RuoYiConfig.getProfile();
+ // 数据库资源地址
+ String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
+ // 下载名称
+ String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
+ response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
+ FileUtils.setAttachmentResponseHeader(response, downloadName);
+ FileUtils.writeBytes(downloadPath, response.getOutputStream());
+ }
+ catch (Exception e)
+ {
+ log.error("下载文件失败", e);
+ }
}
}
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index c205d3a53..394380bcc 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -3,7 +3,7 @@ ruoyi:
# 名称
name: RuoYi
# 版本
- version: 3.2.0
+ version: 3.2.1
# 版权年份
copyrightYear: 2020
# 实例演示开关
@@ -70,7 +70,7 @@ token:
secret: abcdefghijklmnopqrstuvwxyz
# 令牌有效期(默认30分钟)
expireTime: 30
-
+
# MyBatis配置
# https://baomidou.com/config/
mybatis-plus:
diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml
index 46823fe71..35adaa31c 100644
--- a/ruoyi-common/pom.xml
+++ b/ruoyi-common/pom.xml
@@ -5,7 +5,7 @@
ruoyi
com.ruoyi
- 3.2.0
+ 3.2.1
4.0.0
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
index 29b28e1d8..7bcaced4c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
@@ -74,6 +74,9 @@ public class GenConstants
/** 日期控件 */
public static final String HTML_DATETIME = "datetime";
+ /** 上传控件 */
+ public static final String HTML_UPLOAD_IMAGE = "uploadImage";
+
/** 富文本控件 */
public static final String HTML_EDITOR = "editor";
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java
new file mode 100644
index 000000000..65be65b4a
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java
@@ -0,0 +1,47 @@
+package com.ruoyi.common.utils.file;
+
+import java.io.File;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 文件类型工具类
+ *
+ * @author ruoyi
+ */
+public class FileTypeUtils
+{
+ /**
+ * 获取文件类型
+ *
+ * 例如: ruoyi.txt, 返回: txt
+ *
+ * @param file 文件名
+ * @return 后缀(不含".")
+ */
+ public static String getFileType(File file)
+ {
+ if (null == file)
+ {
+ return StringUtils.EMPTY;
+ }
+ return getFileType(file.getName());
+ }
+
+ /**
+ * 获取文件类型
+ *
+ * 例如: ruoyi.txt, 返回: txt
+ *
+ * @param fileName 文件名
+ * @return 后缀(不含".")
+ */
+ public static String getFileType(String fileName)
+ {
+ int separatorIndex = fileName.lastIndexOf(".");
+ if (separatorIndex < 0)
+ {
+ return "";
+ }
+ return fileName.substring(separatorIndex + 1).toLowerCase();
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
index d144072eb..66c9f2484 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
@@ -7,7 +7,11 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.lang3.ArrayUtils;
+import com.ruoyi.common.utils.StringUtils;
/**
* 文件处理工具类
@@ -104,6 +108,30 @@ public class FileUtils extends org.apache.commons.io.FileUtils
return filename.matches(FILENAME_PATTERN);
}
+ /**
+ * 检查文件是否可下载
+ *
+ * @param resource 需要下载的文件
+ * @return true 正常 false 非法
+ */
+ public static boolean checkAllowDownload(String resource)
+ {
+ // 禁止目录上跳级别
+ if (StringUtils.contains(resource, ".."))
+ {
+ return false;
+ }
+
+ // 检查允许下载的文件规则
+ if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))
+ {
+ return true;
+ }
+
+ // 不在允许下载的文件规则
+ return false;
+ }
+
/**
* 下载文件名重新编码
*
@@ -111,8 +139,7 @@ public class FileUtils extends org.apache.commons.io.FileUtils
* @param fileName 文件名
* @return 编码后的文件名
*/
- public static String setFileDownloadHeader(HttpServletRequest request, String fileName)
- throws UnsupportedEncodingException
+ public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException
{
final String agent = request.getHeader("USER-AGENT");
String filename = fileName;
@@ -139,4 +166,38 @@ public class FileUtils extends org.apache.commons.io.FileUtils
}
return filename;
}
+
+ /**
+ * 下载文件名重新编码
+ *
+ * @param response 响应对象
+ * @param realFileName 真实文件名
+ * @return
+ */
+ public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException
+ {
+ String percentEncodedFileName = percentEncode(realFileName);
+
+ StringBuilder contentDispositionValue = new StringBuilder();
+ contentDispositionValue.append("attachment; filename=")
+ .append(percentEncodedFileName)
+ .append(";")
+ .append("filename*=")
+ .append("utf-8''")
+ .append(percentEncodedFileName);
+
+ response.setHeader("Content-disposition", contentDispositionValue.toString());
+ }
+
+ /**
+ * 百分号编码工具方法
+ *
+ * @param s 需要百分号编码的字符串
+ * @return 百分号编码后的字符串
+ */
+ public static String percentEncode(String s) throws UnsupportedEncodingException
+ {
+ String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
+ return encode.replaceAll("\\+", "%20");
+ }
}
diff --git a/ruoyi-framework/pom.xml b/ruoyi-framework/pom.xml
index e8f79c26b..61af7c0a7 100644
--- a/ruoyi-framework/pom.xml
+++ b/ruoyi-framework/pom.xml
@@ -5,7 +5,7 @@
ruoyi
com.ruoyi
- 3.2.0
+ 3.2.1
4.0.0
diff --git a/ruoyi-generator/pom.xml b/ruoyi-generator/pom.xml
index 43d1245e5..58abab131 100644
--- a/ruoyi-generator/pom.xml
+++ b/ruoyi-generator/pom.xml
@@ -5,7 +5,7 @@
ruoyi
com.ruoyi
- 3.2.0
+ 3.2.1
4.0.0
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
index a96d2733f..23b069a3c 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
@@ -59,7 +59,7 @@ public class GenTableColumn extends BaseEntity
/** 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围) */
private String queryType;
- /** 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、editor富文本控件) */
+ /** 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、upload上传控件、editor富文本控件) */
private String htmlType;
/** 字典类型 */
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java
index 43fc71db4..da78d0384 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java
@@ -111,6 +111,11 @@ public class GenUtils
{
column.setHtmlType(GenConstants.HTML_SELECT);
}
+ // 文件字段设置上传控件
+ else if (StringUtils.endsWithIgnoreCase(columnName, "image"))
+ {
+ column.setHtmlType(GenConstants.HTML_UPLOAD_IMAGE);
+ }
// 内容字段设置富文本控件
else if (StringUtils.endsWithIgnoreCase(columnName, "content"))
{
diff --git a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
index e139a1356..e43393412 100644
--- a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
+++ b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
@@ -139,6 +139,10 @@
+#elseif($column.htmlType == "uploadImage")
+
+
+
#elseif($column.htmlType == "editor")
@@ -226,6 +230,12 @@ import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${Busin
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
#foreach($column in $columns)
+#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "uploadImage")
+import UploadImage from '@/components/UploadImage';
+#break
+#end
+#end
+#foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "editor")
import Editor from '@/components/Editor';
#break
@@ -236,6 +246,12 @@ export default {
name: "${BusinessName}",
components: {
#foreach($column in $columns)
+#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "uploadImage")
+ UploadImage,
+#break
+#end
+#end
+#foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "editor")
Editor,
#break
diff --git a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
index 129c17628..aa973b1df 100644
--- a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
+++ b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
@@ -168,6 +168,10 @@
+#elseif($column.htmlType == "uploadImage")
+
+
+
#elseif($column.htmlType == "editor")
@@ -253,6 +257,12 @@
+
+
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/index.vue b/ruoyi-ui/src/views/index.vue
index c50687c3d..55f34391d 100644
--- a/ruoyi-ui/src/views/index.vue
+++ b/ruoyi-ui/src/views/index.vue
@@ -146,6 +146,20 @@
更新日志
+
+
+ - 阻止任意文件下载漏洞
+ - 代码生成支持上传控件
+ - 新增图片上传组件
+ - 调整默认首页
+ - 升级druid到最新版本v1.2.2
+ - mapperLocations配置支持分隔符
+ - 权限信息调整
+ - 调整sql默认时间
+ - 解决代码生成没有bit类型的问题
+ - 升级pagehelper到最新版1.3.0
+
+
- 升级springboot版本到2.1.17 提升安全性
@@ -421,7 +435,7 @@ export default {
data() {
return {
// 版本号
- version: "3.2.0",
+ version: "3.2.1",
};
},
methods: {
diff --git a/ruoyi-ui/src/views/tool/gen/editTable.vue b/ruoyi-ui/src/views/tool/gen/editTable.vue
index 34695457b..9ecab454c 100644
--- a/ruoyi-ui/src/views/tool/gen/editTable.vue
+++ b/ruoyi-ui/src/views/tool/gen/editTable.vue
@@ -90,6 +90,7 @@
+