Преглед изворни кода

feat:新增文件上传逻辑base64编码,以及文件形式存储接口、共通新增接口新增文件逻辑、修复前端获取用户信息异常问题、调用上传接口案例、

韩帛霖 пре 11 месеци
родитељ
комит
7681afaebd

+ 111 - 7
zkqy-admin/src/main/java/com/zkqy/web/controller/common/CommonFileController.java

@@ -11,30 +11,35 @@ import com.zkqy.common.annotation.Log;
 import com.zkqy.common.config.ZkqyConfig;
 import com.zkqy.common.constant.Constants;
 import com.zkqy.common.core.domain.AjaxResult;
+import com.zkqy.common.core.redis.RedisCache;
 import com.zkqy.common.enums.BusinessType;
+import com.zkqy.common.utils.SecurityUtils;
 import com.zkqy.common.utils.StringUtils;
 import com.zkqy.common.utils.file.FileUploadUtils;
 import com.zkqy.common.utils.file.FileUtils;
 import com.zkqy.execution.produce.dispersed.entity.CommonEntity;
 import com.zkqy.execution.produce.dispersed.entity.TableSql;
+import com.zkqy.execution.produce.dispersed.entity.vo.FileVo;
 import com.zkqy.execution.produce.dispersed.service.ICommonService;
 import com.zkqy.execution.produce.dispersed.service.ITableSqlService;
 import com.zkqy.framework.config.ServerConfig;
 import com.zkqy.business.controller.CommonController;
+import com.zkqy.system.service.sso.RedisService;
 import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
+
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
 
 import static com.zkqy.common.core.domain.AjaxResult.success;
 
@@ -63,6 +68,9 @@ public class CommonFileController {
     @Resource
     private IDragTableService dragTableService;
 
+    @Resource
+    private RedisCache redisCache;
+
     private static final String FILE_DELIMETER = ",";
 
     /**
@@ -117,8 +125,6 @@ public class CommonFileController {
     /**
      * 通用上传请求(单个)
      */
-//    @Log(title = "动态表格", businessType = BusinessType.IMPORT)
-    @Anonymous
     @PostMapping("/upload")
     public AjaxResult uploadFile(MultipartFile file) throws Exception {
         try {
@@ -138,6 +144,103 @@ public class CommonFileController {
         }
     }
 
+    /**
+     * 租户通用上传文件接口(需携带租户标识)
+     *
+     * @param file
+     * @param base64
+     * @return
+     */
+    @PostMapping("/tenantUploadFile")
+    public AjaxResult tenantUploadFile(MultipartFile file, boolean base64) {
+        try {
+            // 每个租户都有属于自己的文件夹
+            String tenantCode = SecurityUtils.getLoginUser().getUser().getTenant().getTenantCode();
+            // 上传文件路径
+            String filePath = ZkqyConfig.getUploadPath() + "/" + tenantCode;
+            AjaxResult ajax = success();
+            // 当前文件是否使用base64来进行存储
+            if (base64) {
+                // 从MultipartFile获取字节数组
+                byte[] bytes = file.getBytes();
+                // 将字节数组转换为Base64编码的字符串
+                String base64Encoded = Base64.getEncoder().encodeToString(bytes);
+                String key = UUID.randomUUID().toString();
+                // 存储字节流  redis暂存30分钟
+                redisCache.setCacheObject(key, base64Encoded, Constants.BYTESTREAM_EXPIRATION, TimeUnit.MINUTES);
+                ajax.put("base64", key);
+            } else {
+                // 上传并返回新文件名称
+                String fileName = FileUploadUtils.upload(filePath, file);
+                // 存储文件
+                String url = serverConfig.getUrl() + fileName;
+                ajax.put("url", url);
+                ajax.put("fileName", fileName);
+                ajax.put("newFileName", FileUtils.getName(fileName));
+                ajax.put("originalFilename", file.getOriginalFilename());
+            }
+            return ajax;
+        } catch (Exception e) {
+            return AjaxResult.error(e.getMessage());
+        }
+    }
+
+
+    /**
+     * * 租户通用批量上传文件接口(需携带租户标识)
+     * * * 批量上传无法使用流文件逻辑
+     *
+     * @param request
+     * @param files
+     * @return
+     */
+    @PostMapping("/tenantUploadFiles")
+    @RequestBody
+    public AjaxResult tenantUploadFiles(HttpServletRequest request, List<MultipartFile> files) {
+        try {
+            // 每个租户都有属于自己的文件夹
+            String tenantCode = SecurityUtils.getLoginUser().getUser().getTenant().getTenantCode();
+            // 上传文件路径
+            String filePath = ZkqyConfig.getUploadPath() + "/" + tenantCode;
+            List<String> urls = new ArrayList<String>();
+            List<String> fileNames = new ArrayList<String>();
+            List<String> newFileNames = new ArrayList<String>();
+            List<String> originalFilenames = new ArrayList<String>();
+            List<String> base64Keys = new ArrayList<String>();
+            AjaxResult ajax = success();
+            for (MultipartFile file : files) {
+                boolean is = Boolean.parseBoolean(request.getParameter(file.getOriginalFilename().split("\\.")[0]));
+                if (is) {
+                    // 从MultipartFile获取字节数组
+                    byte[] bytes = file.getBytes();
+                    // 将字节数组转换为Base64编码的字符串
+                    String base64Encoded = Base64.getEncoder().encodeToString(bytes);
+                    String key = UUID.randomUUID().toString();
+                    // 存储字节流  redis暂存30分钟
+                    redisCache.setCacheObject(key, base64Encoded, Constants.BYTESTREAM_EXPIRATION, TimeUnit.MINUTES);
+                    base64Keys.add("file:base64:" + key);
+                    ajax.put("base64", StringUtils.join(base64Keys, FILE_DELIMETER));
+                } else {
+                    // 上传并返回新文件名称
+                    String fileName = FileUploadUtils.upload(filePath, file);
+                    String url = serverConfig.getUrl() + fileName;
+                    urls.add(url);
+                    fileNames.add(fileName);
+                    newFileNames.add(FileUtils.getName(fileName));
+                    originalFilenames.add(file.getOriginalFilename());
+
+                    ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER));
+                    ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER));
+                    ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER));
+                    ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER));
+                }
+            }
+            return ajax;
+        } catch (Exception e) {
+            return AjaxResult.error(e.getMessage());
+        }
+    }
+
     /**
      * 通用上传请求(多个)
      */
