疯狂的狮子li
2020-11-18 ff563c44e257c5921ec6d4647b590d7455edeeb5
Merge branch 'master' of https://gitee.com/y_project/RuoYi-Vue

 Conflicts:
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
 ruoyi-admin/src/main/resources/application.yml
 ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
 ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
 ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
 ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java
 ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
 ruoyi-ui/package.json
 ruoyi-ui/src/views/index.vue
 ruoyi-ui/src/views/tool/gen/editTable.vue
已修改18个文件
已添加2个文件
310 ■■■■ 文件已修改
pom.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/pom.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application.yml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/pom.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/pom.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/pom.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/resources/vm/vue/index.vue.vm 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/pom.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/pom.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/package.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/UploadImage/index.vue 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/index.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/tool/gen/editTable.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -6,14 +6,14 @@
    
    <groupId>com.ruoyi</groupId>
    <artifactId>ruoyi</artifactId>
    <version>3.2.0</version>
    <version>3.2.1</version>
    <name>ruoyi</name>
    <url>http://www.ruoyi.vip</url>
    <description>若依管理系统</description>
    
    <properties>
        <ruoyi.version>3.2.0</ruoyi.version>
        <ruoyi.version>3.2.1</ruoyi.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
ruoyi-admin/pom.xml
@@ -5,7 +5,7 @@
    <parent>
        <artifactId>ruoyi</artifactId>
        <groupId>com.ruoyi</groupId>
        <version>3.2.0</version>
        <version>3.2.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>jar</packaging>
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
@@ -5,6 +5,7 @@
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 @@
    {
        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 @@
     * æœ¬åœ°èµ„源通用下载
     */
    @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);
        }
    }
}
ruoyi-admin/src/main/resources/application.yml
@@ -3,7 +3,7 @@
  # åç§°
  name: RuoYi
  # ç‰ˆæœ¬
  version: 3.2.0
  version: 3.2.1
  # ç‰ˆæƒå¹´ä»½
  copyrightYear: 2020
  # å®žä¾‹æ¼”示开关
@@ -70,7 +70,7 @@
    secret: abcdefghijklmnopqrstuvwxyz
    # ä»¤ç‰Œæœ‰æ•ˆæœŸï¼ˆé»˜è®¤30分钟)
    expireTime: 30
# MyBatis配置
# https://baomidou.com/config/
mybatis-plus:
ruoyi-common/pom.xml
@@ -5,7 +5,7 @@
    <parent>
        <artifactId>ruoyi</artifactId>
        <groupId>com.ruoyi</groupId>
        <version>3.2.0</version>
        <version>3.2.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
@@ -74,6 +74,9 @@
    /** æ—¥æœŸæŽ§ä»¶ */
    public static final String HTML_DATETIME = "datetime";
    /** ä¸Šä¼ æŽ§ä»¶ */
    public static final String HTML_UPLOAD_IMAGE = "uploadImage";
    /** å¯Œæ–‡æœ¬æŽ§ä»¶ */
    public static final String HTML_EDITOR = "editor";
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
{
    /**
     * èŽ·å–æ–‡ä»¶ç±»åž‹
     * <p>
     * ä¾‹å¦‚: ruoyi.txt, è¿”回: txt
     *
     * @param file æ–‡ä»¶å
     * @return åŽç¼€ï¼ˆä¸å«".")
     */
    public static String getFileType(File file)
    {
        if (null == file)
        {
            return StringUtils.EMPTY;
        }
        return getFileType(file.getName());
    }
    /**
     * èŽ·å–æ–‡ä»¶ç±»åž‹
     * <p>
     * ä¾‹å¦‚: 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();
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
@@ -7,7 +7,11 @@
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;
/**
 * æ–‡ä»¶å¤„理工具类
@@ -105,14 +109,37 @@
    }
    /**
     * æ£€æŸ¥æ–‡ä»¶æ˜¯å¦å¯ä¸‹è½½
     *
     * @param resource éœ€è¦ä¸‹è½½çš„æ–‡ä»¶
     * @return true æ­£å¸¸ false éžæ³•
     */
    public static boolean checkAllowDownload(String resource)
    {
        // ç¦æ­¢ç›®å½•上跳级别
        if (StringUtils.contains(resource, ".."))
        {
            return false;
        }
        // æ£€æŸ¥å…è®¸ä¸‹è½½çš„æ–‡ä»¶è§„则
        if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))
        {
            return true;
        }
        // ä¸åœ¨å…è®¸ä¸‹è½½çš„æ–‡ä»¶è§„则
        return false;
    }
    /**
     * ä¸‹è½½æ–‡ä»¶åé‡æ–°ç¼–码
     * 
     * @param request è¯·æ±‚对象
     * @param fileName æ–‡ä»¶å
     * @return ç¼–码后的文件名
     */
    public static String setFileDownloadHeader(HttpServletRequest request, String fileName)
            throws UnsupportedEncodingException
    public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException
    {
        final String agent = request.getHeader("USER-AGENT");
        String filename = fileName;
@@ -139,4 +166,38 @@
        }
        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");
    }
}
ruoyi-framework/pom.xml
@@ -5,7 +5,7 @@
    <parent>
        <artifactId>ruoyi</artifactId>
        <groupId>com.ruoyi</groupId>
        <version>3.2.0</version>
        <version>3.2.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
ruoyi-generator/pom.xml
@@ -5,7 +5,7 @@
    <parent>
        <artifactId>ruoyi</artifactId>
        <groupId>com.ruoyi</groupId>
        <version>3.2.0</version>
        <version>3.2.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
