Commit 2ad1001e94c75aa423da7095546b18af68c3e837
1 parent
8679ad21
修复录像并发下载内存占用过多的问题
Showing
2 changed files
with
198 additions
and
174 deletions
src/main/java/top/panll/assist/config/WebMvcConfig.java
0 → 100644
| 1 | +package top.panll.assist.config; | |
| 2 | + | |
| 3 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 4 | +import org.springframework.context.annotation.Configuration; | |
| 5 | +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; | |
| 6 | +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; | |
| 7 | +import top.panll.assist.dto.UserSettings; | |
| 8 | + | |
| 9 | +import java.io.File; | |
| 10 | + | |
| 11 | + | |
| 12 | +@Configuration | |
| 13 | +public class WebMvcConfig extends WebMvcConfigurerAdapter { | |
| 14 | + | |
| 15 | + @Autowired | |
| 16 | + private UserSettings userSettings; | |
| 17 | + | |
| 18 | + @Override | |
| 19 | + public void addResourceHandlers(ResourceHandlerRegistry registry) { | |
| 20 | + File file = new File(userSettings.getRecord()); | |
| 21 | + registry.addResourceHandler("/download/**").addResourceLocations("file://" + file.getAbsolutePath() + "/"); | |
| 22 | + super.addResourceHandlers(registry); | |
| 23 | + } | |
| 24 | +} | ... | ... |
src/main/java/top/panll/assist/controller/DownloadController.java
| 1 | -package top.panll.assist.controller; | |
| 2 | - | |
| 3 | - | |
| 4 | -import io.swagger.v3.oas.annotations.Operation; | |
| 5 | -import io.swagger.v3.oas.annotations.Parameter; | |
| 6 | -import io.swagger.v3.oas.annotations.tags.Tag; | |
| 7 | -import org.apache.catalina.connector.ClientAbortException; | |
| 8 | -import org.slf4j.Logger; | |
| 9 | -import org.slf4j.LoggerFactory; | |
| 10 | -import org.springframework.beans.factory.annotation.Autowired; | |
| 11 | -import org.springframework.stereotype.Controller; | |
| 12 | -import org.springframework.web.bind.annotation.*; | |
| 13 | -import top.panll.assist.dto.UserSettings; | |
| 14 | -import top.panll.assist.utils.PageInfo; | |
| 15 | - | |
| 16 | -import javax.servlet.http.HttpServletRequest; | |
| 17 | -import javax.servlet.http.HttpServletResponse; | |
| 18 | -import java.io.BufferedOutputStream; | |
| 19 | -import java.io.File; | |
| 20 | -import java.io.IOException; | |
| 21 | -import java.io.RandomAccessFile; | |
| 22 | -import java.nio.charset.StandardCharsets; | |
| 23 | -import java.util.List; | |
| 24 | -import java.util.Map; | |
| 25 | - | |
| 26 | -@Controller | |
| 27 | -@RequestMapping("/download") | |
| 28 | -public class DownloadController { | |
| 29 | - | |
| 30 | - private final static Logger logger = LoggerFactory.getLogger(DownloadController.class); | |
| 31 | - | |
| 32 | - @Autowired | |
| 33 | - private UserSettings userSettings; | |
| 34 | - | |
| 35 | - /** | |
| 36 | - * 获取app+stream列表 | |
| 37 | - * | |
| 38 | - * @return | |
| 39 | - */ | |
| 40 | - @GetMapping(value = "/**") | |
| 41 | - @ResponseBody | |
| 42 | - public void download(HttpServletRequest request, HttpServletResponse response) { | |
| 43 | - | |
| 44 | - String resourcePath = request.getServletPath(); | |
| 45 | - System.out.println(resourcePath); | |
| 46 | - resourcePath = resourcePath.substring("/download".length() + 1, resourcePath.length()); | |
| 47 | - String record = userSettings.getRecord(); | |
| 48 | -// if (record.endsWith("/")) { | |
| 49 | -// record = record.substring(0, record.length() - 1); | |
| 50 | -// System.out.println(record); | |
| 1 | +//package top.panll.assist.controller; | |
| 2 | +// | |
| 3 | +// | |
| 4 | +//import io.swagger.v3.oas.annotations.Operation; | |
| 5 | +//import io.swagger.v3.oas.annotations.Parameter; | |
| 6 | +//import io.swagger.v3.oas.annotations.tags.Tag; | |
| 7 | +//import org.apache.catalina.connector.ClientAbortException; | |
| 8 | +//import org.slf4j.Logger; | |
| 9 | +//import org.slf4j.LoggerFactory; | |
| 10 | +//import org.springframework.beans.factory.annotation.Autowired; | |
| 11 | +//import org.springframework.stereotype.Controller; | |
| 12 | +//import org.springframework.web.bind.annotation.*; | |
| 13 | +//import top.panll.assist.dto.UserSettings; | |
| 14 | +//import top.panll.assist.utils.PageInfo; | |
| 15 | +// | |
| 16 | +//import javax.servlet.http.HttpServletRequest; | |
| 17 | +//import javax.servlet.http.HttpServletResponse; | |
| 18 | +//import java.io.BufferedOutputStream; | |
| 19 | +//import java.io.File; | |
| 20 | +//import java.io.IOException; | |
| 21 | +//import java.io.RandomAccessFile; | |
| 22 | +//import java.nio.charset.StandardCharsets; | |
| 23 | +//import java.util.List; | |
| 24 | +//import java.util.Map; | |
| 25 | +// | |
| 26 | +//@Controller | |
| 27 | +//@RequestMapping("/download") | |
| 28 | +//public class DownloadController { | |
| 29 | +// | |
| 30 | +// private final static Logger logger = LoggerFactory.getLogger(DownloadController.class); | |
| 31 | +// | |
| 32 | +// @Autowired | |
| 33 | +// private UserSettings userSettings; | |
| 34 | +// | |
| 35 | +// /** | |
| 36 | +// * 获取app+stream列表 | |
| 37 | +// * | |
| 38 | +// * @return | |
| 39 | +// */ | |
| 40 | +// @GetMapping(value = "/**") | |
| 41 | +// @ResponseBody | |
| 42 | +// public void download(HttpServletRequest request, HttpServletResponse response) { | |
| 43 | +// | |
| 44 | +// String resourcePath = request.getServletPath(); | |
| 45 | +// System.out.println(resourcePath); | |
| 46 | +// resourcePath = resourcePath.substring("/download".length() + 1, resourcePath.length()); | |
| 47 | +// String record = userSettings.getRecord(); | |
| 48 | +//// if (record.endsWith("/")) { | |
| 49 | +//// record = record.substring(0, record.length() - 1); | |
| 50 | +//// System.out.println(record); | |
| 51 | +//// } | |
| 52 | +// System.out.println(record + resourcePath); | |
| 53 | +// File file = new File(record + resourcePath); | |
| 54 | +// if (!file.exists()) { | |
| 55 | +// response.setStatus(HttpServletResponse.SC_NOT_FOUND); | |
| 56 | +// return; | |
| 51 | 57 | // } |
| 52 | - System.out.println(record + resourcePath); | |
| 53 | - File file = new File(record + resourcePath); | |
| 54 | - if (!file.exists()) { | |
| 55 | - response.setStatus(HttpServletResponse.SC_NOT_FOUND); | |
| 56 | - return; | |
| 57 | - } | |
| 58 | - | |
| 59 | - /** | |
| 60 | - * 参考实现来自: CSDN 进修的CODER SpringBoot Java实现Http方式分片下载断点续传+实现H5大视频渐进式播放 | |
| 61 | - * https://blog.csdn.net/lovequanquqn/article/details/104562945 | |
| 62 | - */ | |
| 63 | - String range = request.getHeader("Range"); | |
| 64 | - logger.info("current request rang:" + range); | |
| 65 | - //开始下载位置 | |
| 66 | - long startByte = 0; | |
| 67 | - //结束下载位置 | |
| 68 | - long endByte = file.length() - 1; | |
| 69 | - logger.info("文件开始位置:{},文件结束位置:{},文件总长度:{}", startByte, endByte, file.length()); | |
| 70 | - | |
| 71 | - //有range的话 | |
| 72 | - if (range != null && range.contains("bytes=") && range.contains("-")) { | |
| 73 | - range = range.substring(range.lastIndexOf("=") + 1).trim(); | |
| 74 | - String[] ranges = range.split("-"); | |
| 75 | - try { | |
| 76 | - //判断range的类型 | |
| 77 | - if (ranges.length == 1) { | |
| 78 | - // 类型一:bytes=-2343, | |
| 79 | - if (range.startsWith("-")) { | |
| 80 | - endByte = Long.parseLong(ranges[0]); | |
| 81 | - } | |
| 82 | - //类型二:bytes=2343- | |
| 83 | - else if (range.endsWith("-")) { | |
| 84 | - startByte = Long.parseLong(ranges[0]); | |
| 85 | - } | |
| 86 | - } | |
| 87 | - //类型三:bytes=22-2343 | |
| 88 | - else if (ranges.length == 2) { | |
| 89 | - startByte = Long.parseLong(ranges[0]); | |
| 90 | - endByte = Long.parseLong(ranges[1]); | |
| 91 | - } | |
| 92 | - | |
| 93 | - } catch (NumberFormatException e) { | |
| 94 | - startByte = 0; | |
| 95 | - endByte = file.length() - 1; | |
| 96 | - logger.error("Range Occur Error,Message:{}", e.getLocalizedMessage()); | |
| 97 | - } | |
| 98 | - | |
| 99 | - | |
| 100 | - } | |
| 101 | - | |
| 102 | - // 要下载的长度 | |
| 103 | - long contentLength = endByte - startByte + 1; | |
| 104 | - // 文件名 | |
| 105 | - String fileName = file.getName(); | |
| 106 | - // 文件类型 | |
| 107 | - String contentType = request.getServletContext().getMimeType(fileName); | |
| 108 | - | |
| 109 | - // 解决下载文件时文件名乱码问题 | |
| 110 | - byte[] fileNameBytes = fileName.getBytes(StandardCharsets.UTF_8); | |
| 111 | - fileName = new String(fileNameBytes, 0, fileNameBytes.length, StandardCharsets.ISO_8859_1); | |
| 112 | - | |
| 113 | - response.setHeader("Content-Type", contentType); | |
| 114 | - response.setHeader("Content-Length", String.valueOf(contentLength)); | |
| 115 | - //inline表示浏览器直接使用,attachment表示下载,fileName表示下载的文件名 | |
| 116 | - response.setHeader("Content-Disposition", "inline;filename=" + fileName); | |
| 117 | - response.setContentType(contentType); | |
| 118 | - if (range != null) { | |
| 119 | - //各种响应头设置 | |
| 120 | - //支持断点续传,获取部分字节内容: | |
| 121 | - response.setHeader("Accept-Ranges", "bytes"); | |
| 122 | - //http状态码要为206:表示获取部分内容 | |
| 123 | - response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); | |
| 124 | - // Content-Range,格式为:[要下载的开始位置]-[结束位置]/[文件总大小] | |
| 125 | - response.setHeader("Content-Range", "bytes " + startByte + "-" + endByte + "/" + file.length()); | |
| 126 | - } else { | |
| 127 | - response.setStatus(HttpServletResponse.SC_OK); | |
| 128 | - } | |
| 129 | - | |
| 130 | - | |
| 131 | - BufferedOutputStream outputStream = null; | |
| 132 | - RandomAccessFile randomAccessFile = null; | |
| 133 | - //已传送数据大小 | |
| 134 | - long transmitted = 0; | |
| 135 | - try { | |
| 136 | - randomAccessFile = new RandomAccessFile(file, "r"); | |
| 137 | - | |
| 138 | - outputStream = new BufferedOutputStream(response.getOutputStream()); | |
| 139 | - byte[] buff = new byte[4096]; | |
| 140 | - int len = 0; | |
| 141 | - randomAccessFile.seek(startByte); | |
| 142 | - //warning:判断是否到了最后不足4096(buff的length)个byte这个逻辑((transmitted + len) <= contentLength)要放前面 | |
| 143 | - //不然会会先读取randomAccessFile,造成后面读取位置出错; | |
| 144 | - while ((transmitted + len) <= contentLength && (len = randomAccessFile.read(buff)) != -1) { | |
| 145 | - outputStream.write(buff, 0, len); | |
| 146 | - transmitted += len; | |
| 147 | - } | |
| 148 | - //处理不足buff.length部分 | |
| 149 | - if (transmitted < contentLength) { | |
| 150 | - len = randomAccessFile.read(buff, 0, (int) (contentLength - transmitted)); | |
| 151 | - outputStream.write(buff, 0, len); | |
| 152 | - transmitted += len; | |
| 153 | - } | |
| 154 | - | |
| 155 | - outputStream.flush(); | |
| 156 | - response.flushBuffer(); | |
| 157 | - randomAccessFile.close(); | |
| 158 | - logger.info("下载完毕:" + startByte + "-" + endByte + ":" + transmitted); | |
| 159 | - } catch (ClientAbortException e) { | |
| 160 | - logger.warn("用户停止下载:" + startByte + "-" + endByte + ":" + transmitted); | |
| 161 | - //捕获此异常表示拥护停止下载 | |
| 162 | - } catch (IOException e) { | |
| 163 | - e.printStackTrace(); | |
| 164 | - logger.error("用户下载IO异常,Message:{}", e.getLocalizedMessage()); | |
| 165 | - } finally { | |
| 166 | - try { | |
| 167 | - if (randomAccessFile != null) { | |
| 168 | - randomAccessFile.close(); | |
| 169 | - } | |
| 170 | - } catch (IOException e) { | |
| 171 | - e.printStackTrace(); | |
| 172 | - } | |
| 173 | - }///end try | |
| 174 | - } | |
| 175 | -} | |
| 58 | +// | |
| 59 | +// /** | |
| 60 | +// * 参考实现来自: CSDN 进修的CODER SpringBoot Java实现Http方式分片下载断点续传+实现H5大视频渐进式播放 | |
| 61 | +// * https://blog.csdn.net/lovequanquqn/article/details/104562945 | |
| 62 | +// */ | |
| 63 | +// String range = request.getHeader("Range"); | |
| 64 | +// logger.info("current request rang:" + range); | |
| 65 | +// //开始下载位置 | |
| 66 | +// long startByte = 0; | |
| 67 | +// //结束下载位置 | |
| 68 | +// long endByte = file.length() - 1; | |
| 69 | +// logger.info("文件开始位置:{},文件结束位置:{},文件总长度:{}", startByte, endByte, file.length()); | |
| 70 | +// | |
| 71 | +// //有range的话 | |
| 72 | +// if (range != null && range.contains("bytes=") && range.contains("-")) { | |
| 73 | +// range = range.substring(range.lastIndexOf("=") + 1).trim(); | |
| 74 | +// String[] ranges = range.split("-"); | |
| 75 | +// try { | |
| 76 | +// //判断range的类型 | |
| 77 | +// if (ranges.length == 1) { | |
| 78 | +// // 类型一:bytes=-2343, | |
| 79 | +// if (range.startsWith("-")) { | |
| 80 | +// endByte = Long.parseLong(ranges[0]); | |
| 81 | +// } | |
| 82 | +// //类型二:bytes=2343- | |
| 83 | +// else if (range.endsWith("-")) { | |
| 84 | +// startByte = Long.parseLong(ranges[0]); | |
| 85 | +// } | |
| 86 | +// } | |
| 87 | +// //类型三:bytes=22-2343 | |
| 88 | +// else if (ranges.length == 2) { | |
| 89 | +// startByte = Long.parseLong(ranges[0]); | |
| 90 | +// endByte = Long.parseLong(ranges[1]); | |
| 91 | +// } | |
| 92 | +// | |
| 93 | +// } catch (NumberFormatException e) { | |
| 94 | +// startByte = 0; | |
| 95 | +// endByte = file.length() - 1; | |
| 96 | +// logger.error("Range Occur Error,Message:{}", e.getLocalizedMessage()); | |
| 97 | +// } | |
| 98 | +// | |
| 99 | +// | |
| 100 | +// } | |
| 101 | +// | |
| 102 | +// // 要下载的长度 | |
| 103 | +// long contentLength = endByte - startByte + 1; | |
| 104 | +// // 文件名 | |
| 105 | +// String fileName = file.getName(); | |
| 106 | +// // 文件类型 | |
| 107 | +// String contentType = request.getServletContext().getMimeType(fileName); | |
| 108 | +// | |
| 109 | +// // 解决下载文件时文件名乱码问题 | |
| 110 | +// byte[] fileNameBytes = fileName.getBytes(StandardCharsets.UTF_8); | |
| 111 | +// fileName = new String(fileNameBytes, 0, fileNameBytes.length, StandardCharsets.ISO_8859_1); | |
| 112 | +// | |
| 113 | +// response.setHeader("Content-Type", contentType); | |
| 114 | +// response.setHeader("Content-Length", String.valueOf(contentLength)); | |
| 115 | +// //inline表示浏览器直接使用,attachment表示下载,fileName表示下载的文件名 | |
| 116 | +// response.setHeader("Content-Disposition", "inline;filename=" + fileName); | |
| 117 | +// response.setContentType(contentType); | |
| 118 | +// if (range != null) { | |
| 119 | +// //各种响应头设置 | |
| 120 | +// //支持断点续传,获取部分字节内容: | |
| 121 | +// response.setHeader("Accept-Ranges", "bytes"); | |
| 122 | +// //http状态码要为206:表示获取部分内容 | |
| 123 | +// response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); | |
| 124 | +// // Content-Range,格式为:[要下载的开始位置]-[结束位置]/[文件总大小] | |
| 125 | +// response.setHeader("Content-Range", "bytes " + startByte + "-" + endByte + "/" + file.length()); | |
| 126 | +// } else { | |
| 127 | +// response.setStatus(HttpServletResponse.SC_OK); | |
| 128 | +// } | |
| 129 | +// | |
| 130 | +// | |
| 131 | +// BufferedOutputStream outputStream = null; | |
| 132 | +// RandomAccessFile randomAccessFile = null; | |
| 133 | +// //已传送数据大小 | |
| 134 | +// long transmitted = 0; | |
| 135 | +// try { | |
| 136 | +// randomAccessFile = new RandomAccessFile(file, "r"); | |
| 137 | +// | |
| 138 | +// outputStream = new BufferedOutputStream(response.getOutputStream()); | |
| 139 | +// byte[] buff = new byte[4096]; | |
| 140 | +// int len = 0; | |
| 141 | +// randomAccessFile.seek(startByte); | |
| 142 | +// //warning:判断是否到了最后不足4096(buff的length)个byte这个逻辑((transmitted + len) <= contentLength)要放前面 | |
| 143 | +// //不然会会先读取randomAccessFile,造成后面读取位置出错; | |
| 144 | +// while ((transmitted + len) <= contentLength && (len = randomAccessFile.read(buff)) != -1) { | |
| 145 | +// outputStream.write(buff, 0, len); | |
| 146 | +// transmitted += len; | |
| 147 | +// } | |
| 148 | +// //处理不足buff.length部分 | |
| 149 | +// if (transmitted < contentLength) { | |
| 150 | +// len = randomAccessFile.read(buff, 0, (int) (contentLength - transmitted)); | |
| 151 | +// outputStream.write(buff, 0, len); | |
| 152 | +// transmitted += len; | |
| 153 | +// } | |
| 154 | +// | |
| 155 | +// outputStream.flush(); | |
| 156 | +// response.flushBuffer(); | |
| 157 | +// randomAccessFile.close(); | |
| 158 | +// logger.info("下载完毕:" + startByte + "-" + endByte + ":" + transmitted); | |
| 159 | +// } catch (ClientAbortException e) { | |
| 160 | +// logger.warn("用户停止下载:" + startByte + "-" + endByte + ":" + transmitted); | |
| 161 | +// //捕获此异常表示拥护停止下载 | |
| 162 | +// } catch (IOException e) { | |
| 163 | +// e.printStackTrace(); | |
| 164 | +// logger.error("用户下载IO异常,Message:{}", e.getLocalizedMessage()); | |
| 165 | +// } finally { | |
| 166 | +// try { | |
| 167 | +// if (randomAccessFile != null) { | |
| 168 | +// randomAccessFile.close(); | |
| 169 | +// } | |
| 170 | +// } catch (IOException e) { | |
| 171 | +// e.printStackTrace(); | |
| 172 | +// } | |
| 173 | +// }///end try | |
| 174 | +// } | |
| 175 | +//} | ... | ... |