修改文件下载方式,使用StreamingResponseBody,支持大文件下载
This commit is contained in:
@@ -9,18 +9,24 @@ import cn.somkit.fmt.utils.PathUtils;
|
|||||||
import cn.somkit.fmt.utils.RocksDBUtils;
|
import cn.somkit.fmt.utils.RocksDBUtils;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.FileSystemUtils;
|
import org.springframework.util.FileSystemUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.context.request.async.DeferredResult;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -91,32 +97,45 @@ public class DownloadAction {
|
|||||||
return mv;
|
return mv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping("/execute")
|
@ApiOperate(description = "StreamingResponseBody方式下载文件")
|
||||||
@ApiOperate(description = "单文件下载")
|
@GetMapping(value = "/file", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||||
public void execute(String path, Boolean temp, HttpServletResponse response) throws Exception {
|
public DeferredResult<ResponseEntity<StreamingResponseBody>> downloadFileByPath(String path, Boolean temp) throws Exception {
|
||||||
File file = new File(path);
|
final File file = new File(path);
|
||||||
if (!file.isFile()) {
|
final DeferredResult<ResponseEntity<StreamingResponseBody>> result = new DeferredResult<>();
|
||||||
throw new FileNotFoundException("文件不存在");
|
|
||||||
|
if (!file.exists()) {
|
||||||
|
result.setErrorResult(new RuntimeException("文件不存在"));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
String filename = file.getName();
|
|
||||||
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8));
|
HttpHeaders headers = new HttpHeaders();
|
||||||
response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(file.length()));
|
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + URLEncoder.encode(file.getName(), StandardCharsets.UTF_8));
|
||||||
try (FileInputStream fileInputStream = new FileInputStream(file);
|
headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(file.length()));
|
||||||
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
|
StreamingResponseBody body = outputStream -> {
|
||||||
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(response.getOutputStream())) {
|
try (InputStream inputStream = new FileInputStream(file)) {
|
||||||
byte[] buffer_ = new byte[1024];
|
byte[] buffer = new byte[1024];
|
||||||
int n = bufferedInputStream.read(buffer_);
|
int bytesRead;
|
||||||
while (n != -1) {
|
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||||
bufferedOutputStream.write(buffer_);
|
outputStream.write(buffer, 0, bytesRead);
|
||||||
n = bufferedInputStream.read(buffer_);
|
}
|
||||||
|
outputStream.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("IO错误: " + e.getMessage());
|
||||||
|
} finally {
|
||||||
|
// 尝试在流关闭后删除文件
|
||||||
|
try {
|
||||||
|
if(temp){
|
||||||
|
Files.deleteIfExists(file.toPath());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// 记录日志或采取其他措施
|
||||||
|
System.err.println("删除文件失败: " + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
};
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
result.setResult(new ResponseEntity<>(body, headers, HttpStatus.OK));
|
||||||
if(temp){//删除临时文件
|
return result;
|
||||||
FileSystemUtils.deleteRecursively(new File(path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/packZip")
|
@PostMapping("/packZip")
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
|
|
||||||
const fileDown = (obj) => {
|
const fileDown = (obj) => {
|
||||||
const path = obj.getAttribute("value");
|
const path = obj.getAttribute("value");
|
||||||
window.open(Fmt.ctx() + '/download/execute?path=' + encodeURIComponent(path) + '&temp=' + false);
|
window.open(Fmt.ctx() + '/download/file?path=' + encodeURIComponent(path) + '&temp=' + false);
|
||||||
};
|
};
|
||||||
|
|
||||||
window.onload = () => {
|
window.onload = () => {
|
||||||
@@ -139,7 +139,7 @@
|
|||||||
};
|
};
|
||||||
Fmt.axios(options).then((result) => {
|
Fmt.axios(options).then((result) => {
|
||||||
message.update({content: '压缩包' + result.filename + "创建完成,准备下载文件......", result: 'success'}).show();
|
message.update({content: '压缩包' + result.filename + "创建完成,准备下载文件......", result: 'success'}).show();
|
||||||
window.open(Fmt.ctx() + '/download/execute?path=' + encodeURIComponent(result.path) + '&temp=' + true);
|
window.open(Fmt.ctx() + '/download/file?path=' + encodeURIComponent(result.path) + '&temp=' + true);
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
new axMessage({content: err, result: 'error', iconShow: true}).show();
|
new axMessage({content: err, result: 'error', iconShow: true}).show();
|
||||||
|
|||||||
@@ -23,4 +23,5 @@
|
|||||||
修改上传文件目录配置,使其支持使用相对路径
|
修改上传文件目录配置,使其支持使用相对路径
|
||||||
新增临时文件存放地址配置,支持相对路径
|
新增临时文件存放地址配置,支持相对路径
|
||||||
新增系统设置页面,支持在线配置上传文件地址、日志文件地址等参数
|
新增系统设置页面,支持在线配置上传文件地址、日志文件地址等参数
|
||||||
|
修改文件下载方式,使用StreamingResponseBody,支持大文件下载
|
||||||
```
|
```
|
||||||
Reference in New Issue
Block a user