马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
springboot相应文件流文件给欣赏器+前端下载
1.controller:
- @Api(tags = {"【样本提取系统】-api"})
- @RestController("YbtqYstbtqController")
- @RequiredArgsConstructor
- @RequestMapping("/ybtq-ystbtq")
- @Slf4j
- public class YbtqYstbtqController {
- private final YbService ybService;
- @ApiOperation(value = "【样本集管理】-样本集导出", notes = "export", produces = "application/octet-stream")
- @PostMapping("/ybgl-set-cloud-download")
- @OpLog("【样本集管理】-样本集导出")
- public void ybGlYbSetDownload(@RequestBody List<String> pkIds, HttpServletResponse response) throws Exception {
- FileDownloadVo fileDownloadVo = tileSetService.ybGlYbSetDownload(pkIds);
- if (null != fileDownloadVo && fileDownloadVo.getFileStream() != null) {
- try (InputStream inputStream = fileDownloadVo.getFileStream();
- OutputStream outputStream = response.getOutputStream()) {
- //先将字符串以UTF-8转换成字节数组,再将字节数组以ISO-8859-1转换字符串(标准)
- String fileName = new String(fileDownloadVo.getFileName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
- response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName,"utf-8"));
- response.setContentType(fileDownloadVo.getContentType());
- response.setCharacterEncoding("UTF-8");
- // 响应文件给浏览器
- IOUtils.copy(inputStream, outputStream);
- } catch (Exception e) {
- e.printStackTrace();
- }
- } else{
- response.setContentType("application/json;charset=utf-8");
- response.getWriter().write(JSONUtil.toJsonStr(Result.error("所选样本集无有效文件!")));
- }
- }
- }
复制代码 文件下载对象FileDownloadVo:
- /**
- * 文件下载对象
- */
- @Data
- public class FileDownloadVo {
- /**
- * 文件名称
- */
- @ApiModelProperty("文件名称")
- private String fileName;
- /**
- * 文件content-type
- */
- @ApiModelProperty("content-type")
- private String contentType;
- /**
- * 文件流
- */
- @ApiModelProperty("文件流")
- private InputStream fileStream;
- }
复制代码 2.serviceImpl:
- @Override
- public FileDownloadVo ybGlYbSetDownload(List<String> pkIds) {
- // 文件根目录
- FileDownloadVo ret = new FileDownloadVo();
- // 获取样本集信息
- List<TileSet> ybSetList = tileSetMapper.selectList(new LambdaQueryWrapper<TileSet>().in(TileSet::getPkId, pkIds));
- // 查询到的样本集,影像压缩成一个zip
- if (ybSetList.size() > 0) {
- try {
- // 获取当前日期并格式化为 yyyyMMdd
- String currentDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
- // 创建临时 ZIP 文件
- File tempZipFile = Files.createTempFile("样本集_" + currentDate + "_", ".zip").toFile();
- // 创建临时根文件夹用于存放样本文件夹
- File tempRootDir = Files.createTempDirectory("样本集_" + currentDate + "_").toFile();
- for (TileSet tileSet : ybSetList) {
- // 为每个样本集创建一个文件夹
- File sampleDir = new File(tempRootDir, tileSet.getTileName() + "_" + tileSet.getPkId());
- sampleDir.mkdirs();
- // 获取文件复制到临时目录下
- setTitleSetFile(tileSet, sampleDir);
- }
- try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(tempZipFile))) {
- // 遍历 tempRootDir 下的所有子文件夹并添加到 ZIP 文件中
- File[] subDirs = tempRootDir.listFiles();
- if (subDirs != null) {
- for (File subDir : subDirs) {
- UnZipUtils.zipFiles(subDir, subDir.getName(), zipOut); // 将每个子文件夹递归添加到 ZIP
- }
- }
- } finally {
- // 删除临时文件夹及其内容
- UnZipUtils.deleteDirectory(tempRootDir);
- }
- try {
- // 将 ZIP 文件转为 FileInputStream
- ret.setFileStream(new FileInputStream(tempZipFile));
- } catch (IOException e) {
- e.printStackTrace();
- }
- // 异步任务:300秒后删除文件
- UnZipUtils.deleteAsyncFiles(tempZipFile);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- ret.setContentType("application/zip");
- ret.setFileName(String.valueOf(new Date().getTime()));
- return ret;
- }
- // 获取文件复制到临时目录下
- private void setTitleSetFile(TileSet tileSet, File sampleDir) {
- String tileSetPath = tileSet.getTilePath();
- boolean isTileSetPath = tileSetPath != null && !Objects.equals(tileSetPath, "");
- if (isTileSetPath) {
- // 获取样本切片file
- List<File> tileSetFileList = UnZipUtils.getFileByImagePaths(tileSetPath);
- for (File file : tileSetFileList) {
- try {
- Files.copy(file.toPath(), new File(sampleDir, file.getName()).toPath(), StandardCopyOption.REPLACE_EXISTING);
- } catch (Exception e) {
- System.out.print("前时项影像文件路径无效:" + file.getPath());
- }
- }
- }
- }
- /**
- * 辅助方法,用于从ZIP输入流中提取文件
- *
- * @param zis ZIP输入流
- * @param filePath 文件的完整路径
- * @throws IOException 如果发生I/O错误
- */
- public static void extractFile(ZipInputStream zis, String filePath) throws IOException {
- BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
- byte[] bytesIn = new byte[4096];
- int read = 0;
- while ((read = zis.read(bytesIn)) != -1) {
- bos.write(bytesIn, 0, read);
- }
- bos.close();
- }
- public static void zipFiles(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException {
- if (fileToZip.isHidden()) return;
- if (fileToZip.isDirectory()) {
- if (fileName.endsWith("/")) {
- zipOut.putNextEntry(new ZipEntry(fileName));
- zipOut.closeEntry();
- } else {
- zipOut.putNextEntry(new ZipEntry(fileName + "/"));
- zipOut.closeEntry();
- }
- File[] children = fileToZip.listFiles();
- for (File childFile : children) {
- zipFiles(childFile, fileName + "/" + childFile.getName(), zipOut);
- }
- return;
- }
- try (FileInputStream fis = new FileInputStream(fileToZip)) {
- ZipEntry zipEntry = new ZipEntry(fileName);
- zipOut.putNextEntry(zipEntry);
- byte[] bytes = new byte[1024];
- int length;
- while ((length = fis.read(bytes)) >= 0) {
- zipOut.write(bytes, 0, length);
- }
- }
- }
- public static void deleteDirectory(File file) {
- File[] contents = file.listFiles();
- if (contents != null) {
- for (File f : contents) {
- deleteDirectory(f);
- }
- }
- file.delete();
- }
- // 异步任务-删除临时文件
- public static void deleteAsyncFiles(File tempZipFile) {
- executorService.submit(() -> {
- try {
- TimeUnit.SECONDS.sleep(300);
- Files.deleteIfExists(tempZipFile.toPath());
- System.out.println("临时压缩包已删除:" + tempZipFile.toPath());
- } catch (Exception e) {
- System.err.println("临时压缩包删除失败:" + e.getMessage());
- }
- });
- }
- public static List<File> getFileByImagePaths(String imagePaths) {
- List<File> ret = new ArrayList<>();
- if (imagePaths != null && !imagePaths.equals("")) {
- List<String> preImagePathList = Arrays.asList(imagePaths.split(","));
- if (preImagePathList.size() > 0) {
- for (String preImagePath : preImagePathList) {
- // 根据path获取文件
- File file = new File(preImagePath);
- ret.add(file);
- }
- }
- }
- return ret;
- }
复制代码 3.前端下载:
- /**
- * 【样本集管理】-样本集导出
- */
- ybGlYbSetDownload(context = undefined, params = undefined, fileName) {
- const url = `${this.interfaceUrl}/ybtq-ystbtq/ybgl-set-cloud-download`;
- return ajaxHelperInstance.downloadFilePost(url, fileName, {}, params);
- }
- async downloadFilePost(url, fileName, urlParam, data = {}, requestMethod = 'POST', vueContext = undefined, spinName = 'spinning', useStreamSaver = false) {
- url = this.prepareUrl(url, {...urlParam, ...data});
- data = convertDateParam(data);
- setVueContextSpinState(vueContext, spinName);
- const requestOptions = this.setupRequestOptions(requestMethod, data);
- try {
- let response;
- if (useStreamSaver) {
- await this.downloadWithStream(url, fileName, requestOptions);
- } else {
- response = await axios({url, ...requestOptions});
- await this.handleResponse(response, fileName);
- }
- } catch (error) {
- this.handleError(error);
- } finally {
- resetVueContextSpinState(vueContext, spinName);
- }
- }
- prepareUrl(url, params) {
- const reqData = _.map(params, (val, prop) => ({name: prop, value: val}));
- const queryString = abp.utils.buildQueryString(reqData);
- return url + queryString;
- }
- /**
- * 转换时间参数,主要处理表单传入参数含有moment对象的问题
- * @param obj 传入对象
- * @constructor
- */
- function convertDateParam(obj) {
- _.each(obj, (val, prop) => {
- if (val instanceof moment) {
- obj[prop] = (val as any).format('YYYY-MM-DD HH:mm:ss');
- }
- if (val instanceof Date) {
- obj[prop] = moment(val)
- .format('YYYY-MM-DD HH:mm:ss');
- }
- });
- return obj;
- }
- function setVueContextSpinState(vueContext, spinName: string) {
- if (vueContext && vueContext[spinName] != undefined) {
- vueContext[spinName] = true;
- }
- }
- setupRequestOptions(method, data = null) {
- const headers = {
- 'Content-Type': 'application/json',
- 'Authorization': 'Bearer ' + window.abp.auth.getToken(),
- };
- return {
- method: method,
- headers: headers,
- responseType: 'blob',
- data: data ? JSON.stringify(data) : undefined,
- };
- }
- /**
- * 通过fetch Api进行流式下载
- * @param url 下载地址
- * @param fileName 文件名称
- * @param options 下载选项
- */
- async downloadWithStream(url, fileName, options: any = {}) {
- const {timeout = 1000 * 60 * 180} = options;
- const response = await this.fetchWithTimeout(url, options, timeout);
- if (!response.ok) {
- notification.warning({
- message: '提示',
- description: '下载失败',
- });
- throw new Error('下载失败');
- }
- const fileStream = StreamSaver.createWriteStream(fileName);
- const writer = fileStream.getWriter();
- if (response.body.pipeTo) {
- writer.releaseLock();
- return response.body.pipeTo(fileStream);
- }
- const reader = response.body.getReader();
- const pump = () =>
- reader
- .read()
- .then(({value, done}) => (done ? writer.close() : writer.write(value).then(pump)));
- return pump();
- }
- async handleResponse(response, fileName) {
- const contentType = response.headers['content-type'];
- console.log(contentType);
- if (contentType && contentType.includes('application/json')) {
- const reader = new FileReader();
- reader.onload = () => {
- try {
- const jsonData = JSON.parse(reader.result as string);
- if (jsonData && jsonData.message) {
- notification.error({
- message: '提示',
- description: jsonData.message,
- });
- }
- } catch (error) {
- console.error('解析json失败:', error);
- }
- };
- reader.readAsText(response.data);
- } else {
- const blob = new Blob([response.data]);
- const link = document.createElement('a');
- link.href = URL.createObjectURL(blob);
- link.download = fileName;
- link.click();
- URL.revokeObjectURL(link.href);
- }
- }
- handleError(error) {
- console.error('下载失败:', error);
- }
- function resetVueContextSpinState(vueContext, spinName: string) {
- if (vueContext && vueContext[spinName] == true) {
- vueContext[spinName] = false;
- }
- }
复制代码 |