2 커밋 6281d70e5e ... b050cbf659

작성자 SHA1 메시지 날짜
  Twelve615 b050cbf659 :recycle: 更新视频下载部分逻辑,适配ios与mac 1 년 전
  Twelve615 323f31b7e9 :sparkles: 懒加载树增加只选择最后一个子节点功能 1 년 전

+ 28 - 1
jlsb-vue/src/components/jeecg/JTreeSelect.vue

@@ -74,7 +74,12 @@
         type: Boolean,
         default: false,
         required:false
-      }
+      },
+      // 是否只选择子节点,为True时只有叶子节点可以选择
+      chooseChild: {
+        type: Boolean,
+        default: false,
+      },
     },
     data () {
       return {
@@ -156,8 +161,14 @@
                 i.value = i.key
                 if(i.leaf==false){
                   i.isLeaf=false
+                  if(this.chooseChild) {
+                    i.selectable = false;
+                  }
                 }else if(i.leaf==true){
                   i.isLeaf=true
+                  if(this.chooseChild && i.parentId ==='0') {
+                    i.selectable = false;
+                  }
                 }
               }
               this.addChildren(pid,res.result,this.treeData)
@@ -173,14 +184,24 @@
             if(item.key == pid){
               if(!children || children.length==0){
                 item.isLeaf=true
+                if(this.chooseChild && item.parentId ==='0') {
+                  children.selectable = false;
+                }
               }else{
                 item.children = children
+                if(this.chooseChild) {
+                  item.selectable = false;
+                }
               }
               break
             }else{
               this.addChildren(pid,children,item.children)
             }
           }
+        } else {
+          if(this.chooseChild && children.parentId ==='0') {
+            children.selectable = false;
+          }
         }
       },
       loadRoot(){
@@ -199,8 +220,14 @@
               i.value = i.key
               if(i.leaf==false){
                 i.isLeaf=false
+                if(this.chooseChild) {
+                  i.selectable = false;
+                }
               }else if(i.leaf==true){
                 i.isLeaf=true
+                if(this.chooseChild && i.parentId ==='0') {
+                  i.selectable = false;
+                }
               }
             }
             this.treeData = [...res.result]

+ 2 - 0
jlsb-vue/src/views/aa/modules/AaCommodityForm.vue

@@ -41,10 +41,12 @@
           <a-col :span="24">
             <a-form-model-item label="分类" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="typeId">
   	          <j-tree-select
+                :choose-child="true"
                 ref="treeSelect"
                 placeholder="请选择分类"
                 v-model="model.typeId"
                 dict="aa_commodity_fl,name,id"
+                :hasChildField="'has_child'"
                 pidValue="0"
                 >
               </j-tree-select>

+ 102 - 9
jlsb/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/CommonController.java

@@ -1,8 +1,13 @@
 package org.jeecg.modules.system.controller;
 
 import cn.hutool.cache.file.LFUFileCache;
+import cn.hutool.http.HtmlUtil;
+import cn.hutool.http.useragent.Browser;
+import cn.hutool.http.useragent.UserAgent;
+import cn.hutool.http.useragent.UserAgentParser;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.google.common.base.Strings;
 import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.constant.CommonConstant;
@@ -27,10 +32,13 @@ import org.springframework.web.multipart.MultipartHttpServletRequest;
 import org.springframework.web.servlet.HandlerMapping;
 import org.springframework.web.servlet.ModelAndView;
 
+import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.*;
 import java.net.URLDecoder;
+import java.util.Date;
+
 /**
  * <p>
  * 用户表 前端控制器
@@ -222,6 +230,8 @@ public class CommonController {
         if(oConvertUtils.isEmpty(imgPath) || imgPath=="null"){
             return;
         }
+        String userAgent = request.getHeader("User-Agent");
+        UserAgent parse = UserAgentParser.parse(userAgent);
         // 其余处理略
         InputStream inputStream = null;
         OutputStream outputStream = null;
@@ -245,6 +255,19 @@ public class CommonController {
                 //outputStream.write(cacheFile, 0, cacheFile.length);
                 inputStream = new ByteArrayInputStream(cacheFile);
                 log.info("视频缓存");
+                String browserName = parse.getBrowser().getName();
+                String osName = parse.getOs().getName();
+                if ((!Strings.isNullOrEmpty(browserName) && browserName.startsWith("Safari")) || (!Strings.isNullOrEmpty(osName) && osName.startsWith("iPhone"))) {
+                    sendVideo(request, response, file, file.getName());
+                } else {
+                    outputStream = response.getOutputStream();
+                    byte[] buf = new byte[512000];
+                    int len;
+                    while ((len = inputStream.read(buf)) > 0) {
+                        outputStream.write(buf, 0, len);
+                    }
+                    response.flushBuffer();
+                }
             } else {
                 // 内存使用太多不使用缓存
 /*                LFUFileCache fileCache = sysFileCacheService.getFileCache(CACHE_IMG_NAME);
@@ -253,19 +276,17 @@ public class CommonController {
                 inputStream = new ByteArrayInputStream(fileBytes);
                 log.info("其他文件缓存");*/
                 inputStream = new BufferedInputStream(new FileInputStream(filePath));