@@ -262,7 +365,8 @@ public class CommonFileController {
             listMap.remove(0);
             CommonEntity commonEntity = new CommonEntity();
             commonEntity.setBasicMap(
-                    JSONObject.parseObject("{ \"tableName\":\"" + tableName + "\"}", new TypeReference<Map<String, Object>>() {})
+                    JSONObject.parseObject("{ \"tableName\":\"" + tableName + "\"}", new TypeReference<Map<String, Object>>() {
+                    })
             );
             int state = 0;  // 返回状态值
             int batchSize = 1000; // 设置批量新增每次执行添加sql上线为1000条

+ 42 - 0
zkqy-process-execution/src/main/java/com/zkqy/execution/produce/dispersed/entity/vo/FileVo.java

@@ -0,0 +1,42 @@
+package com.zkqy.execution.produce.dispersed.entity.vo;
+
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * @author hanzihang
+ * 上传文件VO
+ */
+public class FileVo {
+
+    private boolean isBase64;
+
+    private MultipartFile file;
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("FileVo{");
+        sb.append("isBase64=").append(isBase64);
+        sb.append(", file=").append(file);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    public boolean isBase64() {
+        return isBase64;
+    }
+
+    public void setBase64(boolean base64) {
+        isBase64 = base64;
+    }
+
+    public MultipartFile getFile() {
+        return file;
+    }
+
+    public void setFile(MultipartFile file) {
+        this.file = file;
+    }
+
+}

+ 9 - 1
zkqy-process-execution/src/main/java/com/zkqy/execution/produce/dispersed/service/impl/CommonServiceImpl.java

@@ -7,6 +7,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
+import com.zkqy.common.core.redis.RedisCache;
 import com.zkqy.common.utils.DateUtils;
 import com.zkqy.common.utils.SecurityUtils;
 import com.zkqy.common.utils.StringUtils;
@@ -18,6 +19,7 @@ import com.zkqy.execution.produce.dispersed.service.ICommonService;
 import org.apache.poi.xssf.usermodel.XSSFRow;
 import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
@@ -39,6 +41,8 @@ public class CommonServiceImpl implements ICommonService {
 
     @Resource
     private TableSqlMapper tableSqlMapper;
+    @Autowired
+    private RedisCache redisCache;
 
 
     @Override
@@ -76,9 +80,12 @@ public class CommonServiceImpl implements ICommonService {
         mapList.stream().forEach(map1 -> {
             map1.forEach((key, value) -> {
                 fieldNames.add(toUnderScoreCase(key));
+                if (value.toString().indexOf("file:base64:") != -1) {
+                    // 更新数据
+                    value = redisCache.getCacheList(value.toString().replace("file:base64:", ""));
+                }
             });
         });
-        //
         List<String> sequenceMap = new ArrayList<>(linkedHashMap.keySet());
         for (int e = 0; e < sequenceMap.size(); e++) {
             // 交换键值对位置
@@ -89,6 +96,7 @@ public class CommonServiceImpl implements ICommonService {
                 mapList.get(i).put(entry, val);
             }
         }
+        // file:base64:cc61a700-94d0-46c8-b3f3-7485c4a886fd
         return commonMapper.batchInsert(fieldNames, tableName, mapList);
     }
 

+ 1 - 1
zkqy-ui/src/layout/index.vue

@@ -192,7 +192,7 @@ export default {
     this.getlogo();
     var user = JSON.parse(sessionStorage.getItem("sessionObj"));
     if (user) {
-      this.userName = JSON.parse(user.data()).username;
+      this.userName = JSON.parse(user.data).username;
     }
     // this.startTokenRefresh();
   },

+ 115 - 31
zkqy-ui/src/views/index.vue

@@ -1,29 +1,32 @@
 <template>
   <div class="app-container home">
-    <!--    <div>-->
-    <!--      <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>-->
-    <!--        <el-upload ref="upload" :limit="1"   :headers="upload.headers"-->
-    <!--                   :action="upload.url" :disabled="upload.isUploading"-->
-    <!--                   :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>-->
-    <!--          <i class="el-icon-upload"></i>-->
-    <!--          <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>-->
-    <!--          <div class="el-upload__tip text-center" slot="tip">-->
-    <!--            <div class="el-upload__tip" slot="tip">-->
-    <!--              <el-checkbox v-model="upload.updateSupport"/>-->
-    <!--              是否更新已经存在的用户数据-->
-    <!--            </div>-->
-    <!--            <span>仅允许导入xls、xlsx格式文件。</span>-->
-    <!--            <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline"-->
-    <!--                     @click="importTemplate">下载模板-->
-    <!--            </el-link>-->
-    <!--          </div>-->
-    <!--        </el-upload>-->
-    <!--        <div slot="footer" class="dialog-footer">-->
-    <!--          <el-button type="primary" @click="submitFileForm">确 定</el-button>-->
-    <!--          <el-button @click="upload.open = false">取 消</el-button>-->
-    <!--        </div>-->
-    <!--      </el-dialog>-->
-    <!--    </div>-->
+
+    <div>
+      <button @click="upload.open = true">上传</button>
+      <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
+
+        <!--        :on-progress="handleFileUploadProgress"
+                           :on-success="handleFileSuccess"-->
+        <el-upload ref="upload" :headers="upload.headers"
+                   :action="upload.url" :disabled="upload.isUploading"
+
+                   :auto-upload="false"
+                   :file-list="upload.fileList"
+                   multiple drag>
+          <i class="el-icon-upload"></i>
+
+
+          <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+          <div class="el-upload__tip text-center" slot="tip"></div>
+        </el-upload>
+        <div slot="footer" class="dialog-footer">
+          <el-button type="primary" @click="submitFileForm">确 定</el-button>
+          <el-button @click="upload.open = false">取 消</el-button>
+        </div>
+      </el-dialog>
+    </div>
+
+
     <!-- <el-row :gutter="20"></el-row>
     <el-row :gutter="20"></el-row>
     <el-divider/>
@@ -104,11 +107,7 @@
         <div class="swiper-container">
           <div class="swiper-scrollbar"></div>
           <div class="swiper-wrapper">
-            <div
-              class="swiper-slide"
-              v-for="(item, index) in swiperList"
-              :key="index"
-            >
+            <div class="swiper-slide" v-for="(item, index) in swiperList" :key="index">
               <div>
                 <span class="name">{{ item.operName }}</span>
                 <span class="ip">{{ item.operIp }}</span>
@@ -180,6 +179,8 @@ export default {
       ],
       // 用户导入参数
       upload: {
+        // 文件列表
+        fileList: [],
         // 是否显示弹出层(用户导入)
         open: true,
         // 弹出层标题(用户导入)
@@ -191,7 +192,7 @@ export default {
         // 设置上传的请求头部
         headers: {Authorization: "Bearer " + getToken()},
         // 上传的地址
-        url: process.env.VUE_APP_BASE_API1 + "common/tenantUploadFile",
+        url: process.env.VUE_APP_BASE_API1 + "common/tenantUploadFiles",
       },
       // 版本号
       version: "3.8.5",
@@ -627,8 +628,91 @@ export default {
     },
     // 提交上传文件
     submitFileForm() {
-      this.$refs.upload.submit();
+      console.log(this.$refs.upload);
+      let {uploadFiles, action, data} = this.$refs.upload
+      console.log("uploadFiles", uploadFiles)
+      console.log("action", action)
+      console.log("data", data)
+      data = {}
+      uploadFiles.map(file => {
+        data[file.name.split(".")[0]] = true
+      });
+      data.WechatIMG379 = false;
+
+      this.uploadFiles({
+        uploadFiles,
+        data,
+        action,
+        success: (response) => {
+          console.log(response)
+          // 上传成功后,将里面的内容删除
+          this.$refs.uploadFile.clearFiles();
+          this.$refs.uploadPicture.clearFiles();
+        },
+        error: (error) => {
+          console.log('失败了', error)
+        }
+      })
+      // this.$refs.upload.submit();
     },
+
+    uploadFiles({uploadFiles, headers, data, action, success, error}) {
+      let form = new FormData();
+      uploadFiles.map(file => form.append("files", file.raw))
+      for (let key in data) {
+        form.append(key, data[key])
+      }
+      let xhr = new XMLHttpRequest()
+      xhr.open("post", action, true)
+      xhr.setRequestHeader("Authorization", getToken());
+      xhr.onreadystatechange = function () {
+        if (xhr.readyState == 4) {
+          if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
+            success && success(xhr.responseText)
+          } else {
+            error && error(xhr.status)
+          }
+        }
+      }
+      xhr.send(form)
+
+      // let fileVoList = [];
+      // let form = new FormData();
+      //
+      // // 文件对象
+      // uploadFiles.map(file => {
+      //   let fileVo = {
+      //     "file": file.raw,
+      //     "isBase64": false
+      //   }
+      //   fileVoList.push(fileVo);
+      // })
+      //
+      // 附件参数
+      // for (let key in data) {
+      //   form.append(key, data[key])
+      // }
+      // let xhr = new XMLHttpRequest()
+      // // 异步请求
+      // xhr.open("post", action, true)
+      // // 设置请求头
+      // xhr.setRequestHeader("Authorization", getToken());
+      // xhr.onreadystatechange = function () {
+      //   if (xhr.readyState == 4) {
+      //     if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
+      //       success && success(xhr.responseText)
+      //     } else {
+      //       error && error(xhr.status)
+      //     }
+      //   }
+      // }
+      // console.log("form内容:", fileVoList)
+      // xhr.send({
+      //   "fileVoList": fileVoList
+      // })
+    },
+
+
     goTarget(href) {
       window.open(href, "_blank");
     },

+ 0 - 50
zkqy-ui/src/views/system/engineeringManage/adss.html

@@ -1,50 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-  <meta charset="UTF-8">
-  <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>春节倒计时</title>
-  <style>
-    body {
-      font-family: Arial, sans-serif;
-      text-align: center;
-      margin: 50px;
-    }
-    #countdown {
-      font-size: 24px;
-      font-weight: bold;
-      color: #333;
-    }
-  </style>
-</head>
-<body>
-
-<h1>春节倒计时</h1>
-<div id="countdown"></div>
-
-<script>
-  // 目标日期,春节的日期(假设是2024年的春节,你可以根据实际情况修改)
-  const targetDate = new Date("2024-02-10T00:00:00Z").getTime();
-
-  // 更新倒计时
-  function updateCountdown() {
-    const currentDate = new Date().getTime();
-    const timeDifference = targetDate - currentDate;
-
-    const days = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
-    const hours = Math.floor((timeDifference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
-    const minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
-    const seconds = Math.floor((timeDifference % (1000 * 60)) / 1000);
-
-    document.getElementById("countdown").innerHTML = `${days} 天 ${hours} 小时 ${minutes} 分钟 ${seconds} 秒`;
-  }
-
-  // 每秒更新一次倒计时
-  setInterval(updateCountdown, 1000);
-
-  // 初始加载
-  updateCountdown();
-</script>
-
-</body>
-</html>