@@ -59,7 +59,7 @@
    /** æŸ¥è¯¢æ–¹å¼ï¼ˆ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;
    /** å­—典类型 */
ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java
@@ -111,6 +111,11 @@
        {
            column.setHtmlType(GenConstants.HTML_SELECT);
        }
        // æ–‡ä»¶å­—段设置上传控件
        else if (StringUtils.endsWithIgnoreCase(columnName, "image"))
        {
            column.setHtmlType(GenConstants.HTML_UPLOAD_IMAGE);
        }
        // å†…容字段设置富文本控件
        else if (StringUtils.endsWithIgnoreCase(columnName, "content"))
        {
ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
@@ -139,6 +139,10 @@
        <el-form-item label="${comment}" prop="${field}">
          <el-input v-model="form.${field}" placeholder="请输入${comment}" />
        </el-form-item>
#elseif($column.htmlType == "uploadImage")
        <el-form-item label="${comment}">
          <uploadImage v-model="form.${field}"/>
        </el-form-item>
#elseif($column.htmlType == "editor")
        <el-form-item label="${comment}">
          <editor v-model="form.${field}" :min-height="192"/>
@@ -226,6 +230,12 @@
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 @@
  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
ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
@@ -168,6 +168,10 @@
        <el-form-item label="${comment}" prop="${field}">
          <el-input v-model="form.${field}" placeholder="请输入${comment}" />
        </el-form-item>
#elseif($column.htmlType == "uploadImage")
        <el-form-item label="${comment}">
          <uploadImage v-model="form.${field}"/>
        </el-form-item>
#elseif($column.htmlType == "editor")
        <el-form-item label="${comment}">
          <editor v-model="form.${field}" :min-height="192"/>
@@ -253,6 +257,12 @@
<script>
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}";
#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
@@ -261,12 +271,20 @@
export default {
  name: "${BusinessName}",
  components: {
#foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "editor")
  components: { Editor },
#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
#end
#end
  },
  data() {
    return {
      // é®ç½©å±‚
ruoyi-quartz/pom.xml
@@ -5,7 +5,7 @@
    <parent>
        <artifactId>ruoyi</artifactId>
        <groupId>com.ruoyi</groupId>
        <version>3.2.0</version>
        <version>3.2.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
ruoyi-system/pom.xml
@@ -5,7 +5,7 @@
    <parent>
        <artifactId>ruoyi</artifactId>
        <groupId>com.ruoyi</groupId>
        <version>3.2.0</version>
        <version>3.2.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
ruoyi-ui/package.json
@@ -1,6 +1,6 @@
{
  "name": "ruoyi",
  "version": "3.2.0",
  "version": "3.2.1",
  "description": "若依管理系统",
  "author": "若依",
  "license": "MIT",
ruoyi-ui/src/components/UploadImage/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
<template>
  <div class="component-upload-image">
    <el-upload
      :action="uploadImgUrl"
      list-type="picture-card"
      :on-success="handleUploadSuccess"
      :before-upload="handleBeforeUpload"
      :on-error="handleUploadError"
      name="file"
      :show-file-list="false"
      :headers="headers"
      style="display: inline-block; vertical-align: top"
    >
      <img v-if="value" :src="value" class="avatar" />
      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
    </el-upload>
  </div>
</template>
<script>
import { getToken } from "@/utils/auth";
export default {
  components: {},
  data() {
    return {
      uploadImgUrl: process.env.VUE_APP_BASE_API + "/common/upload", // ä¸Šä¼ çš„图片服务器地址
      headers: {
        Authorization: "Bearer " + getToken(),
      },
    };
  },
  props: {
    value: {
      type: String,
      default: "",
    },
  },
  methods: {
    handleUploadSuccess(res) {
      this.$emit("input", res.url);
      this.loading.close();
    },
    handleBeforeUpload() {
      this.loading = this.$loading({
        lock: true,
        text: "上传中",
        background: "rgba(0, 0, 0, 0.7)",
      });
    },
    handleUploadError() {
      this.$message({
        type: "error",
        message: "上传失败",
      });
      this.loading.close();
    },
  },
  watch: {},
};
</script>
<style scoped lang="scss">
.avatar {
  width: 100%;
  height: 100%;
}
</style>
ruoyi-ui/src/views/index.vue
@@ -146,6 +146,20 @@
            <span>更新日志</span>
          </div>
          <el-collapse accordion>
            <el-collapse-item title="v3.2.1 - 2020-11-18">
              <ol>
                <li>阻止任意文件下载漏洞</li>
                <li>代码生成支持上传控件</li>
                <li>新增图片上传组件</li>
                <li>调整默认首页</li>
                <li>升级druid到最新版本v1.2.2</li>
                <li>mapperLocations配置支持分隔符</li>
                <li>权限信息调整</li>
                <li>调整sql默认时间</li>
                <li>解决代码生成没有bit类型的问题</li>
                <li>升级pagehelper到最新版1.3.0</li>
              </ol>
            </el-collapse-item>
            <el-collapse-item title="v3.2.0 - 2020-10-10">
              <ol>
                <li>升级springboot版本到2.1.17 æå‡å®‰å…¨æ€§</li>
@@ -421,7 +435,7 @@
  data() {
    return {
      // ç‰ˆæœ¬å·
      version: "3.2.0",
      version: "3.2.1",
    };
  },
  methods: {
ruoyi-ui/src/views/tool/gen/editTable.vue
@@ -90,6 +90,7 @@
                <el-option label="单选框" value="radio" />
                <el-option label="复选框" value="checkbox" />
                <el-option label="日期控件" value="datetime" />
                <el-option label="上传控件" value="uploadImage" />
                <el-option label="富文本控件" value="editor" />
              </el-select>
            </template>