+                outputStream = response.getOutputStream();
+                byte[] buf = new byte[4096];
+                int len;
+                while ((len = inputStream.read(buf)) > 0) {
+                    outputStream.write(buf, 0, len);
+                }
+                response.flushBuffer();
             }
-            //inputStream = new BufferedInputStream(new FileInputStream(filePath));
-            outputStream = response.getOutputStream();
-            byte[] buf = new byte[4096];
-            int len;
-            while ((len = inputStream.read(buf)) > 0) {
-                outputStream.write(buf, 0, len);
-            }
-            response.flushBuffer();
         } catch (IOException e) {
             log.error("预览文件失败" + e.getMessage());
             response.setStatus(404);
-            e.printStackTrace();
         } finally {
             if (inputStream != null) {
                 try {
@@ -285,6 +306,78 @@ public class CommonController {
 
     }
 
+    private void sendVideo(HttpServletRequest request, HttpServletResponse response, File file, String fileName) throws FileNotFoundException, IOException {
+        RandomAccessFile randomFile = new RandomAccessFile(file, "r");//只读模式
+        long contentLength = randomFile.length();
+        String range = request.getHeader("Range");
+        int start = 0, end = 0;
+        if(range != null && range.startsWith("bytes=")){
+            String[] values = range.split("=")[1].split("-");
+            start = Integer.parseInt(values[0]);
+            if(values.length > 1){
+                end = Integer.parseInt(values[1]);
+            }
+        }
+        int requestSize = 0;
+        if(end != 0 && end > start){
+            requestSize = end - start + 1;
+        } else {
+            requestSize = Integer.MAX_VALUE;
+        }
+
+        response.setContentType("video/mp4");
+        response.setHeader("Accept-Ranges", "bytes");
+        response.setHeader("ETag", fileName);
+        response.setHeader("Last-Modified", new Date().toString());
+        //第一次请求只返回content length来让客户端请求多次实际数据
+        if(range == null){
+            response.setHeader("Content-length", contentLength + "");
+        }else{
+            //以后的多次以断点续传的方式来返回视频数据
+            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);//206
+            long requestStart = 0, requestEnd = 0;
+            String[] ranges = range.split("=");
+            if(ranges.length > 1){
+                String[] rangeDatas = ranges[1].split("-");
+                requestStart = Integer.parseInt(rangeDatas[0]);
+                if(rangeDatas.length > 1){
+                    requestEnd = Integer.parseInt(rangeDatas[1]);
+                }
+            }
+            long length = 0;
+            if(requestEnd > 0){
+                length = requestEnd - requestStart + 1;
+                response.setHeader("Content-length", "" + length);
+                response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + contentLength);
+            }else{
+                length = contentLength - requestStart;
+                response.setHeader("Content-length", "" + length);
+                response.setHeader("Content-Range", "bytes "+ requestStart + "-" + (contentLength - 1) + "/" + contentLength);
+            }
+        }
+        ServletOutputStream out = response.getOutputStream();
+        int needSize = requestSize;
+        randomFile.seek(start);
+        while(needSize > 0){
+            byte[] buffer = new byte[512000];
+            int len = randomFile.read(buffer);
+            if(needSize < buffer.length){
+                out.write(buffer, 0, needSize);
+            } else {
+                out.write(buffer, 0, len);
+                if(len < buffer.length){
+                    break;
+                }
+            }
+            needSize -= buffer.length;
+        }
+        randomFile.close();
+        out.close();
+    }
+
+
+
+
 //	/**
 //	 * 下载文件
 //	 * 请求地址:http://localhost:8080/common/download/{user/20190119/e1fe9925bc315c60addea1b98eb1cb1349547719_1547866868179.jpg}